Пример #1
0
static void
datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
{
  struct datalink *dl = descriptor2datalink(d);

  switch (dl->state) {
    case DATALINK_CLOSED:
    case DATALINK_OPENING:
      break;

    case DATALINK_HANGUP:
    case DATALINK_DIAL:
    case DATALINK_LOGOUT:
    case DATALINK_LOGIN:
      descriptor_Read(&dl->chat.desc, bundle, fdset);
      break;

    case DATALINK_READY:
    case DATALINK_LCP:
    case DATALINK_AUTH:
    case DATALINK_CBCP:
    case DATALINK_OPEN:
      if (descriptor_IsSet(&dl->chap.desc, fdset))
        descriptor_Read(&dl->chap.desc, bundle, fdset);
      if (descriptor_IsSet(&dl->physical->desc, fdset))
        descriptor_Read(&dl->physical->desc, bundle, fdset);
      break;
  }
}
Пример #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
server_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
{
  struct server *s = descriptor2server(d);
  struct sockaddr_storage ss;
  struct sockaddr *sa = (struct sockaddr *)&ss;
  struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
#ifndef NOINET6
  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
#endif
  int ssize = sizeof ss, wfd;
  struct prompt *p;
  struct ncpaddr addr;

  if (s->fd >= 0 && FD_ISSET(s->fd, fdset)) {
    wfd = accept(s->fd, sa, &ssize);
    if (wfd < 0)
      log_Printf(LogERROR, "server_Read: accept(): %s\n", strerror(errno));
    else if (sa->sa_len == 0) {
      close(wfd);
      wfd = -1;
    }
  } else
    wfd = -1;

  if (wfd >= 0)
    switch (sa->sa_family) {
      case AF_LOCAL:
        log_Printf(LogPHASE, "Connected to local client.\n");
        break;

      case AF_INET:
        ncpaddr_setsa(&addr, sa);
        if (ntohs(sin->sin_port) < 1024) {
          log_Printf(LogALERT, "Rejected client connection from %s:%u"
                    "(invalid port number) !\n",
                    ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
          close(wfd);
          wfd = -1;
          break;
        }
        log_Printf(LogPHASE, "Connected to client from %s:%u\n",
                  ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
        break;

#ifndef NOINET6
      case AF_INET6:
        ncpaddr_setsa(&addr, sa);
        if (ntohs(sin6->sin6_port) < 1024) {
          log_Printf(LogALERT, "Rejected client connection from %s:%u"
                    "(invalid port number) !\n",
                    ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
          close(wfd);
          wfd = -1;
          break;
        }
        log_Printf(LogPHASE, "Connected to client from %s:%u\n",
                  ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
        break;
#endif

      default:
        write(wfd, "Unrecognised access !\n", 22);
        close(wfd);
        wfd = -1;
        break;
    }

  if (wfd >= 0) {
    if ((p = prompt_Create(s, bundle, wfd)) == NULL) {
      write(wfd, "Connection refused.\n", 20);
      close(wfd);
    } else {
      switch (sa->sa_family) {
        case AF_LOCAL:
          p->src.type = "local";
          strncpy(p->src.from, s->cfg.sockname, sizeof p->src.from - 1);
          p->src.from[sizeof p->src.from - 1] = '\0';
          break;
        case AF_INET:
          p->src.type = "ip";
          snprintf(p->src.from, sizeof p->src.from, "%s:%u",
                   ncpaddr_ntoa(&addr), ntohs(sin->sin_port));
          break;
#ifndef NOINET6
        case AF_INET6:
          p->src.type = "ip6";
          snprintf(p->src.from, sizeof p->src.from, "%s:%u",
                   ncpaddr_ntoa(&addr), ntohs(sin6->sin6_port));
          break;
#endif
      }
      prompt_TtyCommandMode(p);
      prompt_Required(p);
    }
  }

  log_PromptListChanged = 0;
  for (p = log_PromptList(); p; p = p->next)
    if (descriptor_IsSet(&p->desc, fdset)) {
      descriptor_Read(&p->desc, bundle, fdset);
      if (log_PromptListChanged)
        break;
    }
}