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; }