Retry on bind failure

This commit is contained in:
Suvendhu Hansa 2025-08-07 17:58:43 +05:30 committed by IOPSYS Dev
parent cf34a85a8e
commit ce1c11e561
No known key found for this signature in database
9 changed files with 220 additions and 155 deletions

View file

@ -725,12 +725,46 @@
<div class="td_row_odd">7547</div> <div class="td_row_odd">7547</div>
</td> </td>
<td class="td_row_odd"> <td class="td_row_odd">
<div class="td_row_odd">The port used for connection request.</div> <div class="td_row_odd">The port allowed for incoming connection request.</div>
</td> </td>
</tr> </tr>
<tr> <tr>
<td class="td_row_even"> <td class="td_row_even">
<div class="td_row_even">path</div> <div class="td_row_even">allowed_cr_ip</div>
</td>
<td class="td_row_even">
<div class="td_row_even">list</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">null</div>
</td>
<td class="td_row_even">
<div class="td_row_even">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 &lt;B&gt;port&lt;/B&gt;. Empty value means only destination port will be used and connection requests on the valid port will be accepted irrespective of any src IP.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">path</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">string</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">/</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">CPE Connection request URI path</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">instance_mode</div>
</td> </td>
<td class="td_row_even"> <td class="td_row_even">
<div class="td_row_even">string</div> <div class="td_row_even">string</div>
@ -739,10 +773,10 @@
<div class="td_row_even">no</div> <div class="td_row_even">no</div>
</td> </td>
<td class="td_row_even"> <td class="td_row_even">
<div class="td_row_even">/</div> <div class="td_row_even">InstanceNumber</div>
</td> </td>
<td class="td_row_even"> <td class="td_row_even">
<div class="td_row_even">CPE Connection request URI path</div> <div class="td_row_even">Configure the instance mode to use. Supported instance modes are : &lt;B&gt;InstanceNumber&lt;/B&gt; and &lt;B&gt;InstanceAlias&lt;/B&gt;.</div>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -781,7 +815,109 @@
</tr> </tr>
<tr> <tr>
<td class="td_row_odd"> <td class="td_row_odd">
<div class="td_row_odd">instance_mode</div> <div class="td_row_odd">session_timeout</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">uinteger</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">60</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">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.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">notification</div>
</td>
<td class="td_row_even">
<div class="td_row_even">boolean</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even"></div>
</td>
<td class="td_row_even">
<div class="td_row_even">If set to **1**, it enables the notification feature.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">exec_download</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">boolean</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd"></div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">If set to **1**, Specifies if Download method is executed.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">log_to_syslog</div>
</td>
<td class="td_row_even">
<div class="td_row_even">boolean</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even"></div>
</td>
<td class="td_row_even">
<div class="td_row_even">If set to **1**, the cwmp log will be appended to busybox syslog.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">periodic_notify_enable</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">boolean</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">1</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">If set to **1**, icwmp will be able to detect parameter value change at any time.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">periodic_notify_interval</div>
</td>
<td class="td_row_even">
<div class="td_row_even">integer</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">10</div>
</td>
<td class="td_row_even">
<div class="td_row_even">Interval in sec to check for value change notifications</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">custom_notify_json</div>
</td> </td>
<td class="td_row_odd"> <td class="td_row_odd">
<div class="td_row_odd">string</div> <div class="td_row_odd">string</div>
@ -789,147 +925,11 @@
<td class="td_row_odd"> <td class="td_row_odd">
<div class="td_row_odd">no</div> <div class="td_row_odd">no</div>
</td> </td>
<td class="td_row_odd">
<div class="td_row_odd">InstanceNumber</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">Configure the instance mode to use. Supported instance modes are : &lt;B&gt;InstanceNumber&lt;/B&gt; and &lt;B&gt;InstanceNumber&lt;/B&gt;.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">session_timeout</div>
</td>
<td class="td_row_even">
<div class="td_row_even">uinteger</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">60</div>
</td>
<td class="td_row_even">
<div class="td_row_even">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.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">notification</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">boolean</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd"> <td class="td_row_odd">
<div class="td_row_odd"></div> <div class="td_row_odd"></div>
</td> </td>
<td class="td_row_odd"> <td class="td_row_odd">
<div class="td_row_odd">If set to **1**, it enables the notification feature.</div> <div class="td_row_odd">Define absolute path of the JSON containing parameters on which notification get enabled as per the definition. See readme for examples.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">exec_download</div>
</td>
<td class="td_row_even">
<div class="td_row_even">boolean</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even"></div>
</td>
<td class="td_row_even">
<div class="td_row_even">If set to **1**, Specifies if Download method is executed.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">log_to_syslog</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">boolean</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd"></div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">If set to **1**, the cwmp log will be appended to busybox syslog.</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">periodic_notify_enable</div>
</td>
<td class="td_row_even">
<div class="td_row_even">boolean</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even">1</div>
</td>
<td class="td_row_even">
<div class="td_row_even">If set to **1**, icwmp will be able to detect parameter value change at any time.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">periodic_notify_interval</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">integer</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">10</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">Interval in sec to check for value change notifications</div>
</td>
</tr>
<tr>
<td class="td_row_even">
<div class="td_row_even">custom_notify_json</div>
</td>
<td class="td_row_even">
<div class="td_row_even">string</div>
</td>
<td class="td_row_even">
<div class="td_row_even">no</div>
</td>
<td class="td_row_even">
<div class="td_row_even"></div>
</td>
<td class="td_row_even">
<div class="td_row_even">Define absolute path of the JSON containing parameters on which notification get enabled as per the definition. See readme for examples.</div>
</td>
</tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">allowed_cr_ip</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">list</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd"></div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">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 &lt10.2.1.1 - 10.2.1.254&gt or from 10.2.1.5 and with dest-port same as &ltport&gt; Empty value means only destination port will be used and connection requests on the valid port will be accepted irrespective of any src IP.</div>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -983,6 +983,23 @@
<div class="td_row_even">If set to **1**, icwmp will skip datatype validation on SPV operations.</div> <div class="td_row_even">If set to **1**, icwmp will skip datatype validation on SPV operations.</div>
</td> </td>
</tr> </tr>
<tr>
<td class="td_row_odd">
<div class="td_row_odd">bind_retries</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">integer</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">no</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">5</div>
</td>
<td class="td_row_odd">
<div class="td_row_odd">Specifies number of retries to be performed on socket binding failure. If set to **0** or **not configured**, means retry infinitely</div>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</td> </td>

