@@ -5708,6 +5708,51 @@ std::shared_ptr<httpserver::http_response> make_response(
5708
5708
return response;
5709
5709
}
5710
5710
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
+
5711
5756
void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db, bool replace) {
5712
5757
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Flushing ADMIN variables. Replace:%d\n", replace);
5713
5758
char *error=NULL;
@@ -5788,8 +5833,23 @@ void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db,
5788
5833
return http_response;
5789
5834
}
5790
5835
};
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
+
5791
5851
if (variables.restapi_enabled != variables.restapi_enabled_old) {
5792
- if (variables.restapi_enabled) {
5852
+ if (variables.restapi_enabled && free_restapi_port ) {
5793
5853
AdminRestApiServer = new ProxySQL_RESTAPI_Server(
5794
5854
variables.restapi_port, {{"/metrics", prometheus_callback}}
5795
5855
);
@@ -5804,7 +5864,7 @@ void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db,
5804
5864
delete AdminRestApiServer;
5805
5865
AdminRestApiServer = NULL;
5806
5866
}
5807
- if (variables.restapi_enabled) {
5867
+ if (variables.restapi_enabled && free_restapi_port ) {
5808
5868
AdminRestApiServer = new ProxySQL_RESTAPI_Server(
5809
5869
variables.restapi_port, {{"/metrics", prometheus_callback}}
5810
5870
);
0 commit comments