示例#1
0
/*
 * Get a netgraph message
 */
static ssize_t
ng_MessageIn(struct physical *p, char *buf, size_t sz)
{
    char msgbuf[sizeof(struct ng_mesg) * 2 + NG_MSGBUFSZ];
    struct ngdevice *dev = device2ng(p->handler);
    struct ng_mesg *rep = (struct ng_mesg *)msgbuf;
    char path[NG_PATHSIZ];
    size_t len;

#ifdef BROKEN_SELECT
    struct timeval t;
    fd_set *r;
    int ret;

    if (dev->cs < 0)
        return 0;

    if ((r = mkfdset()) == NULL) {
        log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
        return -1;
    }
    zerofdset(r);
    FD_SET(dev->cs, r);
    t.tv_sec = t.tv_usec = 0;
    ret = select(dev->cs + 1, r, NULL, NULL, &t);
    free(r);

    if (ret <= 0)
        return 0;
#endif

    if (NgRecvAsciiMsg(dev->cs, rep, sizeof msgbuf, path)) {
        log_Printf(LogWARN, "%s: NgRecvAsciiMsg: %s\n",
                   dev->dev.name, strerror(errno));
        return -1;
    }

    /* XXX: Should we check rep->header.version ? */

    if (sz == 0)
        log_Printf(LogWARN, "%s: Unexpected message: %s\n", dev->dev.name,
                   rep->header.cmdstr);
    else {
        log_Printf(LogDEBUG, "%s: Received message: %s\n", dev->dev.name,
                   rep->header.cmdstr);
        len = strlen(rep->header.cmdstr);
        if (sz > len)
            sz = len;
        memcpy(buf, rep->header.cmdstr, sz);
    }

    return sz;
}
示例#2
0
static void
DoLoop(struct bundle *bundle)
{
  fd_set *rfds, *wfds, *efds;
  int i, nfds, nothing_done;

  if ((rfds = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    return;
  }

  if ((wfds = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    free(rfds);
    return;
  }

  if ((efds = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    free(rfds);
    free(wfds);
    return;
  }

  for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) {
    nfds = 0;
    zerofdset(rfds);
    zerofdset(wfds);
    zerofdset(efds);

    /* All our datalinks, the tun device and the MP socket */
    descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);

    /* All our prompts and the diagnostic socket */
    descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);

    bundle_CleanDatalinks(bundle);
    if (bundle_IsDead(bundle))
      /* Don't select - we'll be here forever */
      break;

    /*
     * It's possible that we've had a signal since we last checked.  If
     * we don't check again before calling select(), we may end up stuck
     * after having missed the event.... sig_Handle() tries to be as
     * quick as possible if nothing is likely to have happened.
     * This is only really likely if we block in open(... O_NONBLOCK)
     * which will happen with a misconfigured device.
     */
    if (sig_Handle())
      continue;

    i = select(nfds, rfds, wfds, efds, NULL);

    if (i < 0 && errno != EINTR) {
      log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
      if (log_IsKept(LogTIMER)) {
        struct timeval t;

        for (i = 0; i <= nfds; i++) {
          if (FD_ISSET(i, rfds)) {
            log_Printf(LogTIMER, "Read set contains %d\n", i);
            FD_CLR(i, rfds);
            t.tv_sec = t.tv_usec = 0;
            if (select(nfds, rfds, wfds, efds, &t) != -1) {
              log_Printf(LogTIMER, "The culprit !\n");
              break;
            }
          }
          if (FD_ISSET(i, wfds)) {
            log_Printf(LogTIMER, "Write set contains %d\n", i);
            FD_CLR(i, wfds);
            t.tv_sec = t.tv_usec = 0;
            if (select(nfds, rfds, wfds, efds, &t) != -1) {
              log_Printf(LogTIMER, "The culprit !\n");
              break;
            }
          }
          if (FD_ISSET(i, efds)) {
            log_Printf(LogTIMER, "Error set contains %d\n", i);
            FD_CLR(i, efds);
            t.tv_sec = t.tv_usec = 0;
            if (select(nfds, rfds, wfds, efds, &t) != -1) {
              log_Printf(LogTIMER, "The culprit !\n");
              break;
            }
          }
        }
      }
      break;
    }

    log_Printf(LogTIMER, "Select returns %d\n", i);

    sig_Handle();

    if (i <= 0)
      continue;

    for (i = 0; i <= nfds; i++)
      if (FD_ISSET(i, efds)) {
        log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i);
        /* We deal gracefully with link descriptor exceptions */
        if (!bundle_Exception(bundle, i)) {
          log_Printf(LogERROR, "Exception cannot be handled !\n");
          break;
        }
      }

    if (i <= nfds)
      break;

    nothing_done = 1;

    if (descriptor_IsSet(&server.desc, rfds)) {
      descriptor_Read(&server.desc, bundle, rfds);
      nothing_done = 0;
    }

    if (descriptor_IsSet(&bundle->desc, rfds)) {
      descriptor_Read(&bundle->desc, bundle, rfds);
      nothing_done = 0;
    }

    if (descriptor_IsSet(&bundle->desc, wfds))
      if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) {
        /*
         * This is disastrous.  The OS has told us that something is
         * writable, and all our write()s have failed.  Rather than
         * going back immediately to do our UpdateSet()s and select(),
         * we sleep for a bit to avoid gobbling up all cpu time.
         */
        struct timeval t;

        t.tv_sec = 0;
        t.tv_usec = 100000;
        select(0, NULL, NULL, NULL, &t);
      }
  }

  log_Printf(LogDEBUG, "DoLoop done.\n");
}
示例#3
0
static void
ether_MessageIn(struct etherdevice *dev)
{
  char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
  struct ng_mesg *rep = (struct ng_mesg *)msgbuf;
  struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep);
  char *end, unknown[14], sessionid[5];
  const char *msg;
  struct timeval t;
  fd_set *r;
  u_long slot;
  int asciilen, ret;

  if (dev->cs < 0)
    return;

  if ((r = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    return;
  }

  while (1) {
    zerofdset(r);
    FD_SET(dev->cs, r);
    t.tv_sec = t.tv_usec = 0;
    ret = select(dev->cs + 1, r, NULL, NULL, &t);

    if (ret <= 0)
      break;

    if (NgRecvMsg(dev->cs, rep, sizeof msgbuf, NULL) <= 0)
      break;

    if (rep->header.version != NG_VERSION) {
      log_Printf(LogWARN, "%ld: Unexpected netgraph version, expected %ld\n",
                 (long)rep->header.version, (long)NG_VERSION);
      break;
    }

    if (rep->header.typecookie != NGM_PPPOE_COOKIE) {
      log_Printf(LogWARN, "%ld: Unexpected netgraph cookie, expected %ld\n",
                 (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE);
      break;
    }

    asciilen = 0;
    switch (rep->header.cmd) {
      case NGM_PPPOE_SET_FLAG:	msg = "SET_FLAG";	break;
      case NGM_PPPOE_CONNECT:	msg = "CONNECT";	break;
      case NGM_PPPOE_LISTEN:	msg = "LISTEN";		break;
      case NGM_PPPOE_OFFER:	msg = "OFFER";		break;
      case NGM_PPPOE_SUCCESS:	msg = "SUCCESS";	break;
      case NGM_PPPOE_FAIL:	msg = "FAIL";		break;
      case NGM_PPPOE_CLOSE:	msg = "CLOSE";		break;
      case NGM_PPPOE_GET_STATUS:	msg = "GET_STATUS";	break;
      case NGM_PPPOE_ACNAME:
        msg = "ACNAME";
        if (setenv("ACNAME", sts->hook, 1) != 0)
          log_Printf(LogWARN, "setenv: cannot set ACNAME=%s: %m", sts->hook);
        asciilen = rep->header.arglen;
        break;
      case NGM_PPPOE_SESSIONID:
        msg = "SESSIONID";
        snprintf(sessionid, sizeof sessionid, "%04x", *(u_int16_t *)sts);
        if (setenv("SESSIONID", sessionid, 1) != 0)
          syslog(LOG_WARNING, "setenv: cannot set SESSIONID=%s: %m",
                 sessionid);
        /* Use this in preference to our interface index */
        slot = strtoul(sessionid, &end, 16);
        if (end != sessionid && *end == '\0')
            dev->slot = slot;
        break;
      default:
        snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd);
        msg = unknown;
        break;
    }

    if (asciilen)
      log_Printf(LogPHASE, "Received NGM_PPPOE_%s (hook \"%.*s\")\n",
                 msg, asciilen, sts->hook);
    else
      log_Printf(LogPHASE, "Received NGM_PPPOE_%s\n", msg);

    switch (rep->header.cmd) {
      case NGM_PPPOE_SUCCESS:
        dev->connected = CARRIER_OK;
        break;
      case NGM_PPPOE_FAIL:
      case NGM_PPPOE_CLOSE:
        dev->connected = CARRIER_LOST;
        break;
    }
  }
  free(r);
}