main.c revision 37453
16059Samurai/* 26059Samurai * User Process PPP 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2037192Sbrian * $Id: main.c,v 1.138 1998/06/27 14:17:28 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2436285Sbrian 2536452Sbrian#include <sys/types.h> 2630715Sbrian#include <netinet/in.h> 2730715Sbrian#include <netinet/in_systm.h> 2830715Sbrian#include <netinet/ip.h> 2936285Sbrian#include <sys/un.h> 3030715Sbrian 3130715Sbrian#include <errno.h> 326059Samurai#include <fcntl.h> 3311336Samurai#include <paths.h> 3430715Sbrian#include <signal.h> 3530715Sbrian#include <stdio.h> 3630715Sbrian#include <string.h> 376059Samurai#include <sys/time.h> 386059Samurai#include <termios.h> 3918786Sjkh#include <unistd.h> 4030715Sbrian 4137141Sbrian#include "probe.h" 4230715Sbrian#include "mbuf.h" 4330715Sbrian#include "log.h" 4430715Sbrian#include "defs.h" 4531061Sbrian#include "id.h" 4630715Sbrian#include "timer.h" 4730715Sbrian#include "fsm.h" 4836285Sbrian#include "lqr.h" 496059Samurai#include "hdlc.h" 5031514Sbrian#include "lcp.h" 5113389Sphk#include "ccp.h" 5236285Sbrian#include "iplist.h" 5336285Sbrian#include "throughput.h" 5436285Sbrian#include "slcompress.h" 556059Samurai#include "ipcp.h" 5636285Sbrian#include "filter.h" 5736285Sbrian#include "descriptor.h" 5836285Sbrian#include "link.h" 5936285Sbrian#include "mp.h" 6036285Sbrian#include "bundle.h" 616735Samurai#include "auth.h" 6213389Sphk#include "systems.h" 6323840Sbrian#include "sig.h" 6430715Sbrian#include "main.h" 6536285Sbrian#include "server.h" 6636285Sbrian#include "prompt.h" 6736285Sbrian#include "chat.h" 6836285Sbrian#include "chap.h" 6936285Sbrian#include "datalink.h" 706059Samurai 716735Samurai#ifndef O_NONBLOCK 726735Samurai#ifdef O_NDELAY 736735Samurai#define O_NONBLOCK O_NDELAY 746735Samurai#endif 756735Samurai#endif 766735Samurai 7736431Sbrianstatic void DoLoop(struct bundle *); 7830715Sbrianstatic void TerminalStop(int); 7931343Sbrianstatic const char *ex_desc(int); 8030715Sbrian 8136285Sbrianstatic struct bundle *SignalBundle; 8236285Sbrianstatic struct prompt *SignalPrompt; 836059Samurai 8410528Samuraivoid 8536285SbrianCleanup(int excode) 866059Samurai{ 8736285Sbrian SignalBundle->CleaningUp = 1; 8836285Sbrian if (bundle_Phase(SignalBundle) != PHASE_DEAD) 8937007Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 906059Samurai} 916059Samurai 926059Samuraivoid 9336285SbrianAbortProgram(int excode) 946059Samurai{ 9536285Sbrian server_Close(SignalBundle); 9636285Sbrian log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 9737007Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 9836285Sbrian bundle_Destroy(SignalBundle); 9936285Sbrian log_Close(); 1006059Samurai exit(excode); 1016059Samurai} 1026059Samurai 1036059Samuraistatic void 10428679SbrianCloseConnection(int signo) 1056059Samurai{ 10626858Sbrian /* NOTE, these are manual, we've done a setsid() */ 10736285Sbrian sig_signal(SIGINT, SIG_IGN); 10836285Sbrian log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 10937018Sbrian bundle_Down(SignalBundle, CLOSE_STAYDOWN); 11036285Sbrian sig_signal(SIGINT, CloseConnection); 1116059Samurai} 1126059Samurai 1136059Samuraistatic void 11428679SbrianCloseSession(int signo) 1156059Samurai{ 11636285Sbrian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 11728679Sbrian Cleanup(EX_TERM); 1186059Samurai} 1196059Samurai 12036285Sbrianstatic pid_t BGPid = 0; 12136285Sbrian 12210528Samuraistatic void 12336285SbrianKillChild(int signo) 12410528Samurai{ 12536285Sbrian log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 12636285Sbrian kill(BGPid, SIGINT); 12710528Samurai} 12810528Samurai 12910528Samuraistatic void 13036285SbrianTerminalCont(int signo) 13110528Samurai{ 13236285Sbrian signal(SIGCONT, SIG_DFL); 13336285Sbrian prompt_Continue(SignalPrompt); 13410528Samurai} 13510528Samurai 13626940Sbrianstatic void 13736285SbrianTerminalStop(int signo) 13826940Sbrian{ 13936285Sbrian prompt_Suspend(SignalPrompt); 14036285Sbrian signal(SIGCONT, TerminalCont); 14136285Sbrian raise(SIGSTOP); 14226940Sbrian} 14326940Sbrian 14431081Sbrianstatic void 14531081SbrianBringDownServer(int signo) 14631081Sbrian{ 14736285Sbrian /* Drops all child prompts too ! */ 14836285Sbrian server_Close(SignalBundle); 14931081Sbrian} 15031081Sbrian 15131343Sbrianstatic const char * 15225908Sbrianex_desc(int ex) 15325908Sbrian{ 15437010Sbrian static char num[12]; /* Used immediately if returned */ 15531343Sbrian static const char *desc[] = { 15631343Sbrian "normal", "start", "sock", "modem", "dial", "dead", "done", 15731343Sbrian "reboot", "errdead", "hangup", "term", "nodial", "nologin" 15831343Sbrian }; 15910528Samurai 16031962Sbrian if (ex >= 0 && ex < sizeof desc / sizeof *desc) 16125908Sbrian return desc[ex]; 16225908Sbrian snprintf(num, sizeof num, "%d", ex); 16325908Sbrian return num; 16425908Sbrian} 16525908Sbrian 16630715Sbrianstatic void 16731343SbrianUsage(void) 1686059Samurai{ 16920120Snate fprintf(stderr, 17031343Sbrian "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" 17131343Sbrian#ifndef NOALIAS 17231343Sbrian " [ -alias ]" 17331343Sbrian#endif 17431343Sbrian " [system]\n"); 1756059Samurai exit(EX_START); 1766059Samurai} 1776059Samurai 17831197Sbrianstatic char * 17937191SbrianProcessArgs(int argc, char **argv, int *mode, int *alias) 1806059Samurai{ 18136465Sbrian int optc, labelrequired, newmode; 1826059Samurai char *cp; 1836059Samurai 18436285Sbrian optc = labelrequired = 0; 18536465Sbrian *mode = PHYS_INTERACTIVE; 18637191Sbrian *alias = 0; 1876059Samurai while (argc > 0 && **argv == '-') { 1886059Samurai cp = *argv + 1; 18936465Sbrian newmode = Nam2mode(cp); 19036465Sbrian switch (newmode) { 19136465Sbrian case PHYS_NONE: 19236465Sbrian if (strcmp(cp, "alias") == 0) { 19337191Sbrian#ifdef NOALIAS 19437191Sbrian log_Printf(LogWARN, "Cannot load alias library\n"); 19537191Sbrian#else 19637191Sbrian *alias = 1; 19736285Sbrian#endif 19836465Sbrian optc--; /* this option isn't exclusive */ 19936465Sbrian } else 20036465Sbrian Usage(); 20136465Sbrian break; 20236465Sbrian 20336465Sbrian case PHYS_ALL: 20436465Sbrian Usage(); 20536465Sbrian break; 20636465Sbrian 20736465Sbrian case PHYS_AUTO: 20836465Sbrian case PHYS_BACKGROUND: 20936465Sbrian case PHYS_DDIAL: 21036465Sbrian labelrequired = 1; 21136465Sbrian /* fall through */ 21236465Sbrian 21336465Sbrian default: 21436465Sbrian *mode = newmode; 21536465Sbrian } 2166059Samurai optc++; 21728679Sbrian argv++; 21828679Sbrian argc--; 2196059Samurai } 22036465Sbrian 2216059Samurai if (argc > 1) { 22236285Sbrian fprintf(stderr, "You may specify only one system label.\n"); 2236059Samurai exit(EX_START); 2246059Samurai } 2256059Samurai 2266059Samurai if (optc > 1) { 22736285Sbrian fprintf(stderr, "You may specify only one mode.\n"); 2286059Samurai exit(EX_START); 2296059Samurai } 23031197Sbrian 23136285Sbrian if (labelrequired && argc != 1) { 23236285Sbrian fprintf(stderr, "Destination system must be specified in" 23336285Sbrian " auto, background or ddial mode.\n"); 23436285Sbrian exit(EX_START); 23536285Sbrian } 23636285Sbrian 23731197Sbrian return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ 2386059Samurai} 2396059Samurai 24026940Sbrianint 24128679Sbrianmain(int argc, char **argv) 2426059Samurai{ 24331197Sbrian char *name, *label; 24437191Sbrian int nfds, mode, alias; 24536285Sbrian struct bundle *bundle; 24636285Sbrian struct prompt *prompt; 24726516Sbrian 24831823Sbrian nfds = getdtablesize(); 24931823Sbrian if (nfds >= FD_SETSIZE) 25031823Sbrian /* 25131823Sbrian * If we've got loads of file descriptors, make sure they're all 25231823Sbrian * closed. If they aren't, we may end up with a seg fault when our 25331823Sbrian * `fd_set's get too big when select()ing ! 25431823Sbrian */ 25531823Sbrian while (--nfds > 2) 25631823Sbrian close(nfds); 25731823Sbrian 25830715Sbrian name = strrchr(argv[0], '/'); 25936285Sbrian log_Open(name ? name + 1 : argv[0]); 26026516Sbrian 26137191Sbrian label = ProcessArgs(argc - 1, argv + 1, &mode, &alias); 26231121Sbrian 26336285Sbrian#ifdef __FreeBSD__ 26436285Sbrian /* 26536285Sbrian * A FreeBSD hack to dodge a bug in the tty driver that drops output 26636285Sbrian * occasionally.... I must find the real reason some time. To display 26736285Sbrian * the dodgy behaviour, comment out this bit, make yourself a large 26836285Sbrian * routing table and then run ppp in interactive mode. The `show route' 26936285Sbrian * command will drop chunks of data !!! 27036285Sbrian */ 27136465Sbrian if (mode == PHYS_INTERACTIVE) { 27236285Sbrian close(STDIN_FILENO); 27336285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 27436285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 27536285Sbrian return 2; 27636285Sbrian } 27736285Sbrian } 27836285Sbrian#endif 27936285Sbrian 28036285Sbrian /* Allow output for the moment (except in direct mode) */ 28136285Sbrian if (mode == PHYS_DIRECT) 28236285Sbrian prompt = NULL; 28336285Sbrian else { 28436285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 28536465Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(mode)); 28636285Sbrian } 28736285Sbrian 28831121Sbrian ID0init(); 28931158Sbrian if (ID0realuid() != 0) { 29031158Sbrian char conf[200], *ptr; 29131158Sbrian 29231158Sbrian snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 29331158Sbrian do { 29431158Sbrian if (!access(conf, W_OK)) { 29537019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 29637019Sbrian conf); 29731158Sbrian return -1; 29831158Sbrian } 29931158Sbrian ptr = conf + strlen(conf)-2; 30031158Sbrian while (ptr > conf && *ptr != '/') 30131158Sbrian *ptr-- = '\0'; 30231158Sbrian } while (ptr >= conf); 30331158Sbrian } 30431158Sbrian 30536285Sbrian if (!system_IsValid(label, prompt, mode)) { 30631121Sbrian fprintf(stderr, "You may not use ppp in this mode with this label\n"); 30736285Sbrian if (mode == PHYS_DIRECT) { 30831157Sbrian const char *l; 30931197Sbrian l = label ? label : "default"; 31036285Sbrian log_Printf(LogWARN, "Label %s rejected -direct connection\n", l); 31131157Sbrian } 31236285Sbrian log_Close(); 31331121Sbrian return 1; 31429083Sbrian } 31531121Sbrian 31636467Sbrian if ((bundle = bundle_Create(TUN_PREFIX, mode, (const char **)argv)) == NULL) { 31736285Sbrian log_Printf(LogWARN, "bundle_Create: %s\n", strerror(errno)); 31826940Sbrian return EX_START; 3196059Samurai } 32036314Sbrian if (prompt) { 32136314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 32236314Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->ifp.Name); 32336314Sbrian } 32436285Sbrian SignalBundle = bundle; 32537191Sbrian bundle->AliasEnabled = alias; 32631121Sbrian 32737008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 32836285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 32936285Sbrian 33036285Sbrian sig_signal(SIGHUP, CloseSession); 33136285Sbrian sig_signal(SIGTERM, CloseSession); 33236285Sbrian sig_signal(SIGINT, CloseConnection); 33336285Sbrian sig_signal(SIGQUIT, CloseSession); 33436285Sbrian sig_signal(SIGALRM, SIG_IGN); 33524753Sache signal(SIGPIPE, SIG_IGN); 3366059Samurai 33736465Sbrian if (mode == PHYS_INTERACTIVE) 33836285Sbrian sig_signal(SIGTSTP, TerminalStop); 33936285Sbrian 34036285Sbrian sig_signal(SIGUSR2, BringDownServer); 34136285Sbrian 34231197Sbrian if (label) { 34331197Sbrian /* 34436285Sbrian * Set label both before and after system_Select ! 34536285Sbrian * This way, "set enddisc label" works during system_Select, and we 34636285Sbrian * also end up with the correct label if we have embedded load 34736285Sbrian * commands. 34831197Sbrian */ 34936285Sbrian bundle_SetLabel(bundle, label); 35037008Sbrian if (system_Select(bundle, label, CONFFILE, prompt, NULL) < 0) { 35136285Sbrian prompt_Printf(prompt, "Destination system (%s) not found.\n", label); 35236285Sbrian AbortProgram(EX_START); 3536059Samurai } 35436285Sbrian bundle_SetLabel(bundle, label); 35536465Sbrian if (mode == PHYS_AUTO && 35636285Sbrian bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 35736285Sbrian prompt_Printf(prompt, "You must \"set ifaddr\" with a peer address " 35836285Sbrian "in label %s for auto mode.\n", label); 35936285Sbrian AbortProgram(EX_START); 36036285Sbrian } 3616059Samurai } 36226940Sbrian 36336465Sbrian if (mode != PHYS_INTERACTIVE) { 36436285Sbrian if (mode != PHYS_DIRECT) { 36536285Sbrian int bgpipe[2]; 36636285Sbrian pid_t bgpid; 36736285Sbrian 36836465Sbrian if (mode == PHYS_BACKGROUND && pipe(bgpipe)) { 36936285Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 37036285Sbrian AbortProgram(EX_SOCK); 37120813Sjkh } 3726059Samurai 37328679Sbrian bgpid = fork(); 37420813Sjkh if (bgpid == -1) { 37536285Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 37636285Sbrian AbortProgram(EX_SOCK); 37720813Sjkh } 37836285Sbrian 37920813Sjkh if (bgpid) { 38020813Sjkh char c = EX_NORMAL; 38111336Samurai 38236465Sbrian if (mode == PHYS_BACKGROUND) { 38336285Sbrian close(bgpipe[1]); 38420813Sjkh BGPid = bgpid; 38536285Sbrian /* If we get a signal, kill the child */ 38636285Sbrian signal(SIGHUP, KillChild); 38736285Sbrian signal(SIGTERM, KillChild); 38836285Sbrian signal(SIGINT, KillChild); 38936285Sbrian signal(SIGQUIT, KillChild); 39036285Sbrian 39136285Sbrian /* Wait for our child to close its pipe before we exit */ 39236285Sbrian if (read(bgpipe[0], &c, 1) != 1) { 39336285Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 39436285Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 39525908Sbrian } else if (c == EX_NORMAL) { 39636285Sbrian prompt_Printf(prompt, "PPP enabled.\n"); 39736285Sbrian log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 39825908Sbrian } else { 39936285Sbrian prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 40036285Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 40128679Sbrian ex_desc((int) c)); 40228679Sbrian } 40336285Sbrian close(bgpipe[0]); 40420813Sjkh } 40528679Sbrian return c; 40636465Sbrian } else if (mode == PHYS_BACKGROUND) { 40736285Sbrian close(bgpipe[0]); 40836285Sbrian bundle->notify.fd = bgpipe[1]; 40936285Sbrian } 41020813Sjkh 41136709Sbrian bundle_LockTun(bundle); /* we have a new pid */ 41236709Sbrian 41336285Sbrian /* -auto, -dedicated, -ddial & -background */ 41436285Sbrian prompt_Destroy(prompt, 0); 41536285Sbrian close(STDOUT_FILENO); 41636285Sbrian close(STDERR_FILENO); 41736285Sbrian close(STDIN_FILENO); 41826686Sbrian setsid(); 41936285Sbrian } else { 42036285Sbrian /* -direct: STDIN_FILENO gets used by modem_Open */ 42136285Sbrian prompt_TtyInit(NULL); 42236285Sbrian close(STDOUT_FILENO); 42336285Sbrian close(STDERR_FILENO); 42426686Sbrian } 4256059Samurai } else { 42636285Sbrian /* Interactive mode */ 42732129Sbrian close(STDERR_FILENO); 42836285Sbrian prompt_TtyInit(prompt); 42936285Sbrian prompt_TtyCommandMode(prompt); 43036285Sbrian prompt_Required(prompt); 4316059Samurai } 43229696Sbrian 43336285Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(mode)); 43436431Sbrian DoLoop(bundle); 43536285Sbrian AbortProgram(EX_NORMAL); 4366059Samurai 43736285Sbrian return EX_NORMAL; 4386059Samurai} 4396059Samurai 4406059Samuraistatic void 44136431SbrianDoLoop(struct bundle *bundle) 4426059Samurai{ 4436059Samurai fd_set rfds, wfds, efds; 44437141Sbrian int i, nfds, nothing_done; 44537141Sbrian struct probe probe; 4466059Samurai 44737141Sbrian probe_Init(&probe); 44837141Sbrian 44936285Sbrian do { 45023598Sache nfds = 0; 45128679Sbrian FD_ZERO(&rfds); 45228679Sbrian FD_ZERO(&wfds); 45328679Sbrian FD_ZERO(&efds); 4547001Samurai 45536314Sbrian /* All our datalinks, the tun device and the MP socket */ 45636285Sbrian descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 45725067Sbrian 45836314Sbrian /* All our prompts and the diagnostic socket */ 45936314Sbrian descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 46036314Sbrian 46136285Sbrian if (bundle_IsDead(bundle)) 46236285Sbrian /* Don't select - we'll be here forever */ 46336285Sbrian break; 46426551Sbrian 46536285Sbrian i = select(nfds, &rfds, &wfds, &efds, NULL); 46626696Sbrian 46736345Sbrian if (i < 0 && errno != EINTR) { 46836285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 46936285Sbrian if (log_IsKept(LogTIMER)) { 47036285Sbrian struct timeval t; 47136285Sbrian 47236285Sbrian for (i = 0; i <= nfds; i++) { 47336285Sbrian if (FD_ISSET(i, &rfds)) { 47436285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 47536285Sbrian FD_CLR(i, &rfds); 47636285Sbrian t.tv_sec = t.tv_usec = 0; 47736285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 47836285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 47936285Sbrian break; 48036285Sbrian } 48136285Sbrian } 48236285Sbrian if (FD_ISSET(i, &wfds)) { 48336285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 48436285Sbrian FD_CLR(i, &wfds); 48536285Sbrian t.tv_sec = t.tv_usec = 0; 48636285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 48736285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 48836285Sbrian break; 48936285Sbrian } 49036285Sbrian } 49136285Sbrian if (FD_ISSET(i, &efds)) { 49236285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 49336285Sbrian FD_CLR(i, &efds); 49436285Sbrian t.tv_sec = t.tv_usec = 0; 49536285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 49636285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 49736285Sbrian break; 49836285Sbrian } 49936285Sbrian } 50036285Sbrian } 50128679Sbrian } 50228679Sbrian break; 5038857Srgrimes } 5046059Samurai 50536345Sbrian sig_Handle(); 50636345Sbrian 50736345Sbrian if (i <= 0) 50836345Sbrian continue; 50936345Sbrian 51036285Sbrian for (i = 0; i <= nfds; i++) 51136285Sbrian if (FD_ISSET(i, &efds)) { 51237019Sbrian log_Printf(LogERROR, "Exception detected on descriptor %d\n", i); 51336285Sbrian break; 5146059Samurai } 51528679Sbrian 51636285Sbrian if (i <= nfds) 51736285Sbrian break; 51828536Sbrian 51937141Sbrian nothing_done = 1; 52037141Sbrian 52137141Sbrian if (descriptor_IsSet(&server.desc, &rfds)) { 52236285Sbrian descriptor_Read(&server.desc, bundle, &rfds); 52337141Sbrian nothing_done = 0; 52437141Sbrian } 52532039Sbrian 52637141Sbrian if (descriptor_IsSet(&bundle->desc, &rfds)) { 52737141Sbrian descriptor_Read(&bundle->desc, bundle, &rfds); 52837141Sbrian nothing_done = 0; 52937141Sbrian } 53037141Sbrian 53136285Sbrian if (descriptor_IsSet(&bundle->desc, &wfds)) 53237141Sbrian if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { 53337141Sbrian /* 53437141Sbrian * This is disasterous. The OS has told us that something is 53537141Sbrian * writable, and all our write()s have failed. Rather than 53637141Sbrian * going back immediately to do our UpdateSet()s and select(), 53737141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 53837141Sbrian */ 53937141Sbrian struct timeval t; 54036285Sbrian 54137141Sbrian t.tv_sec = 0; 54237141Sbrian t.tv_usec = 100000; 54337141Sbrian select(0, NULL, NULL, NULL, &t); 54437141Sbrian } 54536345Sbrian 54636285Sbrian } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); 54736285Sbrian 54836285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 5496059Samurai} 550