diff --git a/tools/nut-scanner/scan_eaton_serial.c b/tools/nut-scanner/scan_eaton_serial.c
index b29bb6de2f..aee6af5c73 100644
--- a/tools/nut-scanner/scan_eaton_serial.c
+++ b/tools/nut-scanner/scan_eaton_serial.c
@@ -380,7 +380,14 @@ static nutscan_device_t * nutscan_scan_eaton_serial_q1(const char* port_name)
return dev;
}
-static void * nutscan_scan_eaton_serial_device(void * port_arg)
+/* Wrap calls to actual implementations of nutscan_scan_eaton_serial_shut(),
+ * nutscan_scan_eaton_serial_xcp() and/or nutscan_scan_eaton_serial_q1()
+ * which implement the semantics of parallel-able scanning.
+ * Returns the device entry, updates global dev_ret when a scan is successful.
+ * DOES NOT FREE the caller's copy of "port_arg", unlike many similar methods
+ * in other scanners.
+ */
+static void * nutscan_scan_eaton_serial_device_thready(void * port_arg)
{
nutscan_device_t * dev = NULL;
char* port_name = (char*) port_arg;
@@ -396,6 +403,7 @@ static void * nutscan_scan_eaton_serial_device(void * port_arg)
}
/* Else try UTalk? */
}
+
return dev;
}
@@ -546,7 +554,7 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range)
current_port_name = serial_ports_list[current_port_nb];
#ifdef HAVE_PTHREAD
- if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device, (void*)current_port_name) == 0) {
+ if (pthread_create(&thread, NULL, nutscan_scan_eaton_serial_device_thready, (void*)current_port_name) == 0) {
nutscan_thread_t *new_thread_array;
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
@@ -571,8 +579,10 @@ nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_range)
# endif /* HAVE_PTHREAD_TRYJOIN */
}
#else /* if not HAVE_PTHREAD */
- nutscan_scan_eaton_serial_device(current_port_name);
+ nutscan_scan_eaton_serial_device_thready(current_port_name);
#endif /* if HAVE_PTHREAD */
+
+ /* Prepare the next iteration */
current_port_nb++;
} else { /* if not pass -- all slots busy */
#ifdef HAVE_PTHREAD
diff --git a/tools/nut-scanner/scan_nut.c b/tools/nut-scanner/scan_nut.c
index 723c8898fb..a29f39a576 100644
--- a/tools/nut-scanner/scan_nut.c
+++ b/tools/nut-scanner/scan_nut.c
@@ -62,6 +62,8 @@ typedef int bool_t;
#endif
struct scan_nut_arg {
+ /* String includes square brackets around host/IP
+ * address, and/or :port suffix (if customized so): */
char * hostname;
useconds_t timeout;
};
@@ -137,9 +139,14 @@ int nutscan_load_upsclient_library(const char *libname_path)
lt_dlexit();
return 0;
}
+/* end of dynamic link library stuff */
/* FIXME: SSL support */
-static void * list_nut_devices(void * arg)
+/* Performs a (parallel-able) NUT protocol scan of one remote host:port.
+ * Returns NULL, updates global dev_ret when a scan is successful.
+ * FREES the caller's copy of "nut_arg" and "hostname" in it, if applicable.
+ */
+static void * list_nut_devices_thready(void * arg)
{
struct scan_nut_arg * nut_arg = (struct scan_nut_arg*)arg;
char *target_hostname = nut_arg->hostname;
@@ -192,6 +199,7 @@ static void * list_nut_devices(void * arg)
free(ups);
return NULL;
}
+
/* FIXME: check for duplication by getting driver.port and device.serial
* for comparison with other busses results */
/* FIXME:
@@ -256,6 +264,7 @@ static void * list_nut_devices(void * arg)
free(target_hostname);
free(nut_arg);
free(ups);
+
return NULL;
}
@@ -526,7 +535,7 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons
nut_arg->hostname = ip_dest;
#ifdef HAVE_PTHREAD
- if (pthread_create(&thread, NULL, list_nut_devices, (void*)nut_arg) == 0) {
+ if (pthread_create(&thread, NULL, list_nut_devices_thready, (void*)nut_arg) == 0) {
nutscan_thread_t *new_thread_array;
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
@@ -550,11 +559,16 @@ nutscan_device_t * nutscan_scan_ip_range_nut(nutscan_ip_range_list_t * irl, cons
pthread_mutex_unlock(&threadcount_mutex);
# endif /* HAVE_PTHREAD_TRYJOIN */
}
-#else /* not HAVE_PTHREAD */
- list_nut_devices(nut_arg);
+#else /* if not HAVE_PTHREAD */
+ list_nut_devices_thready(nut_arg);
#endif /* if HAVE_PTHREAD */
- /* Prepare the next iteration */
+ /* Prepare the next iteration; note that
+ * nutscan_scan_ipmi_device_thready()
+ * takes care of freeing "tmp_sec" and its
+ * copy (note strdup!) of "ip_str" as
+ * hostname, possibly suffixed with a port.
+ */
free(ip_str);
ip_str = nutscan_ip_ranges_iter_inc(&ip);
} else { /* if not pass -- all slots busy */
diff --git a/tools/nut-scanner/scan_snmp.c b/tools/nut-scanner/scan_snmp.c
index 2a5358d1ab..6f971f5c5c 100644
--- a/tools/nut-scanner/scan_snmp.c
+++ b/tools/nut-scanner/scan_snmp.c
@@ -894,7 +894,11 @@ static int init_session(struct snmp_session * snmp_sess, nutscan_snmp_t * sec)
return 1;
}
-static void * try_SysOID(void * arg)
+/* Performs a (parallel-able) SNMP protocol scan of one remote host.
+ * Returns NULL, updates global dev_ret when a scan is successful.
+ * FREES the caller's copy of "sec" and "peername" in it, if applicable.
+ */
+static void * try_SysOID_thready(void * arg)
{
struct snmp_session snmp_sess;
void * handle;
@@ -1265,7 +1269,7 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl,
tmp_sec->peername = ip_str;
#ifdef HAVE_PTHREAD
- if (pthread_create(&thread, NULL, try_SysOID, (void*)tmp_sec) == 0) {
+ if (pthread_create(&thread, NULL, try_SysOID_thready, (void*)tmp_sec) == 0) {
nutscan_thread_t *new_thread_array;
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
@@ -1289,14 +1293,17 @@ nutscan_device_t * nutscan_scan_ip_range_snmp(nutscan_ip_range_list_t * irl,
pthread_mutex_unlock(&threadcount_mutex);
# endif /* HAVE_PTHREAD_TRYJOIN */
}
-#else /* not HAVE_PTHREAD */
- try_SysOID((void *)tmp_sec);
+#else /* if not HAVE_PTHREAD */
+ try_SysOID_thready((void *)tmp_sec);
#endif /* if HAVE_PTHREAD */
- /* Prepare the next iteration */
-/* free(ip_str); */ /* Do not free() here - seems to cause a double-free instead */
+ /* Prepare the next iteration; note that
+ * try_SysOID_thready()
+ * takes care of freeing "tmp_sec" and its
+ * reference (NOT strdup!) to "ip_str" as
+ * peername.
+ */
ip_str = nutscan_ip_ranges_iter_inc(&ip);
-/* free(tmp_sec); */
} else { /* if not pass -- all slots busy */
#ifdef HAVE_PTHREAD
# ifdef HAVE_SEMAPHORE
diff --git a/tools/nut-scanner/scan_xml_http.c b/tools/nut-scanner/scan_xml_http.c
index db94192a26..1e46191d1e 100644
--- a/tools/nut-scanner/scan_xml_http.c
+++ b/tools/nut-scanner/scan_xml_http.c
@@ -182,7 +182,11 @@ static int startelm_cb(void *userdata, int parent, const char *nspace, const cha
return result;
}
-static void * nutscan_scan_xml_http_generic(void * arg)
+/* Performs a (parallel-able) NetXML protocol scan of one remote host:port.
+ * Returns NULL, updates global dev_ret when a scan is successful.
+ * FREES the caller's copy of "arg" and "hostname" in it, if applicable.
+ */
+static void * nutscan_scan_xml_http_thready(void * arg)
{
nutscan_xml_t * sec = (nutscan_xml_t *)arg;
char *scanMsg = "";
@@ -221,12 +225,12 @@ static void * nutscan_scan_xml_http_generic(void * arg)
usec_timeout = 5000000; /* Driver default : 5sec */
if (!nutscan_avail_xml_http) {
- return NULL;
+ goto end_free;
}
if ((peerSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
fprintf(stderr, "Error creating socket\n");
- return NULL;
+ goto end_free;
}
/* FIXME : Per http://stackoverflow.com/questions/683624/udp-broadcast-on-all-interfaces
@@ -237,7 +241,7 @@ static void * nutscan_scan_xml_http_generic(void * arg)
sockAddress_udp.sin_family = AF_INET;
if (ip == NULL) {
upsdebugx(2,
- "nutscan_scan_xml_http_generic() : scanning connected network segment(s) "
+ "nutscan_scan_xml_http_thready() : scanning connected network segment(s) "
"with a broadcast, attempt %d of %d with a timeout of %" PRIdMAX " usec",
(i + 1), MAX_RETRIES, (uintmax_t)usec_timeout);
sockAddress_udp.sin_addr.s_addr = INADDR_BROADCAST;
@@ -246,7 +250,7 @@ static void * nutscan_scan_xml_http_generic(void * arg)
sizeof(sockopt_on));
} else {
upsdebugx(2,
- "nutscan_scan_xml_http_generic() : scanning IP '%s' with a unicast, "
+ "nutscan_scan_xml_http_thready() : scanning IP '%s' with a unicast, "
"attempt %d of %d with a timeout of %" PRIdMAX " usec",
ip, (i + 1), MAX_RETRIES, (uintmax_t)usec_timeout);
inet_pton(AF_INET, ip, &(sockAddress_udp.sin_addr));
@@ -273,7 +277,7 @@ static void * nutscan_scan_xml_http_generic(void * arg)
timeout.tv_sec = usec_timeout / 1000000;
timeout.tv_usec = usec_timeout % 1000000;
- upsdebugx(5, "nutscan_scan_xml_http_generic() : sent request to %s, "
+ upsdebugx(5, "nutscan_scan_xml_http_thready() : sent request to %s, "
"loop #%d/%d, waiting for responses",
(ip ? ip : ""), (i + 1), MAX_RETRIES);
while ((ret = select(peerSocket + 1, &fds, NULL, NULL,
@@ -283,7 +287,7 @@ static void * nutscan_scan_xml_http_generic(void * arg)
int parserFailed;
retNum ++;
- upsdebugx(5, "nutscan_scan_xml_http_generic() : request to %s, "
+ upsdebugx(5, "nutscan_scan_xml_http_thready() : request to %s, "
"loop #%d/%d, response #%d",
(ip ? ip : ""), (i + 1), MAX_RETRIES, retNum);
@@ -353,7 +357,7 @@ static void * nutscan_scan_xml_http_generic(void * arg)
* Does our driver support the notation? */
nut_dev->port = strdup(buf);
upsdebugx(3,
- "nutscan_scan_xml_http_generic(): "
+ "nutscan_scan_xml_http_thready(): "
"Adding configuration for driver='%s' port='%s'",
nut_dev->driver, nut_dev->port);
dev_ret = nutscan_add_device_to_device(
@@ -383,7 +387,7 @@ static void * nutscan_scan_xml_http_generic(void * arg)
if (ip != NULL) {
upsdebugx(2,
- "nutscan_scan_xml_http_generic(): we collected one reply "
+ "nutscan_scan_xml_http_thready(): we collected one reply "
"to unicast for %s (repsponse from %s), done",
ip, string);
goto end;
@@ -391,24 +395,35 @@ static void * nutscan_scan_xml_http_generic(void * arg)
} /* while select() responses */
if (ip == NULL && dev_ret != NULL) {
upsdebugx(2,
- "nutscan_scan_xml_http_generic(): we collected one round of replies "
+ "nutscan_scan_xml_http_thready(): we collected one round of replies "
"to broadcast with no errors, done");
goto end;
}
}
}
upsdebugx(2,
- "nutscan_scan_xml_http_generic(): no replies collected for %s, done",
+ "nutscan_scan_xml_http_thready(): no replies collected for %s, done",
(ip ? ip : ""));
goto end;
end_abort:
upsdebugx(1,
- "Had to abort nutscan_scan_xml_http_generic() for %s, see fatal details above",
+ "Had to abort nutscan_scan_xml_http_thready() for %s, see fatal details above",
(ip ? ip : ""));
+
end:
- if (ip != NULL) /* do not free "ip", it comes from caller */
+ if (ip != NULL)
close(peerSocket);
+
+end_free:
+ /* free resources which come from the caller
+ * (in parallel runs, nobody else can reap them)
+ */
+ if (ip != NULL)
+ free(ip);
+ if (sec != NULL)
+ free(sec);
+
return NULL;
}
@@ -652,7 +667,7 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl,
}
#ifdef HAVE_PTHREAD
- if (pthread_create(&thread, NULL, nutscan_scan_xml_http_generic, (void *)tmp_sec) == 0) {
+ if (pthread_create(&thread, NULL, nutscan_scan_xml_http_thready, (void*)tmp_sec) == 0) {
nutscan_thread_t *new_thread_array;
# ifdef HAVE_PTHREAD_TRYJOIN
pthread_mutex_lock(&threadcount_mutex);
@@ -676,14 +691,17 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl,
pthread_mutex_unlock(&threadcount_mutex);
# endif /* HAVE_PTHREAD_TRYJOIN */
}
-#else /* not HAVE_PTHREAD */
- nutscan_scan_xml_http_generic((void *)tmp_sec);
+#else /* if not HAVE_PTHREAD */
+ nutscan_scan_xml_http_thready(tmp_sec);
#endif /* if HAVE_PTHREAD */
- /* Prepare the next iteration */
-/* free(ip_str); */ /* One of these free()s seems to cause a double-free instead */
+ /* Prepare the next iteration; note that
+ * nutscan_scan_xml_http_thready()
+ * takes care of freeing "tmp_sec" and its
+ * reference (NOT strdup!) to "ip_str" as
+ * peername.
+ */
ip_str = nutscan_ip_ranges_iter_inc(&ip);
-/* free(tmp_sec); */
} else { /* if not pass -- all slots busy */
#ifdef HAVE_PTHREAD
# ifdef HAVE_SEMAPHORE
@@ -797,10 +815,10 @@ nutscan_device_t * nutscan_scan_ip_range_xml_http(nutscan_ip_range_list_t * irl,
tmp_sec->usec_timeout = usec_timeout;
}
- nutscan_scan_xml_http_generic(tmp_sec);
+ /* Note: the thready method releases the resources */
+ nutscan_scan_xml_http_thready(tmp_sec);
result = nutscan_rewind_device(dev_ret);
dev_ret = NULL;
- free(tmp_sec);
return result;
}