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; }
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"); }
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; }