View file

@ -382,6 +382,13 @@
"required": "no", "required": "no",
"default": "0", "default": "0",
"description": "If set to **1**, icwmp will skip datatype validation on SPV operations." "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"
} }
] ]
}, },

View file

@ -1355,6 +1355,9 @@ void stop_service(void)
{ {
struct blob_buf bb; 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)); memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0); blob_buf_init(&bb, 0);

View file

@ -123,6 +123,7 @@ typedef struct config {
time_t schedule_reboot; time_t schedule_reboot;
time_t time; time_t time;
time_t heart_time; time_t heart_time;
int cpe_bind_retries;
unsigned int active_notif_throttle; unsigned int active_notif_throttle;
unsigned int md_notif_limit; unsigned int md_notif_limit;

View file

@ -217,6 +217,7 @@ static int cwmp_init(void)
if (cwmp_stop == true) if (cwmp_stop == true)
return CWMP_GEN_ERR; return CWMP_GEN_ERR;
set_cpe_port_conf(cwmp_ctx.conf.connection_request_port);
cwmp_get_deviceid(); cwmp_get_deviceid();
/* Load default force inform parameters */ /* Load default force inform parameters */

View file

@ -632,13 +632,14 @@ http_end:
void icwmp_http_server_init(void) void icwmp_http_server_init(void)
{ {
int y = 0;
struct sockaddr_in6 server = { 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); unsigned short prev_cr_port = (unsigned short)(cwmp_ctx.conf.connection_request_port);
int max_retry = cwmp_ctx.conf.cpe_bind_retries;
for (;;) { for (;;) {
cr_port = (unsigned short)(cwmp_ctx.conf.connection_request_port); cr_port = (unsigned short)(cwmp_ctx.conf.connection_request_port);
unsigned short i = (DEFAULT_CONNECTION_REQUEST_PORT == cr_port) ? 1 : 0;
//Create socket //Create socket
if (cwmp_stop) if (cwmp_stop)
return; return;
@ -661,30 +662,44 @@ void icwmp_http_server_init(void)
server.sin6_family = AF_INET6; server.sin6_family = AF_INET6;
server.sin6_addr = in6addr_any; server.sin6_addr = in6addr_any;
for (;; i++) { for (;;) {
if (cwmp_stop) if (cwmp_stop)
return; return;
CWMP_LOG(INFO, "Trying to use connection request port: %d", cr_port);
server.sin6_port = htons(cr_port); server.sin6_port = htons(cr_port);
//Bind //Bind
if (bind(cwmp_ctx.cr_socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) { if (bind(cwmp_ctx.cr_socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
//print the error message //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)); CWMP_LOG(ERROR, "Could not bind server socket on port %d, Err no: %d, Err string: %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); 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; continue;
} }
break; break;
} }
break; break;
} }
if (cr_port != prev_cr_port) { if (cr_port != prev_cr_port) {
char cr_port_str[6]; set_cpe_port_conf(cr_port);
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);
cwmp_ctx.cr_ip_port_change = true; cwmp_ctx.cr_ip_port_change = true;
} }

View file

@ -851,6 +851,7 @@ void periodic_check_notifiy(struct uloop_timeout *timeout __attribute__((unused
void trigger_periodic_notify_check() void trigger_periodic_notify_check()
{ {
uloop_timeout_cancel(&check_notify_timer);
uloop_timeout_set(&check_notify_timer, 10); uloop_timeout_set(&check_notify_timer, 10);
} }

View file

@ -283,6 +283,7 @@ static void config_get_cpe_elements(struct uci_section *s)
UCI_CPE_USE_CURL_IFNAME, UCI_CPE_USE_CURL_IFNAME,
UCI_CPE_DISABLE_DATATYPE_CHECK, UCI_CPE_DISABLE_DATATYPE_CHECK,
UCI_CPE_ALLOWED_CR_IP, UCI_CPE_ALLOWED_CR_IP,
UCI_CPE_BIND_RETRIES,
__MAX_NUM_UCI_CPE_ATTRS, __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_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_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_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]; 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]); char *port = get_value_from_uci_option(cpe_tb[UCI_CPE_PORT]);
if (strlen(port) != 0) { if (strlen(port) != 0) {
int a = (int)strtol(port, NULL, 10); 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); 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_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) static void config_get_lwn_elements(struct uci_section *s)
@ -1071,3 +1082,12 @@ exit:
return ret; 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);
}
}

View file

@ -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 get_inform_parameters_uci(struct list_head *inform_head);
int commit_uci_package(char *package, const char *conf_dir, const char *save_dir); int commit_uci_package(char *package, const char *conf_dir, const char *save_dir);
int get_global_config(); int get_global_config();
void set_cpe_port_conf(int cr_cpe_port);
#endif #endif