Ejemplo n.º 1
0
static int
server_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
{
  struct server *s = descriptor2server(d);
  struct prompt *p;
  int sets;

  sets = 0;
  if (r && s->fd >= 0) {
    if (*n < s->fd + 1)
      *n = s->fd + 1;
    FD_SET(s->fd, r);
    log_Printf(LogTIMER, "server: fdset(r) %d\n", s->fd);
    sets++;
  }

  for (p = log_PromptList(); p; p = p->next)
    sets += descriptor_UpdateSet(&p->desc, r, w, e, n);

  return sets;
}
Ejemplo n.º 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");
}
Ejemplo n.º 3
0
static int
datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
                   int *n)
{
  struct datalink *dl = descriptor2datalink(d);
  int result;

  result = 0;
  switch (dl->state) {
    case DATALINK_CLOSED:
      if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|
                                 PHYS_FOREGROUND|PHYS_DDIAL)) &&
          !dl->bundle->CleaningUp)
        /*
         * Our first time in - DEDICATED & DDIAL never come down, and
         * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter
         * DATALINK_CLOSED.  Go to DATALINK_OPENING via datalink_Up()
         * and fall through.
         */
        datalink_Up(dl, 1, 1);
      else
        break;
      /* FALLTHROUGH */

    case DATALINK_OPENING:
      if (dl->dial.timer.state != TIMER_RUNNING) {
        if (--dl->dial.tries < 0)
          dl->dial.tries = 0;
        if (physical_Open(dl->physical, dl->bundle) >= 0) {
          log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n"
                           "Type `~?' for help\r\n", dl->name,
                           dl->physical->name.full);
          if (dl->script.run) {
            datalink_NewState(dl, DATALINK_DIAL);
            if (!chat_Setup(&dl->chat, dl->cfg.script.dial,
                            *dl->cfg.script.dial ?
                            datalink_ChoosePhoneNumber(dl) : ""))
              log_Printf(LogWARN, "Invalid dial script\n");
            if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
                dl->cfg.dial.max)
              log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
                        dl->name, dl->cfg.dial.max - dl->dial.tries,
                        dl->cfg.dial.max);
          } else
            datalink_NewState(dl, DATALINK_CARRIER);
          return datalink_UpdateSet(d, r, w, e, n);
        } else {
          if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
              dl->cfg.dial.max)
            log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n",
                       dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max);
          else
            log_Printf(LogCHAT, "Failed to open device\n");

          if (dl->bundle->CleaningUp ||
              (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
               dl->cfg.dial.max && dl->dial.tries == 0)) {
            datalink_NewState(dl, DATALINK_CLOSED);
            dl->reconnect_tries = 0;
            dl->dial.tries = -1;
            log_WritePrompts(dl, "Failed to open %s\n",
                             dl->physical->name.full);
            bundle_LinkClosed(dl->bundle, dl);
          }
          if (!dl->bundle->CleaningUp) {
            int timeout;

            timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
            bundle_Notify(dl->bundle, EX_REDIAL);
            log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n",
                             dl->physical->name.full, timeout);
          }
        }
      }
      break;

    case DATALINK_CARRIER:
      /* Wait for carrier on the device */
      switch (physical_AwaitCarrier(dl->physical)) {
        case CARRIER_PENDING:
          log_Printf(LogDEBUG, "Waiting for carrier\n");
          return 0;	/* A device timer is running to wake us up again */

        case CARRIER_OK:
          if (dl->script.run) {
            datalink_NewState(dl, DATALINK_LOGIN);
            if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL))
              log_Printf(LogWARN, "Invalid login script\n");
          } else
            datalink_LoginDone(dl);
          return datalink_UpdateSet(d, r, w, e, n);

        case CARRIER_LOST:
          physical_Offline(dl->physical);	/* Is this required ? */
          if (dl->script.run) {
            datalink_NewState(dl, DATALINK_HANGUP);
            if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
              log_Printf(LogWARN, "Invalid hangup script\n");
            return datalink_UpdateSet(d, r, w, e, n);
          } else {
            datalink_HangupDone(dl);
            return 0;	/* Maybe bundle_CleanDatalinks() has something to do */
          }
      }

    case DATALINK_HANGUP:
    case DATALINK_DIAL:
    case DATALINK_LOGOUT:
    case DATALINK_LOGIN:
      result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
      switch (dl->chat.state) {
        case CHAT_DONE:
          /* script succeeded */
          switch(dl->state) {
            case DATALINK_HANGUP:
              datalink_HangupDone(dl);
              break;
            case DATALINK_DIAL:
              datalink_NewState(dl, DATALINK_CARRIER);
              return datalink_UpdateSet(d, r, w, e, n);
            case DATALINK_LOGOUT:
              datalink_NewState(dl, DATALINK_HANGUP);
              physical_Offline(dl->physical);
              if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
                log_Printf(LogWARN, "Invalid hangup script\n");
              return datalink_UpdateSet(d, r, w, e, n);
            case DATALINK_LOGIN:
              dl->phone.alt = NULL;
              datalink_LoginDone(dl);
              return datalink_UpdateSet(d, r, w, e, n);
          }
          break;
        case CHAT_FAILED:
          /* Going down - script failed */
          log_Printf(LogWARN, "Chat script failed\n");
          switch(dl->state) {
            case DATALINK_HANGUP:
              datalink_HangupDone(dl);
              break;
            case DATALINK_DIAL:
            case DATALINK_LOGOUT:
            case DATALINK_LOGIN:
              datalink_NewState(dl, DATALINK_HANGUP);
              physical_Offline(dl->physical);
              if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
                log_Printf(LogWARN, "Invalid hangup script\n");
              return datalink_UpdateSet(d, r, w, e, n);
          }
          break;
      }
      break;

    case DATALINK_READY:
    case DATALINK_LCP:
    case DATALINK_AUTH:
    case DATALINK_CBCP:
    case DATALINK_OPEN:
      result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) +
               descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
      break;
  }
  return result;
}