main.c revision 58038
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 58038 2000-03-14 01:47:07Z 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> 3058032Sbrian#include <sys/socket.h> 3158032Sbrian#include <net/route.h> 3230715Sbrian 3330715Sbrian#include <errno.h> 346059Samurai#include <fcntl.h> 3511336Samurai#include <paths.h> 3630715Sbrian#include <signal.h> 3730715Sbrian#include <stdio.h> 3852396Sbrian#include <stdlib.h> 3930715Sbrian#include <string.h> 406059Samurai#include <sys/time.h> 416059Samurai#include <termios.h> 4218786Sjkh#include <unistd.h> 4349581Sbrian#include <sys/stat.h> 4430715Sbrian 4550059Sbrian#ifndef NONAT 4658037Sbrian#ifdef LOCALNAT 4758037Sbrian#include "alias.h" 4858037Sbrian#else 4946086Sbrian#include <alias.h> 5039395Sbrian#endif 5139395Sbrian#endif 5258037Sbrian 5346686Sbrian#include "layer.h" 5437141Sbrian#include "probe.h" 5530715Sbrian#include "mbuf.h" 5630715Sbrian#include "log.h" 5730715Sbrian#include "defs.h" 5831061Sbrian#include "id.h" 5930715Sbrian#include "timer.h" 6030715Sbrian#include "fsm.h" 6136285Sbrian#include "lqr.h" 626059Samurai#include "hdlc.h" 6331514Sbrian#include "lcp.h" 6413389Sphk#include "ccp.h" 6536285Sbrian#include "iplist.h" 6636285Sbrian#include "throughput.h" 6736285Sbrian#include "slcompress.h" 686059Samurai#include "ipcp.h" 6936285Sbrian#include "filter.h" 7036285Sbrian#include "descriptor.h" 7136285Sbrian#include "link.h" 7236285Sbrian#include "mp.h" 7343313Sbrian#ifndef NORADIUS 7443313Sbrian#include "radius.h" 7543313Sbrian#endif 7636285Sbrian#include "bundle.h" 776735Samurai#include "auth.h" 7813389Sphk#include "systems.h" 7923840Sbrian#include "sig.h" 8030715Sbrian#include "main.h" 8136285Sbrian#include "server.h" 8236285Sbrian#include "prompt.h" 8336285Sbrian#include "chat.h" 8436285Sbrian#include "chap.h" 8538174Sbrian#include "cbcp.h" 8636285Sbrian#include "datalink.h" 8740561Sbrian#include "iface.h" 886059Samurai 896735Samurai#ifndef O_NONBLOCK 906735Samurai#ifdef O_NDELAY 916735Samurai#define O_NONBLOCK O_NDELAY 926735Samurai#endif 936735Samurai#endif 946735Samurai 9536431Sbrianstatic void DoLoop(struct bundle *); 9630715Sbrianstatic void TerminalStop(int); 9731343Sbrianstatic const char *ex_desc(int); 9830715Sbrian 9936285Sbrianstatic struct bundle *SignalBundle; 10036285Sbrianstatic struct prompt *SignalPrompt; 1016059Samurai 10210528Samuraivoid 10336285SbrianCleanup(int excode) 1046059Samurai{ 10536285Sbrian SignalBundle->CleaningUp = 1; 10638008Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1076059Samurai} 1086059Samurai 1096059Samuraivoid 11036285SbrianAbortProgram(int excode) 1116059Samurai{ 11236285Sbrian server_Close(SignalBundle); 11336285Sbrian log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 11437007Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 11536285Sbrian bundle_Destroy(SignalBundle); 11636285Sbrian log_Close(); 1176059Samurai exit(excode); 1186059Samurai} 1196059Samurai 1206059Samuraistatic void 12128679SbrianCloseConnection(int signo) 1226059Samurai{ 12326858Sbrian /* NOTE, these are manual, we've done a setsid() */ 12436285Sbrian sig_signal(SIGINT, SIG_IGN); 12536285Sbrian log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 12637018Sbrian bundle_Down(SignalBundle, CLOSE_STAYDOWN); 12736285Sbrian sig_signal(SIGINT, CloseConnection); 1286059Samurai} 1296059Samurai 1306059Samuraistatic void 13128679SbrianCloseSession(int signo) 1326059Samurai{ 13336285Sbrian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 13428679Sbrian Cleanup(EX_TERM); 1356059Samurai} 1366059Samurai 13736285Sbrianstatic pid_t BGPid = 0; 13836285Sbrian 13910528Samuraistatic void 14036285SbrianKillChild(int signo) 14110528Samurai{ 14247119Sbrian signal(signo, SIG_IGN); 14336285Sbrian log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 14436285Sbrian kill(BGPid, SIGINT); 14510528Samurai} 14610528Samurai 14710528Samuraistatic void 14836285SbrianTerminalCont(int signo) 14910528Samurai{ 15036285Sbrian signal(SIGCONT, SIG_DFL); 15136285Sbrian prompt_Continue(SignalPrompt); 15210528Samurai} 15310528Samurai 15426940Sbrianstatic void 15536285SbrianTerminalStop(int signo) 15626940Sbrian{ 15736285Sbrian prompt_Suspend(SignalPrompt); 15836285Sbrian signal(SIGCONT, TerminalCont); 15936285Sbrian raise(SIGSTOP); 16026940Sbrian} 16126940Sbrian 16231081Sbrianstatic void 16331081SbrianBringDownServer(int signo) 16431081Sbrian{ 16536285Sbrian /* Drops all child prompts too ! */ 16636285Sbrian server_Close(SignalBundle); 16731081Sbrian} 16831081Sbrian 16931343Sbrianstatic const char * 17025908Sbrianex_desc(int ex) 17125908Sbrian{ 17237010Sbrian static char num[12]; /* Used immediately if returned */ 17355146Sbrian static const char * const desc[] = { 17431343Sbrian "normal", "start", "sock", "modem", "dial", "dead", "done", 17531343Sbrian "reboot", "errdead", "hangup", "term", "nodial", "nologin" 17631343Sbrian }; 17710528Samurai 17831962Sbrian if (ex >= 0 && ex < sizeof desc / sizeof *desc) 17925908Sbrian return desc[ex]; 18025908Sbrian snprintf(num, sizeof num, "%d", ex); 18125908Sbrian return num; 18225908Sbrian} 18325908Sbrian 18430715Sbrianstatic void 18531343SbrianUsage(void) 1866059Samurai{ 18720120Snate fprintf(stderr, 18850059Sbrian "Usage: ppp [-auto | -foreground | -background | -direct | -dedicated | -ddial | -interactive]" 18931343Sbrian#ifndef NOALIAS 19050059Sbrian " [-nat]" 19131343Sbrian#endif 19252396Sbrian " [-quiet] [-unit N] [system ...]\n"); 1936059Samurai exit(EX_START); 1946059Samurai} 1956059Samurai 19652396Sbrianstruct switches { 19752396Sbrian unsigned nat : 1; 19852396Sbrian unsigned fg : 1; 19952396Sbrian unsigned quiet : 1; 20052396Sbrian int mode; 20152396Sbrian int unit; 20252396Sbrian}; 20352396Sbrian 20440797Sbrianstatic int 20552396SbrianProcessArgs(int argc, char **argv, struct switches *sw) 2066059Samurai{ 20740797Sbrian int optc, newmode, arg; 2086059Samurai char *cp; 2096059Samurai 21040797Sbrian optc = 0; 21152396Sbrian memset(sw, '\0', sizeof *sw); 21252396Sbrian sw->mode = PHYS_INTERACTIVE; 21352396Sbrian sw->unit = -1; 21452396Sbrian 21540797Sbrian for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 21640797Sbrian cp = argv[arg] + 1; 21736465Sbrian newmode = Nam2mode(cp); 21836465Sbrian switch (newmode) { 21936465Sbrian case PHYS_NONE: 22052396Sbrian if (strcmp(cp, "nat") == 0) { 22150059Sbrian#ifdef NONAT 22252396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 22337191Sbrian#else 22452396Sbrian sw->nat = 1; 22536285Sbrian#endif 22636465Sbrian optc--; /* this option isn't exclusive */ 22752396Sbrian } else if (strcmp(cp, "alias") == 0) { 22852396Sbrian#ifdef NONAT 22952396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 23052396Sbrian fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 23152396Sbrian#else 23253889Sbrian log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 23353889Sbrian fprintf(stderr, "%s is deprecated\n", argv[arg]); 23452396Sbrian sw->nat = 1; 23552396Sbrian#endif 23652396Sbrian optc--; /* this option isn't exclusive */ 23752396Sbrian } else if (strncmp(cp, "unit", 4) == 0) { 23853067Sbrian optc--; /* this option isn't exclusive */ 23952396Sbrian if (cp[4] == '\0') { 24053067Sbrian optc--; /* nor is the argument */ 24152396Sbrian if (++arg == argc) { 24252396Sbrian fprintf(stderr, "-unit: Expected unit number\n"); 24352396Sbrian Usage(); 24452396Sbrian } else 24552396Sbrian sw->unit = atoi(argv[arg]); 24652396Sbrian } else 24752396Sbrian sw->unit = atoi(cp + 4); 24850059Sbrian } else if (strcmp(cp, "quiet") == 0) { 24952396Sbrian sw->quiet = 1; 25050059Sbrian optc--; /* this option isn't exclusive */ 25136465Sbrian } else 25236465Sbrian Usage(); 25336465Sbrian break; 25436465Sbrian 25536465Sbrian case PHYS_ALL: 25636465Sbrian Usage(); 25736465Sbrian break; 25836465Sbrian 25936465Sbrian default: 26052396Sbrian sw->mode = newmode; 26153830Sbrian if (newmode == PHYS_FOREGROUND) 26253830Sbrian sw->fg = 1; 26336465Sbrian } 2646059Samurai } 26536465Sbrian 2666059Samurai if (optc > 1) { 26736285Sbrian fprintf(stderr, "You may specify only one mode.\n"); 2686059Samurai exit(EX_START); 2696059Samurai } 27031197Sbrian 27152396Sbrian if (sw->mode == PHYS_AUTO && arg == argc) { 27240797Sbrian fprintf(stderr, "A system must be specified in auto mode.\n"); 27336285Sbrian exit(EX_START); 27436285Sbrian } 27536285Sbrian 27640797Sbrian return arg; /* Don't SetLabel yet ! */ 2776059Samurai} 2786059Samurai 27940797Sbrianstatic void 28040797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode) 28140797Sbrian{ 28240797Sbrian const char *err; 28340797Sbrian 28440797Sbrian if ((err = system_IsValid(label, prompt, mode)) != NULL) { 28540797Sbrian fprintf(stderr, "%s: %s\n", label, err); 28640797Sbrian if (mode == PHYS_DIRECT) 28740797Sbrian log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 28840797Sbrian label, err); 28940797Sbrian log_Close(); 29040797Sbrian exit(1); 29140797Sbrian } 29240797Sbrian} 29340797Sbrian 29440797Sbrian 29526940Sbrianint 29628679Sbrianmain(int argc, char **argv) 2976059Samurai{ 29840797Sbrian char *name; 29943187Sbrian const char *lastlabel; 30052396Sbrian int nfds, label, arg; 30136285Sbrian struct bundle *bundle; 30236285Sbrian struct prompt *prompt; 30352396Sbrian struct switches sw; 30426516Sbrian 30531823Sbrian nfds = getdtablesize(); 30631823Sbrian if (nfds >= FD_SETSIZE) 30731823Sbrian /* 30831823Sbrian * If we've got loads of file descriptors, make sure they're all 30931823Sbrian * closed. If they aren't, we may end up with a seg fault when our 31031823Sbrian * `fd_set's get too big when select()ing ! 31131823Sbrian */ 31231823Sbrian while (--nfds > 2) 31331823Sbrian close(nfds); 31431823Sbrian 31530715Sbrian name = strrchr(argv[0], '/'); 31636285Sbrian log_Open(name ? name + 1 : argv[0]); 31726516Sbrian 31850059Sbrian#ifndef NONAT 31938198Sbrian PacketAliasInit(); 32038198Sbrian#endif 32152396Sbrian label = ProcessArgs(argc, argv, &sw); 32231121Sbrian 32336285Sbrian /* 32444539Sbrian * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 32544539Sbrian * output occasionally.... I must find the real reason some time. To 32644539Sbrian * display the dodgy behaviour, comment out this bit, make yourself a large 32736285Sbrian * routing table and then run ppp in interactive mode. The `show route' 32836285Sbrian * command will drop chunks of data !!! 32936285Sbrian */ 33052396Sbrian if (sw.mode == PHYS_INTERACTIVE) { 33136285Sbrian close(STDIN_FILENO); 33236285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 33336285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 33436285Sbrian return 2; 33536285Sbrian } 33636285Sbrian } 33736285Sbrian 33836285Sbrian /* Allow output for the moment (except in direct mode) */ 33952396Sbrian if (sw.mode == PHYS_DIRECT) 34036285Sbrian prompt = NULL; 34143526Sbrian else 34236285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 34336285Sbrian 34431121Sbrian ID0init(); 34531158Sbrian if (ID0realuid() != 0) { 34631158Sbrian char conf[200], *ptr; 34731158Sbrian 34831158Sbrian snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 34931158Sbrian do { 35049581Sbrian struct stat sb; 35149581Sbrian 35249581Sbrian if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 35337019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 35437019Sbrian conf); 35531158Sbrian return -1; 35631158Sbrian } 35731158Sbrian ptr = conf + strlen(conf)-2; 35831158Sbrian while (ptr > conf && *ptr != '/') 35931158Sbrian *ptr-- = '\0'; 36031158Sbrian } while (ptr >= conf); 36131158Sbrian } 36231158Sbrian 36340797Sbrian if (label < argc) 36440797Sbrian for (arg = label; arg < argc; arg++) 36552396Sbrian CheckLabel(argv[arg], prompt, sw.mode); 36640797Sbrian else 36752396Sbrian CheckLabel("default", prompt, sw.mode); 36831121Sbrian 36952396Sbrian if (!sw.quiet) 37052396Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 37143526Sbrian 37253298Sbrian if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 37326940Sbrian return EX_START; 37443187Sbrian 37543187Sbrian /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 37643187Sbrian 37736314Sbrian if (prompt) { 37836314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 37952396Sbrian if (!sw.quiet) 38050059Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 38136314Sbrian } 38236285Sbrian SignalBundle = bundle; 38352396Sbrian bundle->NatEnabled = sw.nat; 38452396Sbrian if (sw.nat) 38540561Sbrian bundle->cfg.opt |= OPT_IFACEALIAS; 38631121Sbrian 38737008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 38836285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 38936285Sbrian 39036285Sbrian sig_signal(SIGHUP, CloseSession); 39136285Sbrian sig_signal(SIGTERM, CloseSession); 39236285Sbrian sig_signal(SIGINT, CloseConnection); 39336285Sbrian sig_signal(SIGQUIT, CloseSession); 39436285Sbrian sig_signal(SIGALRM, SIG_IGN); 39524753Sache signal(SIGPIPE, SIG_IGN); 3966059Samurai 39752396Sbrian if (sw.mode == PHYS_INTERACTIVE) 39836285Sbrian sig_signal(SIGTSTP, TerminalStop); 39936285Sbrian 40036285Sbrian sig_signal(SIGUSR2, BringDownServer); 40136285Sbrian 40253298Sbrian lastlabel = argv[argc - 1]; 40340797Sbrian for (arg = label; arg < argc; arg++) { 40440797Sbrian /* In case we use LABEL or ``set enddisc label'' */ 40543187Sbrian bundle_SetLabel(bundle, lastlabel); 40653298Sbrian system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 4076059Samurai } 40826940Sbrian 40940797Sbrian if (label < argc) 41040797Sbrian /* In case the last label did a ``load'' */ 41143187Sbrian bundle_SetLabel(bundle, lastlabel); 41240797Sbrian 41352396Sbrian if (sw.mode == PHYS_AUTO && 41440797Sbrian bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 41540797Sbrian prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 41640797Sbrian "in auto mode.\n"); 41740797Sbrian AbortProgram(EX_START); 41840797Sbrian } 41940797Sbrian 42052396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 42152396Sbrian if (sw.mode != PHYS_DIRECT) { 42252396Sbrian if (!sw.fg) { 42350059Sbrian int bgpipe[2]; 42450059Sbrian pid_t bgpid; 42536285Sbrian 42652396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 42750059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 42850059Sbrian AbortProgram(EX_SOCK); 42950059Sbrian } 4306059Samurai 43150059Sbrian bgpid = fork(); 43250059Sbrian if (bgpid == -1) { 43350059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 43450059Sbrian AbortProgram(EX_SOCK); 43550059Sbrian } 43636285Sbrian 43750059Sbrian if (bgpid) { 43850059Sbrian char c = EX_NORMAL; 43911336Samurai 44052396Sbrian if (sw.mode == PHYS_BACKGROUND) { 44150059Sbrian close(bgpipe[1]); 44250059Sbrian BGPid = bgpid; 44350059Sbrian /* If we get a signal, kill the child */ 44450059Sbrian signal(SIGHUP, KillChild); 44550059Sbrian signal(SIGTERM, KillChild); 44650059Sbrian signal(SIGINT, KillChild); 44750059Sbrian signal(SIGQUIT, KillChild); 44836285Sbrian 44950059Sbrian /* Wait for our child to close its pipe before we exit */ 45050059Sbrian if (read(bgpipe[0], &c, 1) != 1) { 45150059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 45250059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 45350059Sbrian } else if (c == EX_NORMAL) { 45450059Sbrian prompt_Printf(prompt, "PPP enabled.\n"); 45550059Sbrian log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 45650059Sbrian } else { 45750059Sbrian prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 45850059Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 45950059Sbrian ex_desc((int) c)); 46050059Sbrian } 46150059Sbrian close(bgpipe[0]); 46228679Sbrian } 46350059Sbrian return c; 46452396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 46536285Sbrian close(bgpipe[0]); 46650059Sbrian bundle->notify.fd = bgpipe[1]; 46750059Sbrian } 46850059Sbrian 46956350Sbrian bundle_ChangedPID(bundle); 47050059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 47136285Sbrian } 47220813Sjkh 47350059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 47436285Sbrian prompt_Destroy(prompt, 0); 47536285Sbrian close(STDOUT_FILENO); 47636285Sbrian close(STDERR_FILENO); 47736285Sbrian close(STDIN_FILENO); 47852396Sbrian if (!sw.fg) 47950059Sbrian setsid(); 48036285Sbrian } else { 48150059Sbrian /* -direct - STDIN_FILENO gets used by physical_Open */ 48236285Sbrian prompt_TtyInit(NULL); 48336285Sbrian close(STDOUT_FILENO); 48436285Sbrian close(STDERR_FILENO); 48526686Sbrian } 4866059Samurai } else { 48750059Sbrian /* -interactive */ 48832129Sbrian close(STDERR_FILENO); 48936285Sbrian prompt_TtyInit(prompt); 49036285Sbrian prompt_TtyCommandMode(prompt); 49136285Sbrian prompt_Required(prompt); 4926059Samurai } 49329696Sbrian 49452396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 49536431Sbrian DoLoop(bundle); 49636285Sbrian AbortProgram(EX_NORMAL); 4976059Samurai 49836285Sbrian return EX_NORMAL; 4996059Samurai} 5006059Samurai 5016059Samuraistatic void 50236431SbrianDoLoop(struct bundle *bundle) 5036059Samurai{ 5046059Samurai fd_set rfds, wfds, efds; 50537141Sbrian int i, nfds, nothing_done; 50637141Sbrian struct probe probe; 5076059Samurai 50837141Sbrian probe_Init(&probe); 50937141Sbrian 51053070Sbrian for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 51123598Sache nfds = 0; 51228679Sbrian FD_ZERO(&rfds); 51328679Sbrian FD_ZERO(&wfds); 51428679Sbrian FD_ZERO(&efds); 5157001Samurai 51636314Sbrian /* All our datalinks, the tun device and the MP socket */ 51736285Sbrian descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 51825067Sbrian 51936314Sbrian /* All our prompts and the diagnostic socket */ 52036314Sbrian descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 52136314Sbrian 52236285Sbrian if (bundle_IsDead(bundle)) 52336285Sbrian /* Don't select - we'll be here forever */ 52436285Sbrian break; 52526551Sbrian 52645126Sbrian /* 52745126Sbrian * It's possible that we've had a signal since we last checked. If 52845126Sbrian * we don't check again before calling select(), we may end up stuck 52945126Sbrian * after having missed the event.... sig_Handle() tries to be as 53045126Sbrian * quick as possible if nothing is likely to have happened. 53145126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 53245126Sbrian * which will happen with a misconfigured device. 53345126Sbrian */ 53445126Sbrian if (sig_Handle()) 53545126Sbrian continue; 53645126Sbrian 53736285Sbrian i = select(nfds, &rfds, &wfds, &efds, NULL); 53826696Sbrian 53936345Sbrian if (i < 0 && errno != EINTR) { 54036285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 54136285Sbrian if (log_IsKept(LogTIMER)) { 54236285Sbrian struct timeval t; 54336285Sbrian 54436285Sbrian for (i = 0; i <= nfds; i++) { 54536285Sbrian if (FD_ISSET(i, &rfds)) { 54636285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 54736285Sbrian FD_CLR(i, &rfds); 54836285Sbrian t.tv_sec = t.tv_usec = 0; 54936285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 55036285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 55136285Sbrian break; 55236285Sbrian } 55336285Sbrian } 55436285Sbrian if (FD_ISSET(i, &wfds)) { 55536285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 55636285Sbrian FD_CLR(i, &wfds); 55736285Sbrian t.tv_sec = t.tv_usec = 0; 55836285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 55936285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 56036285Sbrian break; 56136285Sbrian } 56236285Sbrian } 56336285Sbrian if (FD_ISSET(i, &efds)) { 56436285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 56536285Sbrian FD_CLR(i, &efds); 56636285Sbrian t.tv_sec = t.tv_usec = 0; 56736285Sbrian if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 56836285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 56936285Sbrian break; 57036285Sbrian } 57136285Sbrian } 57236285Sbrian } 57328679Sbrian } 57428679Sbrian break; 5758857Srgrimes } 5766059Samurai 57743693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 57843693Sbrian 57936345Sbrian sig_Handle(); 58036345Sbrian 58136345Sbrian if (i <= 0) 58236345Sbrian continue; 58336345Sbrian 58436285Sbrian for (i = 0; i <= nfds; i++) 58536285Sbrian if (FD_ISSET(i, &efds)) { 58658038Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 58758038Sbrian /* We deal gracefully with link descriptor exceptions */ 58841654Sbrian if (!bundle_Exception(bundle, i)) { 58941654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 59041654Sbrian break; 59141654Sbrian } 5926059Samurai } 59328679Sbrian 59436285Sbrian if (i <= nfds) 59536285Sbrian break; 59628536Sbrian 59737141Sbrian nothing_done = 1; 59837141Sbrian 59937141Sbrian if (descriptor_IsSet(&server.desc, &rfds)) { 60036285Sbrian descriptor_Read(&server.desc, bundle, &rfds); 60137141Sbrian nothing_done = 0; 60237141Sbrian } 60332039Sbrian 60437141Sbrian if (descriptor_IsSet(&bundle->desc, &rfds)) { 60537141Sbrian descriptor_Read(&bundle->desc, bundle, &rfds); 60637141Sbrian nothing_done = 0; 60737141Sbrian } 60837141Sbrian 60936285Sbrian if (descriptor_IsSet(&bundle->desc, &wfds)) 61037141Sbrian if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { 61137141Sbrian /* 61237141Sbrian * This is disasterous. The OS has told us that something is 61337141Sbrian * writable, and all our write()s have failed. Rather than 61437141Sbrian * going back immediately to do our UpdateSet()s and select(), 61537141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 61637141Sbrian */ 61737141Sbrian struct timeval t; 61836285Sbrian 61937141Sbrian t.tv_sec = 0; 62037141Sbrian t.tv_usec = 100000; 62137141Sbrian select(0, NULL, NULL, NULL, &t); 62237141Sbrian } 62353070Sbrian } 62436285Sbrian 62536285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6266059Samurai} 627