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