static int join_mcgroup (os_socket socket, const os_sockaddr_storage *mcip, const struct nn_interface *interf) { /* Note: interf == NULL indicates default address for multicast */ int rc; #if OS_SOCKET_HAS_IPV6 if (config.useIpv6) { os_ipv6_mreq ipv6mreq; memset (&ipv6mreq, 0, sizeof (ipv6mreq)); memcpy (&ipv6mreq.ipv6mr_multiaddr, &((os_sockaddr_in6 *) mcip)->sin6_addr, sizeof (ipv6mreq.ipv6mr_multiaddr)); ipv6mreq.ipv6mr_interface = interf ? interf->if_index : 0; rc = os_sockSetsockopt (socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mreq, sizeof (ipv6mreq)); } else #endif { struct ip_mreq mreq; mreq.imr_multiaddr = ((os_sockaddr_in *) mcip)->sin_addr; if (interf) mreq.imr_interface = ((os_sockaddr_in *) &interf->addr)->sin_addr; else mreq.imr_interface.s_addr = htonl (INADDR_ANY); rc = os_sockSetsockopt (socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof (mreq)); } if (rc != os_resultSuccess) { const char *op = config.useIpv6 ? "IPV6_JOIN_GROUP" : "IP_ADD_MEMBERSHIP"; int err = os_sockError (); char buf1[INET6_ADDRSTRLEN_EXTENDED]; sockaddr_to_string_no_port (buf1, mcip); if (interf) { char buf2[INET6_ADDRSTRLEN]; sockaddr_to_string_no_port (buf2, &interf->addr); if (err == os_sockEADDRINUSE) NN_WARNING3 ("%s for %s failed on interface with address %s: already bound\n", op, buf1, buf2); else NN_WARNING4 ("%s for %s failed on interface with address %s (errno %d)\n", op, buf1, buf2, err); } else { if (err == os_sockEADDRINUSE) NN_WARNING2 ("%s for %s failed on default interface: already bound\n", op, buf1); else NN_WARNING3 ("%s for %s failed on default interface (errno %d)\n", op, buf1, err); } return -2; } return 0; }
static int add_addresses_to_addrset_1 (struct addrset *as, const char *ip, int port_mode, const char *msgtag) { char buf[INET6_ADDRSTRLEN_EXTENDED]; os_sockaddr_storage addr; if (!os_sockaddrStringToAddress (ip, (os_sockaddr *) &addr, !config.useIpv6)) { NN_WARNING2 ("%s: %s: not a valid address\n", msgtag, ip); return -1; } if (port_mode >= 0) { sockaddr_set_port (&addr, port_mode); nn_log (LC_CONFIG, "%s: add %s", msgtag, sockaddr_to_string_with_port (buf, &addr)); add_to_addrset (as, &addr); } else { sockaddr_set_port (&addr, 0); nn_log (LC_CONFIG, "%s: add ", msgtag); if (!is_mcaddr (&addr)) { int i; for (i = 0; i < 10; i++) { int port = config.port_base + config.port_dg * config.domainId + i * config.port_pg + config.port_d1; sockaddr_set_port (&addr, port); if (i == 0) nn_log (LC_CONFIG, "%s", sockaddr_to_string_with_port (buf, &addr)); else nn_log (LC_CONFIG, ", :%d", port); add_to_addrset (as, &addr); } } else { int port = port_mode; if (port == -1) port = config.port_base + config.port_dg * config.domainId + config.port_d0; sockaddr_set_port (&addr, port); nn_log (LC_CONFIG, "%s", sockaddr_to_string_with_port (buf, &addr)); add_to_addrset (as, &addr); } } nn_log (LC_CONFIG, "\n"); return 0; }
int find_own_ip (const char *requested_address) { const char *sep = " "; char last_if_name[80] = ""; int quality = -1; os_result res; int i; unsigned int nif; os_ifAttributes *ifs; int maxq_list[MAX_INTERFACES]; int maxq_count = 0; int maxq_strlen = 0; int selected_idx = -1; char addrbuf[INET6_ADDRSTRLEN_EXTENDED]; if ((ifs = os_malloc (MAX_INTERFACES * sizeof (*ifs))) == NULL) { NN_FATAL0 ("ddsi2: insufficient memory for enumerating network interfaces\n"); return 0; } nn_log (LC_CONFIG, "interfaces:"); if (config.useIpv6) res = os_sockQueryIPv6Interfaces (ifs, (os_uint32) MAX_INTERFACES, &nif); else res = os_sockQueryInterfaces (ifs, (os_uint32) MAX_INTERFACES, &nif); if (res != os_resultSuccess) { NN_ERROR1 ("os_sockQueryInterfaces: %d\n", (int) res); os_free (ifs); return 0; } gv.n_interfaces = 0; for (i = 0; i < (int) nif; i++, sep = ", ") { os_sockaddr_storage tmpip, tmpmask; char if_name[sizeof (last_if_name)]; int q = 0; os_strncpy (if_name, ifs[i].name, sizeof (if_name) - 1); if_name[sizeof (if_name) - 1] = 0; if (strcmp (if_name, last_if_name)) nn_log (LC_CONFIG, "%s%s", sep, if_name); os_strcpy (last_if_name, if_name); /* interface must be up */ if ((ifs[i].flags & IFF_UP) == 0) { nn_log (LC_CONFIG, " (interface down)"); continue; } tmpip = ifs[i].address; tmpmask = ifs[i].network_mask; sockaddr_to_string_no_port (addrbuf, &tmpip); nn_log (LC_CONFIG, " %s", addrbuf); if (ifs[i].flags & IFF_LOOPBACK) { /* Loopback device has the lowest priority of every interface available, because the other interfaces at least in principle allow communicating with other machines. */ q += 0; #if OS_SOCKET_HAS_IPV6 if (!(tmpip.ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &tmpip)->sin6_addr))) q += 1; #endif } else { #if OS_SOCKET_HAS_IPV6 /* We accept link-local IPv6 addresses, but an interface with a link-local address will end up lower in the ordering than one with a global address. When forced to use a link-local address, we restrict ourselves to operating on that one interface only and assume any advertised (incoming) link-local address belongs to that interface. FIXME: this is wrong, and should be changed to tag addresses with the interface over which it was received. But that means proper multi-homing support and has quite an impact in various places, not least of which is the abstraction layer. */ if (!(tmpip.ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &tmpip)->sin6_addr))) q += 5; #endif /* We strongly prefer a multicast capable interface, if that's not available anything that's not point-to-point, or else we hope IP routing will take care of the issues. */ if (ifs[i].flags & IFF_MULTICAST) q += 4; else if (!(ifs[i].flags & IFF_POINTOPOINT)) q += 3; else q += 2; } nn_log (LC_CONFIG, "(q%d)", q); if (q == quality) { maxq_list[maxq_count] = gv.n_interfaces; maxq_strlen += 2 + strlen (if_name); maxq_count++; } else if (q > quality) { maxq_list[0] = gv.n_interfaces; maxq_strlen += 2 + strlen (if_name); maxq_count = 1; quality = q; } gv.interfaces[gv.n_interfaces].addr = tmpip; gv.interfaces[gv.n_interfaces].netmask = tmpmask; gv.interfaces[gv.n_interfaces].mc_capable = ((ifs[i].flags & IFF_MULTICAST) != 0); gv.interfaces[gv.n_interfaces].point_to_point = ((ifs[i].flags & IFF_POINTOPOINT) != 0); gv.interfaces[gv.n_interfaces].if_index = ifs[i].interfaceIndexNo; gv.interfaces[gv.n_interfaces].name = os_strdup (if_name); gv.n_interfaces++; } nn_log (LC_CONFIG, "\n"); os_free (ifs); if (requested_address == NULL) { if (maxq_count > 1) { const int idx = maxq_list[0]; char *names; sockaddr_to_string_no_port (addrbuf, &gv.interfaces[idx].addr); if ((names = os_malloc (maxq_strlen + 1)) == NULL) NN_WARNING2 ("using network interface %s (%s) out of multiple candidates\n", gv.interfaces[idx].name, addrbuf); else { int p = 0; for (i = 0; i < maxq_count; i++) p += snprintf (names + p, maxq_strlen - p, ", %s", gv.interfaces[maxq_list[i]].name); NN_WARNING3 ("using network interface %s (%s) selected arbitrarily from: %s\n", gv.interfaces[idx].name, addrbuf, names + 2); os_free (names); } } if (maxq_count > 0) selected_idx = maxq_list[0]; else NN_ERROR0 ("failed to determine default own IP address\n"); } else { os_sockaddr_storage req; if (!os_sockaddrStringToAddress (config.networkAddressString, (os_sockaddr *) &req, !config.useIpv6)) { /* Presumably an interface name */ for (i = 0; i < gv.n_interfaces; i++) if (strcmp (gv.interfaces[i].name, config.networkAddressString) == 0) break; } else { /* Try an exact match on the address */ for (i = 0; i < gv.n_interfaces; i++) if (os_sockaddrIPAddressEqual ((os_sockaddr *) &gv.interfaces[i].addr, (os_sockaddr *) &req)) break; if (i == gv.n_interfaces && !config.useIpv6) { /* Try matching on network portion only, where the network portion is based on the netmask of the interface under consideration */ for (i = 0; i < gv.n_interfaces; i++) { os_sockaddr_storage req1 = req, ip1 = gv.interfaces[i].addr; assert (req1.ss_family == AF_INET); assert (ip1.ss_family == AF_INET); /* If the host portion of the requested address is non-zero, skip this interface */ if (((os_sockaddr_in *) &req1)->sin_addr.s_addr & ~((os_sockaddr_in *) &gv.interfaces[i].netmask)->sin_addr.s_addr) continue; ((os_sockaddr_in *) &req1)->sin_addr.s_addr &= ((os_sockaddr_in *) &gv.interfaces[i].netmask)->sin_addr.s_addr; ((os_sockaddr_in *) &ip1)->sin_addr.s_addr &= ((os_sockaddr_in *) &gv.interfaces[i].netmask)->sin_addr.s_addr; if (os_sockaddrIPAddressEqual ((os_sockaddr *) &ip1, (os_sockaddr *) &req1)) break; } } } if (i < gv.n_interfaces) selected_idx = i; else NN_ERROR1 ("%s: does not match an available interface\n", config.networkAddressString); } if (selected_idx < 0) return 0; else { gv.ownip = gv.interfaces[selected_idx].addr; sockaddr_set_port (&gv.ownip, 0); gv.selected_interface = selected_idx; gv.interfaceNo = gv.interfaces[selected_idx].if_index; #if OS_SOCKET_HAS_IPV6 if (config.useIpv6) { assert (gv.ownip.ss_family == AF_INET6); gv.ipv6_link_local = IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &gv.ownip)->sin6_addr) != 0; } else { gv.ipv6_link_local = 0; } #endif nn_log (LC_CONFIG, "selected interface: %s (index %u)\n", gv.interfaces[selected_idx].name, (unsigned) gv.interfaceNo); return 1; } }
static void *lease_renewal_thread (struct nn_servicelease *sl) { /* Do not check more often than once every 100ms (no particular reason why it has to be 100ms), regardless of the lease settings. Note: can't trust sl->self, may have been scheduled before the assignment. */ const os_int64 min_progress_check_intv = 100 * T_MILLISECOND; struct thread_state1 *self = lookup_thread_state (); nn_mtime_t next_thread_cputime = { 0 }; nn_mtime_t tlast = { 0 }; int was_alive = 1; unsigned i; for (i = 0; i < thread_states.nthreads; i++) { sl->av_ary[i].alive = 1; sl->av_ary[i].wd = thread_states.ts[i].watchdog - 1; } os_mutexLock (&sl->lock); while (sl->keepgoing) { unsigned n_alive = 0; nn_mtime_t tnow = now_mt (); LOG_THREAD_CPUTIME (next_thread_cputime); TRACE (("servicelease: tnow %"PA_PRId64":", tnow.v)); /* Check progress only if enough time has passed: there is no guarantee that os_cond_timedwait wont ever return early, and we do want to avoid spurious warnings. */ if (tnow.v < tlast.v + min_progress_check_intv) { n_alive = thread_states.nthreads; } else { tlast = tnow; for (i = 0; i < thread_states.nthreads; i++) { if (thread_states.ts[i].state != THREAD_STATE_ALIVE) n_alive++; else { vtime_t vt = thread_states.ts[i].vtime; vtime_t wd = thread_states.ts[i].watchdog; int alive = vtime_asleep_p (vt) || vtime_asleep_p (wd) || vtime_gt (wd, sl->av_ary[i].wd); n_alive += (unsigned) alive; TRACE ((" %d(%s):%c:%u:%u->%u:", i, thread_states.ts[i].name, alive ? 'a' : 'd', vt, sl->av_ary[i].wd, wd)); sl->av_ary[i].wd = wd; if (sl->av_ary[i].alive != alive) { const char *name = thread_states.ts[i].name; const char *msg; if (!alive) msg = "failed to make progress"; else msg = "once again made progress"; NN_WARNING2 ("thread %s %s\n", name ? name : "(anon)", msg); sl->av_ary[i].alive = (char) alive; } } } } /* Only renew the lease if all threads are alive, so that one thread blocking for a while but not too extremely long will cause warnings for that thread in the log file, but won't cause the DDSI2 service to be marked as dead. */ if (n_alive == thread_states.nthreads) { TRACE ((": [%d] renewing\n", n_alive)); /* FIXME: perhaps it would be nice to control automatic liveliness updates from here. FIXME: should terminate failure of renew_cb() */ sl->renew_cb (sl->renew_arg); was_alive = 1; } else { TRACE ((": [%d] NOT renewing\n", n_alive)); if (was_alive) log_stack_traces (); was_alive = 0; } #if SYSDEPS_HAVE_GETRUSAGE /* If getrusage() is available, use it to log CPU and memory statistics to the trace. Getrusage() can't fail if the parameters are valid, and these are by the book. Still we check. */ if (config.enabled_logcats & LC_TIMING) { struct rusage u; if (getrusage (RUSAGE_SELF, &u) == 0) { nn_log (LC_TIMING, "rusage: utime %d.%06d stime %d.%06d maxrss %ld data %ld vcsw %ld ivcsw %ld\n", (int) u.ru_utime.tv_sec, (int) u.ru_utime.tv_usec, (int) u.ru_stime.tv_sec, (int) u.ru_stime.tv_usec, u.ru_maxrss, u.ru_idrss, u.ru_nvcsw, u.ru_nivcsw); } } #endif os_condTimedWait (&sl->cond, &sl->lock, sl->sleepTime); /* We are never active in a way that matters for the garbage collection of old writers, &c. */ thread_state_asleep (self); } os_mutexUnlock (&sl->lock); return NULL; }