main.c revision 52396
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 * 2050479Speter * $FreeBSD: head/usr.sbin/ppp/main.c 52396 1999-10-19 15:21:09Z brian $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2436285Sbrian 2543313Sbrian#include <sys/param.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> 3652396Sbrian#include <stdlib.h> 3730715Sbrian#include <string.h> 386059Samurai#include <sys/time.h> 396059Samurai#include <termios.h> 4018786Sjkh#include <unistd.h> 4149581Sbrian#include <sys/stat.h> 4230715Sbrian 4350059Sbrian#ifndef NONAT 4446086Sbrian#ifdef __FreeBSD__ 4546086Sbrian#include <alias.h> 4646086Sbrian#else 4739395Sbrian#include "alias.h" 4839395Sbrian#endif 4939395Sbrian#endif 5046686Sbrian#include "layer.h" 5137141Sbrian#include "probe.h" 5230715Sbrian#include "mbuf.h" 5330715Sbrian#include "log.h" 5430715Sbrian#include "defs.h" 5531061Sbrian#include "id.h" 5630715Sbrian#include "timer.h" 5730715Sbrian#include "fsm.h" 5836285Sbrian#include "lqr.h" 596059Samurai#include "hdlc.h" 6031514Sbrian#include "lcp.h" 6113389Sphk#include "ccp.h" 6236285Sbrian#include "iplist.h" 6336285Sbrian#include "throughput.h" 6436285Sbrian#include "slcompress.h" 656059Samurai#include "ipcp.h" 6636285Sbrian#include "filter.h" 6736285Sbrian#include "descriptor.h" 6836285Sbrian#include "link.h" 6936285Sbrian#include "mp.h" 7043313Sbrian#ifndef NORADIUS 7143313Sbrian#include "radius.h" 7243313Sbrian#endif 7336285Sbrian#include "bundle.h" 746735Samurai#include "auth.h" 7513389Sphk#include "systems.h" 7623840Sbrian#include "sig.h" 7730715Sbrian#include "main.h" 7836285Sbrian#include "server.h" 7936285Sbrian#include "prompt.h" 8036285Sbrian#include "chat.h" 8136285Sbrian#include "chap.h" 8238174Sbrian#include "cbcp.h" 8336285Sbrian#include "datalink.h" 8440561Sbrian#include "iface.h" 856059Samurai 866735Samurai#ifndef O_NONBLOCK 876735Samurai#ifdef O_NDELAY 886735Samurai#define O_NONBLOCK O_NDELAY 896735Samurai#endif 906735Samurai#endif 916735Samurai 9236431Sbrianstatic void DoLoop(struct bundle *); 9330715Sbrianstatic void TerminalStop(int); 9431343Sbrianstatic const char *ex_desc(int); 9530715Sbrian 9636285Sbrianstatic struct bundle *SignalBundle; 9736285Sbrianstatic struct prompt *SignalPrompt; 986059Samurai 9910528Samuraivoid 10036285SbrianCleanup(int excode) 1016059Samurai{ 10236285Sbrian SignalBundle->CleaningUp = 1; 10338008Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1046059Samurai} 1056059Samurai 1066059Samuraivoid 10736285SbrianAbortProgram(int excode) 1086059Samurai{ 10936285Sbrian server_Close(SignalBundle); 11036285Sbrian log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 11137007Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 11236285Sbrian bundle_Destroy(SignalBundle); 11336285Sbrian log_Close(); 1146059Samurai exit(excode); 1156059Samurai} 1166059Samurai 1176059Samuraistatic void 11828679SbrianCloseConnection(int signo) 1196059Samurai{ 12026858Sbrian /* NOTE, these are manual, we've done a setsid() */ 12136285Sbrian sig_signal(SIGINT, SIG_IGN); 12236285Sbrian log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 12337018Sbrian bundle_Down(SignalBundle, CLOSE_STAYDOWN); 12436285Sbrian sig_signal(SIGINT, CloseConnection); 1256059Samurai} 1266059Samurai 1276059Samuraistatic void 12828679SbrianCloseSession(int signo) 1296059Samurai{ 13036285Sbrian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 13128679Sbrian Cleanup(EX_TERM); 1326059Samurai} 1336059Samurai 13436285Sbrianstatic pid_t BGPid = 0; 13536285Sbrian 13610528Samuraistatic void 13736285SbrianKillChild(int signo) 13810528Samurai{ 13947119Sbrian signal(signo, SIG_IGN); 14036285Sbrian log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 14136285Sbrian kill(BGPid, SIGINT); 14210528Samurai} 14310528Samurai 14410528Samuraistatic void 14536285SbrianTerminalCont(int signo) 14610528Samurai{ 14736285Sbrian signal(SIGCONT, SIG_DFL); 14836285Sbrian prompt_Continue(SignalPrompt); 14910528Samurai} 15010528Samurai 15126940Sbrianstatic void 15236285SbrianTerminalStop(int signo) 15326940Sbrian{ 15436285Sbrian prompt_Suspend(SignalPrompt); 15536285Sbrian signal(SIGCONT, TerminalCont); 15636285Sbrian raise(SIGSTOP); 15726940Sbrian} 15826940Sbrian 15931081Sbrianstatic void 16031081SbrianBringDownServer(int signo) 16131081Sbrian{ 16236285Sbrian /* Drops all child prompts too ! */ 16336285Sbrian server_Close(SignalBundle); 16431081Sbrian} 16531081Sbrian 16631343Sbrianstatic const char * 16725908Sbrianex_desc(int ex) 16825908Sbrian{ 16937010Sbrian static char num[12]; /* Used immediately if returned */ 17031343Sbrian static const char *desc[] = { 17131343Sbrian "normal", "start", "sock", "modem", "dial", "dead", "done", 17231343Sbrian "reboot", "errdead", "hangup", "term", "nodial", "nologin" 17331343Sbrian }; 17410528Samurai 17531962Sbrian if (ex >= 0 && ex < sizeof desc / sizeof *desc) 17625908Sbrian return desc[ex]; 17725908Sbrian snprintf(num, sizeof num, "%d", ex); 17825908Sbrian return num; 17925908Sbrian} 18025908Sbrian 18130715Sbrianstatic void 18231343SbrianUsage(void) 1836059Samurai{ 18420120Snate fprintf(stderr, 18550059Sbrian "Usage: ppp [-auto | -foreground | -background | -direct | -dedicated | -ddial | -interactive]" 18631343Sbrian#ifndef NOALIAS 18750059Sbrian " [-nat]" 18831343Sbrian#endif 18952396Sbrian " [-quiet] [-unit N] [system ...]\n"); 1906059Samurai exit(EX_START); 1916059Samurai} 1926059Samurai 19352396Sbrianstruct switches { 19452396Sbrian unsigned nat : 1; 19552396Sbrian unsigned fg : 1; 19652396Sbrian unsigned quiet : 1; 19752396Sbrian int mode; 19852396Sbrian int unit; 19952396Sbrian}; 20052396Sbrian 20140797Sbrianstatic int 20252396SbrianProcessArgs(int argc, char **argv, struct switches *sw) 2036059Samurai{ 20440797Sbrian int optc, newmode, arg; 2056059Samurai char *cp; 2066059Samurai 20740797Sbrian optc = 0; 20852396Sbrian memset(sw, '\0', sizeof *sw); 20952396Sbrian sw->mode = PHYS_INTERACTIVE; 21052396Sbrian sw->unit = -1; 21152396Sbrian 21240797Sbrian for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 21340797Sbrian cp = argv[arg] + 1; 21436465Sbrian newmode = Nam2mode(cp); 21536465Sbrian switch (newmode) { 21636465Sbrian case PHYS_NONE: 21752396Sbrian if (strcmp(cp, "nat") == 0) { 21850059Sbrian#ifdef NONAT 21952396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 22037191Sbrian#else 22152396Sbrian sw->nat = 1; 22236285Sbrian#endif 22336465Sbrian optc--; /* this option isn't exclusive */ 22452396Sbrian } else if (strcmp(cp, "alias") == 0) { 22552396Sbrian#ifdef NONAT 22652396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 22752396Sbrian fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 22852396Sbrian#else 22952396Sbrian log_Printf(LogWARN, "%s is depricated\n", argv[arg]); 23052396Sbrian fprintf(stderr, "%s is depricated\n", argv[arg]); 23152396Sbrian sw->nat = 1; 23252396Sbrian#endif 23352396Sbrian optc--; /* this option isn't exclusive */ 23452396Sbrian } else if (strncmp(cp, "unit", 4) == 0) { 23552396Sbrian if (cp[4] == '\0') { 23652396Sbrian if (++arg == argc) { 23752396Sbrian fprintf(stderr, "-unit: Expected unit number\n"); 23852396Sbrian Usage(); 23952396Sbrian } else 24052396Sbrian sw->unit = atoi(argv[arg]); 24152396Sbrian } else 24252396Sbrian sw->unit = atoi(cp + 4); 24350059Sbrian } else if (strcmp(cp, "quiet") == 0) { 24452396Sbrian sw->quiet = 1; 24550059Sbrian optc--; /* this option isn't exclusive */ 24650059Sbrian } else if (strcmp(cp, "foreground") == 0) { 24752396Sbrian sw->mode = PHYS_BACKGROUND; /* Kinda like background mode */ 24852396Sbrian sw->fg = 1; 24936465Sbrian } else 25036465Sbrian Usage(); 25136465Sbrian break; 25236465Sbrian 25336465Sbrian case PHYS_ALL: 25436465Sbrian Usage(); 25536465Sbrian break; 25636465Sbrian 25736465Sbrian default: 25852396Sbrian sw->mode = newmode; 25936465Sbrian } 2606059Samurai } 26136465Sbrian 2626059Samurai if (optc > 1) { 26336285Sbrian fprintf(stderr, "You may specify only one mode.\n"); 2646059Samurai exit(EX_START); 2656059Samurai } 26631197Sbrian 26752396Sbrian if (sw->mode == PHYS_AUTO && arg == argc) { 26840797Sbrian fprintf(stderr, "A system must be specified in auto mode.\n"); 26936285Sbrian exit(EX_START); 27036285Sbrian } 27136285Sbrian 27240797Sbrian return arg; /* Don't SetLabel yet ! */ 2736059Samurai} 2746059Samurai 27540797Sbrianstatic void 27640797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode) 27740797Sbrian{ 27840797Sbrian const char *err; 27940797Sbrian 28040797Sbrian if ((err = system_IsValid(label, prompt, mode)) != NULL) { 28140797Sbrian fprintf(stderr, "%s: %s\n", label, err); 28240797Sbrian if (mode == PHYS_DIRECT) 28340797Sbrian log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 28440797Sbrian label, err); 28540797Sbrian log_Close(); 28640797Sbrian exit(1); 28740797Sbrian } 28840797Sbrian} 28940797Sbrian 29040797Sbrian 29126940Sbrianint 29228679Sbrianmain(int argc, char **argv) 2936059Samurai{ 29440797Sbrian char *name; 29543187Sbrian const char *lastlabel; 29652396Sbrian int nfds, label, arg; 29736285Sbrian struct bundle *bundle; 29836285Sbrian struct prompt *prompt; 29952396Sbrian struct switches sw; 30026516Sbrian 30131823Sbrian nfds = getdtablesize(); 30231823Sbrian if (nfds >= FD_SETSIZE) 30331823Sbrian /* 30431823Sbrian * If we've got loads of file descriptors, make sure they're all 30531823Sbrian * closed. If they aren't, we may end up with a seg fault when our 30631823Sbrian * `fd_set's get too big when select()ing ! 30731823Sbrian */ 30831823Sbrian while (--nfds > 2) 30931823Sbrian close(nfds); 31031823Sbrian 31130715Sbrian name = strrchr(argv[0], '/'); 31236285Sbrian log_Open(name ? name + 1 : argv[0]); 31326516Sbrian 31450059Sbrian#ifndef NONAT 31538198Sbrian PacketAliasInit(); 31638198Sbrian#endif 31752396Sbrian label = ProcessArgs(argc, argv, &sw); 31831121Sbrian 31936285Sbrian /* 32044539Sbrian * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 32144539Sbrian * output occasionally.... I must find the real reason some time. To 32244539Sbrian * display the dodgy behaviour, comment out this bit, make yourself a large 32336285Sbrian * routing table and then run ppp in interactive mode. The `show route' 32436285Sbrian * command will drop chunks of data !!! 32536285Sbrian */ 32652396Sbrian if (sw.mode == PHYS_INTERACTIVE) { 32736285Sbrian close(STDIN_FILENO); 32836285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 32936285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 33036285Sbrian return 2; 33136285Sbrian } 33236285Sbrian } 33336285Sbrian 33436285Sbrian /* Allow output for the moment (except in direct mode) */ 33552396Sbrian if (sw.mode == PHYS_DIRECT) 33636285Sbrian prompt = NULL; 33743526Sbrian else 33836285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 33936285Sbrian 34031121Sbrian ID0init(); 34131158Sbrian if (ID0realuid() != 0) { 34231158Sbrian char conf[200], *ptr; 34331158Sbrian 34431158Sbrian snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 34531158Sbrian do { 34649581Sbrian struct stat sb; 34749581Sbrian 34849581Sbrian if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 34937019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 35037019Sbrian conf); 35131158Sbrian return -1; 35231158Sbrian } 35331158Sbrian ptr = conf + strlen(conf)-2; 35431158Sbrian while (ptr > conf && *ptr != '/') 35531158Sbrian *ptr-- = '\0'; 35631158Sbrian } while (ptr >= conf); 35731158Sbrian } 35831158Sbrian 35940797Sbrian if (label < argc) 36040797Sbrian for (arg = label; arg < argc; arg++) 36152396Sbrian CheckLabel(argv[arg], prompt, sw.mode); 36240797Sbrian else 36352396Sbrian CheckLabel("default", prompt, sw.mode); 36431121Sbrian 36552396Sbrian if (!sw.quiet) 36652396Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 36743526Sbrian 36852396Sbrian if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit, 36952396Sbrian (const char **)argv)) == NULL) 37026940Sbrian return EX_START; 37143187Sbrian 37243187Sbrian /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 37343187Sbrian 37436314Sbrian if (prompt) { 37536314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 37652396Sbrian if (!sw.quiet) 37750059Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 37836314Sbrian } 37936285Sbrian SignalBundle = bundle; 38052396Sbrian bundle->NatEnabled = sw.nat; 38152396Sbrian if (sw.nat) 38240561Sbrian bundle->cfg.opt |= OPT_IFACEALIAS; 38331121Sbrian 38437008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 38536285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 38636285Sbrian 38736285Sbrian sig_signal(SIGHUP, CloseSession); 38836285Sbrian sig_signal(SIGTERM, CloseSession); 38936285Sbrian sig_signal(SIGINT, CloseConnection); 39036285Sbrian sig_signal(SIGQUIT, CloseSession); 39136285Sbrian sig_signal(SIGALRM, SIG_IGN); 39224753Sache signal(SIGPIPE, SIG_IGN); 3936059Samurai 39452396Sbrian if (sw.mode == PHYS_INTERACTIVE) 39536285Sbrian sig_signal(SIGTSTP, TerminalStop); 39636285Sbrian 39736285Sbrian sig_signal(SIGUSR2, BringDownServer); 39836285Sbrian 39943187Sbrian lastlabel = argc == 2 ? bundle->argv1 : argv[argc - 1]; 40040797Sbrian for (arg = label; arg < argc; arg++) { 40140797Sbrian /* In case we use LABEL or ``set enddisc label'' */ 40243187Sbrian bundle_SetLabel(bundle, lastlabel); 40343187Sbrian system_Select(bundle, arg == 1 ? bundle->argv1 : argv[arg], 40443187Sbrian CONFFILE, prompt, NULL); 4056059Samurai } 40626940Sbrian 40740797Sbrian if (label < argc) 40840797Sbrian /* In case the last label did a ``load'' */ 40943187Sbrian bundle_SetLabel(bundle, lastlabel); 41040797Sbrian 41152396Sbrian if (sw.mode == PHYS_AUTO && 41240797Sbrian bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 41340797Sbrian prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 41440797Sbrian "in auto mode.\n"); 41540797Sbrian AbortProgram(EX_START); 41640797Sbrian } 41740797Sbrian 41852396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 41952396Sbrian if (sw.mode != PHYS_DIRECT) { 42052396Sbrian if (!sw.fg) { 42150059Sbrian int bgpipe[2]; 42250059Sbrian pid_t bgpid; 42336285Sbrian 42452396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 42550059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 42650059Sbrian AbortProgram(EX_SOCK); 42750059Sbrian } 4286059Samurai 42950059Sbrian bgpid = fork(); 43050059Sbrian if (bgpid == -1) { 43150059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 43250059Sbrian AbortProgram(EX_SOCK); 43350059Sbrian } 43436285Sbrian 43550059Sbrian if (bgpid) { 43650059Sbrian char c = EX_NORMAL; 43711336Samurai 43852396Sbrian if (sw.mode == PHYS_BACKGROUND) { 43950059Sbrian close(bgpipe[1]); 44050059Sbrian BGPid = bgpid; 44150059Sbrian /* If we get a signal, kill the child */ 44250059Sbrian signal(SIGHUP, KillChild); 44350059Sbrian signal(SIGTERM, KillChild); 44450059Sbrian signal(SIGINT, KillChild); 44550059Sbrian signal(SIGQUIT, KillChild); 44636285Sbrian 44750059Sbrian /* Wait for our child to close its pipe before we exit */ 44850059Sbrian if (read(bgpipe[0], &c, 1) != 1) { 44950059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 45050059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 45150059Sbrian } else if (c == EX_NORMAL) { 45250059Sbrian prompt_Printf(prompt, "PPP enabled.\n"); 45350059Sbrian log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 45450059Sbrian } else { 45550059Sbrian prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 45650059Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 45750059Sbrian ex_desc((int) c)); 45850059Sbrian } 45950059Sbrian close(bgpipe[0]); 46028679Sbrian } 46150059Sbrian return c; 46252396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 46336285Sbrian close(bgpipe[0]); 46450059Sbrian bundle->notify.fd = bgpipe[1]; 46550059Sbrian } 46650059Sbrian 46750059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 46836285Sbrian } 46920813Sjkh 47050059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 47136285Sbrian prompt_Destroy(prompt, 0); 47236285Sbrian close(STDOUT_FILENO); 47336285Sbrian close(STDERR_FILENO); 47436285Sbrian close(STDIN_FILENO); 47552396Sbrian if (!sw.fg) 47650059Sbrian setsid(); 47736285Sbrian } else { 47850059Sbrian /* -direct - STDIN_FILENO gets used by physical_Open */ 47936285Sbrian prompt_TtyInit(NULL); 48036285Sbrian close(STDOUT_FILENO); 48136285Sbrian close(STDERR_FILENO); 48226686Sbrian } 4836059Samurai } else { 48450059Sbrian /* -interactive */ 48532129Sbrian close(STDERR_FILENO); 48636285Sbrian prompt_TtyInit(prompt); 48736285Sbrian prompt_TtyCommandMode(prompt); 48836285Sbrian prompt_Required(prompt); 4896059Samurai } 49029696Sbrian 49152396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 49236431Sbrian DoLoop(bundle); 49336285Sbrian AbortProgram(EX_NORMAL); 4946059Samurai 49536285Sbrian return EX_NORMAL; 4966059Samurai} 4976059Samurai 4986059Samuraistatic void 49936431SbrianDoLoop(struct bundle *bundle) 5006059Samurai{ 5016059Samurai fd_set rfds, wfds, efds; 50237141Sbrian int i, nfds, nothing_done; 50337141Sbrian struct probe probe; 5046059Samurai 50537141Sbrian probe_Init(&probe); 50637141Sbrian 50736285Sbrian do { 50823598Sache nfds = 0; 50928679Sbrian FD_ZERO(&rfds); 51028679Sbrian FD_ZERO(&wfds); 51128679Sbrian FD_ZERO(&efds); 5127001Samurai 51336314Sbrian /* All our datalinks, the tun device and the MP socket */ 51436285Sbrian descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 51525067Sbrian 51636314Sbrian /* All our prompts and the diagnostic socket */ 51736314Sbrian descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 51836314Sbrian 51936285Sbrian if (bundle_IsDead(bundle)) 52036285Sbrian /* Don't select - we'll be here forever */ 52136285Sbrian break; 52226551Sbrian 52345126Sbrian /* 52445126Sbrian * It's possible that we've had a signal since we last checked. If 52545126Sbrian * we don't check again before calling select(), we may end up stuck 52645126Sbrian * after having missed the event.... sig_Handle() tries to be as 52745126Sbrian * quick as possible if nothing is likely to have happened. 52845126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 52945126Sbrian * which will happen with a misconfigured device. 53045126Sbrian */ 53145126Sbrian if (sig_Handle()) 53245126Sbrian continue; 53345126Sbrian 53436285Sbrian i = select(nfds, &rfds, &wfds, &efds, NULL); 53526696Sbrian 53636345Sbrian if (i < 0 && errno != EINTR) { 53736285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 53836285Sbrian if (log_IsKept(LogTIMER)) { 53936285Sbrian struct timeval t; 54036285Sbrian 54136285Sbrian for (i = 0; i <= nfds; i++) { 54236285Sbrian if (FD_ISSET(i, &rfds)) { 54336285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 54436285Sbrian FD_CLR(i, &rfds); 54536285Sbrian t.tv_sec = t.tv_usec = 0; 54636285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 54736285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 54836285Sbrian break; 54936285Sbrian } 55036285Sbrian } 55136285Sbrian if (FD_ISSET(i, &wfds)) { 55236285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 55336285Sbrian FD_CLR(i, &wfds); 55436285Sbrian t.tv_sec = t.tv_usec = 0; 55536285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 55636285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 55736285Sbrian break; 55836285Sbrian } 55936285Sbrian } 56036285Sbrian if (FD_ISSET(i, &efds)) { 56136285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 56236285Sbrian FD_CLR(i, &efds); 56336285Sbrian t.tv_sec = t.tv_usec = 0; 56436285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 56536285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 56636285Sbrian break; 56736285Sbrian } 56836285Sbrian } 56936285Sbrian } 57028679Sbrian } 57128679Sbrian break; 5728857Srgrimes } 5736059Samurai 57443693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 57543693Sbrian 57636345Sbrian sig_Handle(); 57736345Sbrian 57836345Sbrian if (i <= 0) 57936345Sbrian continue; 58036345Sbrian 58136285Sbrian for (i = 0; i <= nfds; i++) 58236285Sbrian if (FD_ISSET(i, &efds)) { 58341654Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 58441654Sbrian /* We deal gracefully with link descriptor exceptions */ 58541654Sbrian if (!bundle_Exception(bundle, i)) { 58641654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 58741654Sbrian break; 58841654Sbrian } 5896059Samurai } 59028679Sbrian 59136285Sbrian if (i <= nfds) 59236285Sbrian break; 59328536Sbrian 59437141Sbrian nothing_done = 1; 59537141Sbrian 59637141Sbrian if (descriptor_IsSet(&server.desc, &rfds)) { 59736285Sbrian descriptor_Read(&server.desc, bundle, &rfds); 59837141Sbrian nothing_done = 0; 59937141Sbrian } 60032039Sbrian 60137141Sbrian if (descriptor_IsSet(&bundle->desc, &rfds)) { 60237141Sbrian descriptor_Read(&bundle->desc, bundle, &rfds); 60337141Sbrian nothing_done = 0; 60437141Sbrian } 60537141Sbrian 60636285Sbrian if (descriptor_IsSet(&bundle->desc, &wfds)) 60737141Sbrian if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { 60837141Sbrian /* 60937141Sbrian * This is disasterous. The OS has told us that something is 61037141Sbrian * writable, and all our write()s have failed. Rather than 61137141Sbrian * going back immediately to do our UpdateSet()s and select(), 61237141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 61337141Sbrian */ 61437141Sbrian struct timeval t; 61536285Sbrian 61637141Sbrian t.tv_sec = 0; 61737141Sbrian t.tv_usec = 100000; 61837141Sbrian select(0, NULL, NULL, NULL, &t); 61937141Sbrian } 62036285Sbrian } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); 62136285Sbrian 62236285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6236059Samurai} 624