Skip to content

Commit 17a4b4a

Browse files
authored
Merge pull request #3239 from sysown/v2.1.0-3238
Closes #3238: Improve error handling when port is already in use when instantiating 'ProxySQL_RestAPI_Server'
2 parents 718298f + 5dbddb3 commit 17a4b4a

File tree

1 file changed

+62
-2
lines changed

1 file changed

+62
-2
lines changed

lib/ProxySQL_Admin.cpp

+62-2
Original file line numberDiff line numberDiff line change
@@ -5708,6 +5708,51 @@ std::shared_ptr<httpserver::http_response> make_response(
57085708
return response;
57095709
}
57105710

5711+
/**
5712+
* @brief Checks if the supplied port is available.
5713+
*
5714+
* @param port_num The port number to check.
5715+
* @param free Output parameter. True if the port is free, false otherwise.
5716+
*
5717+
* @return Returns:
5718+
* - '-1' in case 'SO_REUSEADDR' fails to be set for the check.
5719+
* - '-2' in case of invalid arguments supplied.
5720+
* - '0' otherwise.
5721+
*/
5722+
int check_port_availability(int port_num, bool* port_free) {
5723+
int ecode = 0;
5724+
int sfd = 0;
5725+
int reuseaddr = 1;
5726+
struct sockaddr_in tmp_addr;
5727+
5728+
if (port_num == 0 || port_free == nullptr) {
5729+
return -2;
5730+
}
5731+
5732+
// set 'port_free' to false by default
5733+
*port_free = false;
5734+
5735+
sfd = socket(AF_INET, SOCK_STREAM, 0);
5736+
memset(&tmp_addr, 0, sizeof(tmp_addr));
5737+
tmp_addr.sin_family = AF_INET;
5738+
tmp_addr.sin_port = htons(port_num);
5739+
tmp_addr.sin_addr.s_addr = INADDR_ANY;
5740+
5741+
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(reuseaddr)) == -1) {
5742+
close(sfd);
5743+
ecode = -1;
5744+
} else {
5745+
if (bind(sfd, (struct sockaddr*)&tmp_addr, sizeof(tmp_addr)) == -1) {
5746+
close(sfd);
5747+
} else {
5748+
*port_free = true;
5749+
close(sfd);
5750+
}
5751+
}
5752+
5753+
return ecode;
5754+
}
5755+
57115756
void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db, bool replace) {
57125757
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Flushing ADMIN variables. Replace:%d\n", replace);
57135758
char *error=NULL;
@@ -5788,8 +5833,23 @@ void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db,
57885833
return http_response;
57895834
}
57905835
};
5836+
5837+
bool free_restapi_port = false;
5838+
int e_port_check = check_port_availability(variables.restapi_port, &free_restapi_port);
5839+
5840+
if (free_restapi_port == false) {
5841+
if (e_port_check == -1) {
5842+
proxy_error("Unable to start 'ProxySQL_RestAPI_Server', failed to set 'SO_REUSEADDR' to check port availability.\n");
5843+
} else {
5844+
proxy_error(
5845+
"Unable to start 'ProxySQL_RestAPI_Server', port '%d' already in use.\n",
5846+
variables.restapi_port
5847+
);
5848+
}
5849+
}
5850+
57915851
if (variables.restapi_enabled != variables.restapi_enabled_old) {
5792-
if (variables.restapi_enabled) {
5852+
if (variables.restapi_enabled && free_restapi_port) {
57935853
AdminRestApiServer = new ProxySQL_RESTAPI_Server(
57945854
variables.restapi_port, {{"/metrics", prometheus_callback}}
57955855
);
@@ -5804,7 +5864,7 @@ void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db,
58045864
delete AdminRestApiServer;
58055865
AdminRestApiServer = NULL;
58065866
}
5807-
if (variables.restapi_enabled) {
5867+
if (variables.restapi_enabled && free_restapi_port) {
58085868
AdminRestApiServer = new ProxySQL_RESTAPI_Server(
58095869
variables.restapi_port, {{"/metrics", prometheus_callback}}
58105870
);

0 commit comments

Comments
 (0)