Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
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;
  }
}
Exemplo n.º 4
0
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;
}