From d017aa025cd000b1668d7ec370266df03690d4de Mon Sep 17 00:00:00 2001 From: Amin Ben Romdhane Date: Mon, 19 May 2025 13:52:48 +0000 Subject: [PATCH] bbfdmd: Prevent repeated async calls to unstable services --- bbfdmd/ubus/bbfdmd.c | 60 ++++++++++++++++++++++++++++++++++++++++++- bbfdmd/ubus/common.h | 1 + bbfdmd/ubus/get.c | 26 ++++++++++++++----- bbfdmd/ubus/get.h | 3 ++- bbfdmd/ubus/service.c | 15 +++++++++-- bbfdmd/ubus/service.h | 2 ++ 6 files changed, 97 insertions(+), 10 deletions(-) diff --git a/bbfdmd/ubus/bbfdmd.c b/bbfdmd/ubus/bbfdmd.c index 789fb80d..b3e7440a 100644 --- a/bbfdmd/ubus/bbfdmd.c +++ b/bbfdmd/ubus/bbfdmd.c @@ -27,6 +27,50 @@ extern struct list_head registered_services; extern int g_log_level; +static void bbfdm_ubus_add_event_cb(struct ubus_context *ctx __attribute__((unused)), + struct ubus_event_handler *ev __attribute__((unused)), + const char *type, struct blob_attr *msg) +{ + const struct blobmsg_policy policy = { + "path", BLOBMSG_TYPE_STRING + }; + service_entry_t *service = NULL; + struct blob_attr *attr = NULL; + bool service_found = false; + const char *path; + + if (type && strcmp(type, "ubus.object.add") != 0) + return; + + blobmsg_parse(&policy, 1, &attr, blob_data(msg), blob_len(msg)); + if (!attr) + return; + + path = blobmsg_data(attr); + + if (path && strncmp(path, BBFDM_UBUS_OBJECT".", strlen(BBFDM_UBUS_OBJECT) + 1) == 0) { + + BBFDM_ERR("Detected new service registration: '%s'", path); + + list_for_each_entry(service, ®istered_services, list) { + // Check if the service is present in the registred services list + if (strcmp(service->name, path) == 0) { + service->is_blacklisted = false; + service->consecutive_timeouts = 0; + service_found = true; + BBFDM_ERR("Service '%s' found in registry. Resetting blacklist and timeout counters.", path); + break; + } + + if (!service_found) { + BBFDM_ERR("Newly registered service '%s' is not recognized in the registry." + " Possible missing configuration JSON file under '%s'.", + path, BBFDM_MICROSERVICE_INPUT_PATH); + } + } + } +} + static const struct blobmsg_policy bbfdm_policy[] = { [BBFDM_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, [BBFDM_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING }, @@ -72,10 +116,13 @@ static int bbfdm_handler_async(struct ubus_context *ctx, struct ubus_object *obj list_for_each_entry(service, ®istered_services, list) { + if (service->is_blacklisted) + continue; + if (!is_path_match(context->requested_path, requested_proto, service)) continue; - run_async_call(context, service->name, msg); + run_async_call(context, service, msg); } context->service_list_processed = true; @@ -117,6 +164,9 @@ static int bbfdm_handler_sync(struct ubus_context *ctx, struct ubus_object *obj, list_for_each_entry(service, ®istered_services, list) { + if (service->is_blacklisted) + continue; + if (!is_path_match(requested_path, requested_proto, service)) continue; @@ -181,6 +231,10 @@ static void usage(char *prog) int main(int argc, char **argv) { struct ubus_context ubus_ctx = {0}; + struct ubus_event_handler add_event = { + .cb = bbfdm_ubus_add_event_cb, + }; + char *cli_argv[4] = {0}; int err = 0, ch, cli_argc = 0, i; @@ -236,11 +290,15 @@ int main(int argc, char **argv) goto end; } + if (ubus_register_event_handler(&ubus_ctx, &add_event, "ubus.object.add")) + goto end; + BBFDM_INFO("Waiting on uloop...."); uloop_run(); end: BBFDM_DEBUG("BBFDMD exits"); + ubus_unregister_event_handler(&ubus_ctx, &add_event); unregister_services(); uloop_done(); ubus_shutdown(&ubus_ctx); diff --git a/bbfdmd/ubus/common.h b/bbfdmd/ubus/common.h index 13add469..3d20e8b0 100644 --- a/bbfdmd/ubus/common.h +++ b/bbfdmd/ubus/common.h @@ -21,6 +21,7 @@ #define MAX_VALUE_LENGTH 1024 * 4 #define SERVICE_CALL_TIMEOUT 10000 // 10 secs #define SERVICE_CALL_OPERATE_TIMEOUT 1800000 // 30 mins +#define SERVICE_MAX_CONSECUTIVE_TIMEOUTS 10 enum bbfdmd_type_enum { BBFDMD_NONE = 0, diff --git a/bbfdmd/ubus/get.c b/bbfdmd/ubus/get.c index 22030784..854852e9 100644 --- a/bbfdmd/ubus/get.c +++ b/bbfdmd/ubus/get.c @@ -321,6 +321,16 @@ static void handle_request_timeout(struct uloop_timeout *timeout) ubus_abort_request(tracker->ctx->ubus_ctx, &tracker->async_request); tracker->ctx->pending_requests--; + service_entry_t *service = tracker->service; + + if (service) { + service->consecutive_timeouts++; + if (service->consecutive_timeouts >= SERVICE_MAX_CONSECUTIVE_TIMEOUTS) { + service->is_blacklisted = true; + BBFDM_ERR("Service '%s' has been blacklisted due to repeated timeouts", service->name); + } + } + if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) { BBFDM_ERR("All requests completed after timeout"); send_response(tracker->ctx); @@ -347,6 +357,9 @@ static void ubus_request_complete(struct ubus_request *req, int ret) uloop_timeout_cancel(&tracker->timeout); tracker->ctx->pending_requests--; + if (tracker->service && ret == UBUS_STATUS_OK) + tracker->service->consecutive_timeouts = 0; + if (tracker->ctx->pending_requests == 0 && tracker->ctx->service_list_processed) { BBFDM_DEBUG("Result Callback: All requests completed"); send_response(tracker->ctx); @@ -355,20 +368,20 @@ static void ubus_request_complete(struct ubus_request *req, int ret) BBFDM_FREE(tracker); } -void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg) +void run_async_call(struct async_request_context *ctx, service_entry_t *service, struct blob_attr *msg) { struct blob_buf req_buf = {0}; struct blob_attr *attr = NULL; int remaining = 0; uint32_t id = 0; - if (!ctx || !ubus_obj || !msg) { + if (!ctx || !service || !msg || !service->name) { BBFDM_ERR("Invalid arguments"); return; } - if (ubus_lookup_id(ctx->ubus_ctx, ubus_obj, &id)) { - BBFDM_ERR("Failed to lookup object: %s", ubus_obj); + if (ubus_lookup_id(ctx->ubus_ctx, service->name, &id)) { + BBFDM_ERR("Failed to lookup object: %s", service->name); return; } @@ -379,6 +392,7 @@ void run_async_call(struct async_request_context *ctx, const char *ubus_obj, str } tracker->ctx = ctx; + tracker->service = service; ctx->pending_requests++; ctx->path_matched = true; @@ -389,14 +403,14 @@ void run_async_call(struct async_request_context *ctx, const char *ubus_obj, str blobmsg_add_field(&req_buf, blobmsg_type(attr), blobmsg_name(attr), blobmsg_data(attr), blobmsg_len(attr)); } - snprintf(tracker->request_name, sizeof(tracker->request_name), "%s->%s", ubus_obj, ctx->ubus_method); + snprintf(tracker->request_name, sizeof(tracker->request_name), "%s->%s", service->name, ctx->ubus_method); tracker->timeout.cb = handle_request_timeout; uloop_timeout_set(&tracker->timeout, !strcmp(ctx->ubus_method, "operate") ? SERVICE_CALL_OPERATE_TIMEOUT : SERVICE_CALL_TIMEOUT); if (g_log_level == LOG_DEBUG) { char *json_str = blobmsg_format_json_indent(req_buf.head, true, -1); - BBFDM_DEBUG("### ubus call %s %s '%s' ###", ubus_obj, ctx->ubus_method, json_str); + BBFDM_DEBUG("### ubus call %s %s '%s' ###", service->name, ctx->ubus_method, json_str); BBFDM_FREE(json_str); } diff --git a/bbfdmd/ubus/get.h b/bbfdmd/ubus/get.h index a96aa008..c973e323 100644 --- a/bbfdmd/ubus/get.h +++ b/bbfdmd/ubus/get.h @@ -41,12 +41,13 @@ struct async_request_context { struct ubus_request_tracker { struct async_request_context *ctx; + service_entry_t *service; struct ubus_request async_request; struct uloop_timeout timeout; char request_name[128]; }; -void run_async_call(struct async_request_context *ctx, const char *ubus_obj, struct blob_attr *msg); +void run_async_call(struct async_request_context *ctx, service_entry_t *service, struct blob_attr *msg); void send_response(struct async_request_context *ctx); #endif /* BBFDMD_GET_H */ diff --git a/bbfdmd/ubus/service.c b/bbfdmd/ubus/service.c index 5a2754d1..51129b5e 100644 --- a/bbfdmd/ubus/service.c +++ b/bbfdmd/ubus/service.c @@ -201,24 +201,35 @@ void list_registered_services(struct blob_buf *bb) list_for_each_entry(service, ®istered_services, list) { void *table = blobmsg_open_table(bb, NULL); + blobmsg_add_string(bb, "name", service->name ? service->name : ""); - blobmsg_add_string(bb, "proto", service->protocol == BBFDMD_USP ? "usp" : service->protocol == BBFDMD_CWMP ? "cwmp" : "both"); + blobmsg_add_string(bb, "proto", + service->protocol == BBFDMD_USP ? "usp" : + service->protocol == BBFDMD_CWMP ? "cwmp" : "both"); + blobmsg_add_u8(bb, "unified_daemon", service->is_unified); + blobmsg_add_u8(bb, "blacklisted", service->is_blacklisted); + void *objects_array = blobmsg_open_array(bb, "objects"); for (size_t i = 0; i < service->object_count; i++) { void *obj_table = blobmsg_open_table(bb, NULL); blobmsg_add_string(bb, "parent_dm", service->objects[i].parent_path); blobmsg_add_string(bb, "object", service->objects[i].object_name); + if (service->protocol == BBFDMD_USP) { blobmsg_add_string(bb, "proto", "usp"); } else if (service->protocol == BBFDMD_CWMP) { blobmsg_add_string(bb, "proto", "cwmp"); } else { - blobmsg_add_string(bb, "proto", service->objects[i].protocol == BBFDMD_USP ? "usp" : service->objects[i].protocol == BBFDMD_CWMP ? "cwmp" : "both"); + blobmsg_add_string(bb, "proto", + service->objects[i].protocol == BBFDMD_USP ? "usp" : + service->objects[i].protocol == BBFDMD_CWMP ? "cwmp" : "both"); } + blobmsg_close_table(bb, obj_table); } blobmsg_close_array(bb, objects_array); + blobmsg_close_table(bb, table); } diff --git a/bbfdmd/ubus/service.h b/bbfdmd/ubus/service.h index 426231b9..db1decff 100644 --- a/bbfdmd/ubus/service.h +++ b/bbfdmd/ubus/service.h @@ -25,6 +25,8 @@ typedef struct service_entry { bool is_unified; size_t object_count; service_object_t *objects; + int consecutive_timeouts; // Tracks successive timeouts + bool is_blacklisted; // Marks if the service is blacklisted } service_entry_t; int register_services(struct ubus_context *ctx);