From ce1c11e561ba25a4086c27c4dd5aa18bb0ed3e4d Mon Sep 17 00:00:00 2001 From: Suvendhu Hansa Date: Thu, 7 Aug 2025 17:58:43 +0530 Subject: [PATCH] Retry on bind failure --- docs/api/uci/cwmp.md | 301 ++++++++++++++++++++++-------------------- schemas/uci/cwmp.json | 7 + src/common.c | 3 + src/common.h | 1 + src/cwmp.c | 1 + src/http.c | 37 ++++-- src/notifications.c | 1 + src/uci_utils.c | 22 ++- src/uci_utils.h | 2 +- 9 files changed, 220 insertions(+), 155 deletions(-) diff --git a/docs/api/uci/cwmp.md b/docs/api/uci/cwmp.md index c632af7..12a3425 100644 --- a/docs/api/uci/cwmp.md +++ b/docs/api/uci/cwmp.md @@ -725,12 +725,46 @@
7547
-
The port used for connection request.
+
The port allowed for incoming connection request.
-
path
+
allowed_cr_ip
+ + +
list
+ + +
no
+ + +
null
+ + +
List of subnets or ips from where incoming connection requests are allowed e.g 10.2.1.0/24 or 10.2.1.5/32. So connection requests are allowed with SRC IP in range of '10.2.1.1 - 10.2.1.254' or from 10.2.1.5 and with dest port same as <B>port</B>. Empty value means only destination port will be used and connection requests on the valid port will be accepted irrespective of any src IP.
+ + + + +
path
+ + +
string
+ + +
no
+ + +
/
+ + +
CPE Connection request URI path
+ + + + +
instance_mode
string
@@ -739,10 +773,10 @@
no
-
/
+
InstanceNumber
-
CPE Connection request URI path
+
Configure the instance mode to use. Supported instance modes are : <B>InstanceNumber</B> and <B>InstanceAlias</B>.
@@ -781,7 +815,109 @@ -
instance_mode
+
session_timeout
+ + +
uinteger
+ + +
no
+ + +
60
+ + +
Represents the number of seconds that should be used by the ACS as the amount of time to wait before timing out a CWMP session due to the CPE not responding.
+ + + + +
notification
+ + +
boolean
+ + +
no
+ + +
+ + +
If set to **1**, it enables the notification feature.
+ + + + +
exec_download
+ + +
boolean
+ + +
no
+ + +
+ + +
If set to **1**, Specifies if Download method is executed.
+ + + + +
log_to_syslog
+ + +
boolean
+ + +
no
+ + +
+ + +
If set to **1**, the cwmp log will be appended to busybox syslog.
+ + + + +
periodic_notify_enable
+ + +
boolean
+ + +
no
+ + +
1
+ + +
If set to **1**, icwmp will be able to detect parameter value change at any time.
+ + + + +
periodic_notify_interval
+ + +
integer
+ + +
no
+ + +
10
+ + +
Interval in sec to check for value change notifications
+ + + + +
custom_notify_json
string
@@ -789,147 +925,11 @@
no
- -
InstanceNumber
- - -
Configure the instance mode to use. Supported instance modes are : <B>InstanceNumber</B> and <B>InstanceNumber</B>.
- - - - -
session_timeout
- - -
uinteger
- - -
no
- - -
60
- - -
Represents the number of seconds that should be used by the ACS as the amount of time to wait before timing out a CWMP session due to the CPE not responding.
- - - - -
notification
- - -
boolean
- - -
no
-
-
If set to **1**, it enables the notification feature.
- - - - -
exec_download
- - -
boolean
- - -
no
- - -
- - -
If set to **1**, Specifies if Download method is executed.
- - - - -
log_to_syslog
- - -
boolean
- - -
no
- - -
- - -
If set to **1**, the cwmp log will be appended to busybox syslog.
- - - - -
periodic_notify_enable
- - -
boolean
- - -
no
- - -
1
- - -
If set to **1**, icwmp will be able to detect parameter value change at any time.
- - - - -
periodic_notify_interval
- - -
integer
- - -
no
- - -
10
- - -
Interval in sec to check for value change notifications
- - - - -
custom_notify_json
- - -
string
- - -
no
- - -
- - -
Define absolute path of the JSON containing parameters on which notification get enabled as per the definition. See readme for examples.
- - - - -
allowed_cr_ip
- - -
list
- - -
no
- - -
- - -
List of subnets or ips from where incoming connection requests are allowed e.g 10.2.1.0/24 or 10.2.1.5/32. So connection requests are allowed with src IP in range of <10.2.1.1 - 10.2.1.254> or from 10.2.1.5 and with dest-port same as <port> Empty value means only destination port will be used and connection requests on the valid port will be accepted irrespective of any src IP.
+
Define absolute path of the JSON containing parameters on which notification get enabled as per the definition. See readme for examples.
@@ -983,6 +983,23 @@
If set to **1**, icwmp will skip datatype validation on SPV operations.
+ + +
bind_retries
+ + +
integer
+ + +
no
+ + +
5
+ + +
Specifies number of retries to be performed on socket binding failure. If set to **0** or **not configured**, means retry infinitely
+ + diff --git a/schemas/uci/cwmp.json b/schemas/uci/cwmp.json index fb38700..24c4dfc 100644 --- a/schemas/uci/cwmp.json +++ b/schemas/uci/cwmp.json @@ -382,6 +382,13 @@ "required": "no", "default": "0", "description": "If set to **1**, icwmp will skip datatype validation on SPV operations." + }, + { + "name": "bind_retries", + "type": "integer", + "required": "no", + "default": "5", + "description": "Specifies number of retries to be performed on socket binding failure. If set to **0** or **not configured**, means retry infinitely" } ] }, diff --git a/src/common.c b/src/common.c index 2680bf6..1b30672 100755 --- a/src/common.c +++ b/src/common.c @@ -1355,6 +1355,9 @@ void stop_service(void) { struct blob_buf bb; + // Remove port rules from firewall since cwmp is disabled + apply_allowed_cr_ip_port(); + memset(&bb, 0, sizeof(struct blob_buf)); blob_buf_init(&bb, 0); diff --git a/src/common.h b/src/common.h index 9c07a34..8b73550 100644 --- a/src/common.h +++ b/src/common.h @@ -123,6 +123,7 @@ typedef struct config { time_t schedule_reboot; time_t time; time_t heart_time; + int cpe_bind_retries; unsigned int active_notif_throttle; unsigned int md_notif_limit; diff --git a/src/cwmp.c b/src/cwmp.c index 812e005..5b92572 100644 --- a/src/cwmp.c +++ b/src/cwmp.c @@ -217,6 +217,7 @@ static int cwmp_init(void) if (cwmp_stop == true) return CWMP_GEN_ERR; + set_cpe_port_conf(cwmp_ctx.conf.connection_request_port); cwmp_get_deviceid(); /* Load default force inform parameters */ diff --git a/src/http.c b/src/http.c index 1d0b0c4..78de059 100644 --- a/src/http.c +++ b/src/http.c @@ -632,13 +632,14 @@ http_end: void icwmp_http_server_init(void) { + int y = 0; struct sockaddr_in6 server = { 0 }; - unsigned short cr_port; + unsigned short cr_port = 0; unsigned short prev_cr_port = (unsigned short)(cwmp_ctx.conf.connection_request_port); + int max_retry = cwmp_ctx.conf.cpe_bind_retries; for (;;) { cr_port = (unsigned short)(cwmp_ctx.conf.connection_request_port); - unsigned short i = (DEFAULT_CONNECTION_REQUEST_PORT == cr_port) ? 1 : 0; //Create socket if (cwmp_stop) return; @@ -661,30 +662,44 @@ void icwmp_http_server_init(void) server.sin6_family = AF_INET6; server.sin6_addr = in6addr_any; - for (;; i++) { + for (;;) { if (cwmp_stop) return; + CWMP_LOG(INFO, "Trying to use connection request port: %d", cr_port); server.sin6_port = htons(cr_port); //Bind if (bind(cwmp_ctx.cr_socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) { //print the error message - CWMP_LOG(ERROR, "Could not bind server socket on the port %d, Error no is : %d, Error description is : %s", cr_port, errno, strerror(errno)); - cr_port = DEFAULT_CONNECTION_REQUEST_PORT + i; - CWMP_LOG(INFO, "Trying to use another connection request port: %d", cr_port); + CWMP_LOG(ERROR, "Could not bind server socket on port %d, Err no: %d, Err string: %s", cr_port, errno, strerror(errno)); + + if (max_retry == 0) { + // Need to infinitely try with configured port + sleep(2); + continue; + } + + if (y < max_retry) { + // retry with same port for max_retry times + y = y + 1; + sleep(2); + continue; + } + + // Max retries expired, switch to next random port + y = 0; + cr_port = cr_port + 1; + sleep(2); continue; } + break; } break; } if (cr_port != prev_cr_port) { - char cr_port_str[6]; - snprintf(cr_port_str, 6, "%hu", cr_port); - cr_port_str[5] = '\0'; - set_uci_path_value(NULL, "cwmp.cpe.port", cr_port_str); - connection_request_port_value_change(cr_port); + set_cpe_port_conf(cr_port); cwmp_ctx.cr_ip_port_change = true; } diff --git a/src/notifications.c b/src/notifications.c index ce77dbb..11c3eb6 100644 --- a/src/notifications.c +++ b/src/notifications.c @@ -851,6 +851,7 @@ void periodic_check_notifiy(struct uloop_timeout *timeout __attribute__((unused void trigger_periodic_notify_check() { + uloop_timeout_cancel(&check_notify_timer); uloop_timeout_set(&check_notify_timer, 10); } diff --git a/src/uci_utils.c b/src/uci_utils.c index 38f7f31..7750565 100644 --- a/src/uci_utils.c +++ b/src/uci_utils.c @@ -283,6 +283,7 @@ static void config_get_cpe_elements(struct uci_section *s) UCI_CPE_USE_CURL_IFNAME, UCI_CPE_DISABLE_DATATYPE_CHECK, UCI_CPE_ALLOWED_CR_IP, + UCI_CPE_BIND_RETRIES, __MAX_NUM_UCI_CPE_ATTRS, }; @@ -311,6 +312,7 @@ static void config_get_cpe_elements(struct uci_section *s) [UCI_CPE_USE_CURL_IFNAME] = { .name = "use_curl_ifname", .type = UCI_TYPE_STRING }, [UCI_CPE_DISABLE_DATATYPE_CHECK] = { .name = "disable_datatype_check", .type = UCI_TYPE_STRING }, [UCI_CPE_ALLOWED_CR_IP] = { .name = "allowed_cr_ip", .type = UCI_TYPE_LIST }, + [UCI_CPE_BIND_RETRIES] = { .name = "bind_retries", .type = UCI_TYPE_STRING }, }; struct uci_option *cpe_tb[__MAX_NUM_UCI_CPE_ATTRS]; @@ -338,7 +340,7 @@ static void config_get_cpe_elements(struct uci_section *s) char *port = get_value_from_uci_option(cpe_tb[UCI_CPE_PORT]); if (strlen(port) != 0) { int a = (int)strtol(port, NULL, 10); - cwmp_ctx.conf.connection_request_port = (a != 0) ? a : DEFAULT_CONNECTION_REQUEST_PORT; + cwmp_ctx.conf.connection_request_port = (a > 0) ? a : DEFAULT_CONNECTION_REQUEST_PORT; } CWMP_LOG(DEBUG, "CWMP CONFIG - cpe connection request port: %d", cwmp_ctx.conf.connection_request_port); @@ -468,6 +470,15 @@ static void config_get_cpe_elements(struct uci_section *s) } CWMP_LOG(DEBUG, "CWMP CONFIG - cpe allowed_cr_ip: %s", cwmp_ctx.conf.valid_cr_ip); + + cwmp_ctx.conf.cpe_bind_retries = 0; + char *bind_count = get_value_from_uci_option(cpe_tb[UCI_CPE_BIND_RETRIES]); + if (strlen(bind_count) != 0) { + int a = (int)strtol(bind_count, NULL, 10); + cwmp_ctx.conf.cpe_bind_retries = (a > 0) ? a : 0; + } + + CWMP_LOG(DEBUG, "CWMP CONFIG - cpe bind retries: %d", cwmp_ctx.conf.cpe_bind_retries); } static void config_get_lwn_elements(struct uci_section *s) @@ -1071,3 +1082,12 @@ exit: return ret; } + +void set_cpe_port_conf(int cr_cpe_port) +{ + if (cr_cpe_port > 0) { + char cr_port_str[BUF_SIZE_16] = {0}; + snprintf(cr_port_str, sizeof(cr_port_str), "%d", cr_cpe_port); + set_uci_path_value(NULL, "cwmp.cpe.port", cr_port_str); + } +} diff --git a/src/uci_utils.h b/src/uci_utils.h index aa8eb71..231020f 100644 --- a/src/uci_utils.h +++ b/src/uci_utils.h @@ -39,6 +39,6 @@ int del_uci_list_value(const char *conf_dir, char *path, char *value); int get_inform_parameters_uci(struct list_head *inform_head); int commit_uci_package(char *package, const char *conf_dir, const char *save_dir); int get_global_config(); - +void set_cpe_port_conf(int cr_cpe_port); #endif