main.c revision 67912
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 67912 2000-10-30 00:15:29Z 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); 9730715Sbrian 9836285Sbrianstatic struct bundle *SignalBundle; 9936285Sbrianstatic struct prompt *SignalPrompt; 1006059Samurai 10110528Samuraivoid 10236285SbrianCleanup(int excode) 1036059Samurai{ 10436285Sbrian SignalBundle->CleaningUp = 1; 10538008Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1066059Samurai} 1076059Samurai 1086059Samuraivoid 10936285SbrianAbortProgram(int excode) 1106059Samurai{ 11136285Sbrian server_Close(SignalBundle); 11236285Sbrian log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 11337007Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 11436285Sbrian bundle_Destroy(SignalBundle); 11536285Sbrian log_Close(); 1166059Samurai exit(excode); 1176059Samurai} 1186059Samurai 1196059Samuraistatic void 12028679SbrianCloseConnection(int signo) 1216059Samurai{ 12226858Sbrian /* NOTE, these are manual, we've done a setsid() */ 12336285Sbrian sig_signal(SIGINT, SIG_IGN); 12436285Sbrian log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 12537018Sbrian bundle_Down(SignalBundle, CLOSE_STAYDOWN); 12636285Sbrian sig_signal(SIGINT, CloseConnection); 1276059Samurai} 1286059Samurai 1296059Samuraistatic void 13028679SbrianCloseSession(int signo) 1316059Samurai{ 13236285Sbrian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 13328679Sbrian Cleanup(EX_TERM); 1346059Samurai} 1356059Samurai 13636285Sbrianstatic pid_t BGPid = 0; 13736285Sbrian 13810528Samuraistatic void 13936285SbrianKillChild(int signo) 14010528Samurai{ 14147119Sbrian signal(signo, SIG_IGN); 14236285Sbrian log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 14336285Sbrian kill(BGPid, SIGINT); 14410528Samurai} 14510528Samurai 14610528Samuraistatic void 14736285SbrianTerminalCont(int signo) 14810528Samurai{ 14936285Sbrian signal(SIGCONT, SIG_DFL); 15036285Sbrian prompt_Continue(SignalPrompt); 15110528Samurai} 15210528Samurai 15326940Sbrianstatic void 15436285SbrianTerminalStop(int signo) 15526940Sbrian{ 15636285Sbrian prompt_Suspend(SignalPrompt); 15736285Sbrian signal(SIGCONT, TerminalCont); 15836285Sbrian raise(SIGSTOP); 15926940Sbrian} 16026940Sbrian 16131081Sbrianstatic void 16231081SbrianBringDownServer(int signo) 16331081Sbrian{ 16436285Sbrian /* Drops all child prompts too ! */ 16536285Sbrian server_Close(SignalBundle); 16631081Sbrian} 16731081Sbrian 16830715Sbrianstatic void 16931343SbrianUsage(void) 1706059Samurai{ 17167912Sbrian fprintf(stderr, "Usage: ppp [-auto | -foreground | -background | -direct |" 17267912Sbrian " -dedicated | -ddial | -interactive]" 17331343Sbrian#ifndef NOALIAS 17450059Sbrian " [-nat]" 17531343Sbrian#endif 17652396Sbrian " [-quiet] [-unit N] [system ...]\n"); 1776059Samurai exit(EX_START); 1786059Samurai} 1796059Samurai 18052396Sbrianstruct switches { 18152396Sbrian unsigned nat : 1; 18252396Sbrian unsigned fg : 1; 18352396Sbrian unsigned quiet : 1; 18452396Sbrian int mode; 18552396Sbrian int unit; 18652396Sbrian}; 18752396Sbrian 18840797Sbrianstatic int 18952396SbrianProcessArgs(int argc, char **argv, struct switches *sw) 1906059Samurai{ 19140797Sbrian int optc, newmode, arg; 1926059Samurai char *cp; 1936059Samurai 19440797Sbrian optc = 0; 19552396Sbrian memset(sw, '\0', sizeof *sw); 19652396Sbrian sw->mode = PHYS_INTERACTIVE; 19752396Sbrian sw->unit = -1; 19852396Sbrian 19940797Sbrian for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 20040797Sbrian cp = argv[arg] + 1; 20136465Sbrian newmode = Nam2mode(cp); 20236465Sbrian switch (newmode) { 20336465Sbrian case PHYS_NONE: 20452396Sbrian if (strcmp(cp, "nat") == 0) { 20550059Sbrian#ifdef NONAT 20652396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 20737191Sbrian#else 20852396Sbrian sw->nat = 1; 20936285Sbrian#endif 21036465Sbrian optc--; /* this option isn't exclusive */ 21152396Sbrian } else if (strcmp(cp, "alias") == 0) { 21252396Sbrian#ifdef NONAT 21352396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 21452396Sbrian fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 21552396Sbrian#else 21653889Sbrian log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 21753889Sbrian fprintf(stderr, "%s is deprecated\n", argv[arg]); 21852396Sbrian sw->nat = 1; 21952396Sbrian#endif 22052396Sbrian optc--; /* this option isn't exclusive */ 22152396Sbrian } else if (strncmp(cp, "unit", 4) == 0) { 22253067Sbrian optc--; /* this option isn't exclusive */ 22352396Sbrian if (cp[4] == '\0') { 22453067Sbrian optc--; /* nor is the argument */ 22552396Sbrian if (++arg == argc) { 22652396Sbrian fprintf(stderr, "-unit: Expected unit number\n"); 22752396Sbrian Usage(); 22852396Sbrian } else 22952396Sbrian sw->unit = atoi(argv[arg]); 23052396Sbrian } else 23152396Sbrian sw->unit = atoi(cp + 4); 23250059Sbrian } else if (strcmp(cp, "quiet") == 0) { 23352396Sbrian sw->quiet = 1; 23450059Sbrian optc--; /* this option isn't exclusive */ 23536465Sbrian } else 23636465Sbrian Usage(); 23736465Sbrian break; 23836465Sbrian 23936465Sbrian case PHYS_ALL: 24036465Sbrian Usage(); 24136465Sbrian break; 24236465Sbrian 24336465Sbrian default: 24452396Sbrian sw->mode = newmode; 24553830Sbrian if (newmode == PHYS_FOREGROUND) 24653830Sbrian sw->fg = 1; 24736465Sbrian } 2486059Samurai } 24936465Sbrian 2506059Samurai if (optc > 1) { 25136285Sbrian fprintf(stderr, "You may specify only one mode.\n"); 2526059Samurai exit(EX_START); 2536059Samurai } 25431197Sbrian 25552396Sbrian if (sw->mode == PHYS_AUTO && arg == argc) { 25640797Sbrian fprintf(stderr, "A system must be specified in auto mode.\n"); 25736285Sbrian exit(EX_START); 25836285Sbrian } 25936285Sbrian 26040797Sbrian return arg; /* Don't SetLabel yet ! */ 2616059Samurai} 2626059Samurai 26340797Sbrianstatic void 26440797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode) 26540797Sbrian{ 26640797Sbrian const char *err; 26740797Sbrian 26840797Sbrian if ((err = system_IsValid(label, prompt, mode)) != NULL) { 26940797Sbrian fprintf(stderr, "%s: %s\n", label, err); 27040797Sbrian if (mode == PHYS_DIRECT) 27140797Sbrian log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 27240797Sbrian label, err); 27340797Sbrian log_Close(); 27440797Sbrian exit(1); 27540797Sbrian } 27640797Sbrian} 27740797Sbrian 27840797Sbrian 27926940Sbrianint 28028679Sbrianmain(int argc, char **argv) 2816059Samurai{ 28240797Sbrian char *name; 28343187Sbrian const char *lastlabel; 28466898Sbrian int label, arg; 28536285Sbrian struct bundle *bundle; 28636285Sbrian struct prompt *prompt; 28752396Sbrian struct switches sw; 28826516Sbrian 28930715Sbrian name = strrchr(argv[0], '/'); 29036285Sbrian log_Open(name ? name + 1 : argv[0]); 29126516Sbrian 29250059Sbrian#ifndef NONAT 29338198Sbrian PacketAliasInit(); 29438198Sbrian#endif 29552396Sbrian label = ProcessArgs(argc, argv, &sw); 29631121Sbrian 29736285Sbrian /* 29844539Sbrian * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 29944539Sbrian * output occasionally.... I must find the real reason some time. To 30044539Sbrian * display the dodgy behaviour, comment out this bit, make yourself a large 30136285Sbrian * routing table and then run ppp in interactive mode. The `show route' 30236285Sbrian * command will drop chunks of data !!! 30336285Sbrian */ 30452396Sbrian if (sw.mode == PHYS_INTERACTIVE) { 30536285Sbrian close(STDIN_FILENO); 30636285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 30736285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 30836285Sbrian return 2; 30936285Sbrian } 31036285Sbrian } 31136285Sbrian 31236285Sbrian /* Allow output for the moment (except in direct mode) */ 31352396Sbrian if (sw.mode == PHYS_DIRECT) 31436285Sbrian prompt = NULL; 31543526Sbrian else 31636285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 31736285Sbrian 31831121Sbrian ID0init(); 31931158Sbrian if (ID0realuid() != 0) { 32031158Sbrian char conf[200], *ptr; 32131158Sbrian 32231158Sbrian snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 32331158Sbrian do { 32449581Sbrian struct stat sb; 32549581Sbrian 32649581Sbrian if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 32737019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 32837019Sbrian conf); 32931158Sbrian return -1; 33031158Sbrian } 33131158Sbrian ptr = conf + strlen(conf)-2; 33231158Sbrian while (ptr > conf && *ptr != '/') 33331158Sbrian *ptr-- = '\0'; 33431158Sbrian } while (ptr >= conf); 33531158Sbrian } 33631158Sbrian 33740797Sbrian if (label < argc) 33840797Sbrian for (arg = label; arg < argc; arg++) 33952396Sbrian CheckLabel(argv[arg], prompt, sw.mode); 34040797Sbrian else 34152396Sbrian CheckLabel("default", prompt, sw.mode); 34231121Sbrian 34352396Sbrian if (!sw.quiet) 34452396Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 34543526Sbrian 34653298Sbrian if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 34726940Sbrian return EX_START; 34843187Sbrian 34943187Sbrian /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 35043187Sbrian 35136314Sbrian if (prompt) { 35236314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 35352396Sbrian if (!sw.quiet) 35450059Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 35536314Sbrian } 35636285Sbrian SignalBundle = bundle; 35752396Sbrian bundle->NatEnabled = sw.nat; 35852396Sbrian if (sw.nat) 35940561Sbrian bundle->cfg.opt |= OPT_IFACEALIAS; 36031121Sbrian 36137008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 36236285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 36336285Sbrian 36436285Sbrian sig_signal(SIGHUP, CloseSession); 36536285Sbrian sig_signal(SIGTERM, CloseSession); 36636285Sbrian sig_signal(SIGINT, CloseConnection); 36736285Sbrian sig_signal(SIGQUIT, CloseSession); 36836285Sbrian sig_signal(SIGALRM, SIG_IGN); 36924753Sache signal(SIGPIPE, SIG_IGN); 3706059Samurai 37152396Sbrian if (sw.mode == PHYS_INTERACTIVE) 37236285Sbrian sig_signal(SIGTSTP, TerminalStop); 37336285Sbrian 37436285Sbrian sig_signal(SIGUSR2, BringDownServer); 37536285Sbrian 37653298Sbrian lastlabel = argv[argc - 1]; 37740797Sbrian for (arg = label; arg < argc; arg++) { 37840797Sbrian /* In case we use LABEL or ``set enddisc label'' */ 37943187Sbrian bundle_SetLabel(bundle, lastlabel); 38053298Sbrian system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 3816059Samurai } 38226940Sbrian 38340797Sbrian if (label < argc) 38440797Sbrian /* In case the last label did a ``load'' */ 38543187Sbrian bundle_SetLabel(bundle, lastlabel); 38640797Sbrian 38752396Sbrian if (sw.mode == PHYS_AUTO && 38840797Sbrian bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 38940797Sbrian prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 39040797Sbrian "in auto mode.\n"); 39140797Sbrian AbortProgram(EX_START); 39240797Sbrian } 39340797Sbrian 39452396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 39552396Sbrian if (sw.mode != PHYS_DIRECT) { 39652396Sbrian if (!sw.fg) { 39750059Sbrian int bgpipe[2]; 39850059Sbrian pid_t bgpid; 39936285Sbrian 40052396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 40150059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 40250059Sbrian AbortProgram(EX_SOCK); 40350059Sbrian } 4046059Samurai 40550059Sbrian bgpid = fork(); 40650059Sbrian if (bgpid == -1) { 40750059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 40850059Sbrian AbortProgram(EX_SOCK); 40950059Sbrian } 41036285Sbrian 41150059Sbrian if (bgpid) { 41250059Sbrian char c = EX_NORMAL; 41359084Sbrian int ret; 41411336Samurai 41552396Sbrian if (sw.mode == PHYS_BACKGROUND) { 41650059Sbrian close(bgpipe[1]); 41750059Sbrian BGPid = bgpid; 41850059Sbrian /* If we get a signal, kill the child */ 41950059Sbrian signal(SIGHUP, KillChild); 42050059Sbrian signal(SIGTERM, KillChild); 42150059Sbrian signal(SIGINT, KillChild); 42250059Sbrian signal(SIGQUIT, KillChild); 42336285Sbrian 42450059Sbrian /* Wait for our child to close its pipe before we exit */ 42559084Sbrian while ((ret = read(bgpipe[0], &c, 1)) == 1) { 42659084Sbrian switch (c) { 42759084Sbrian case EX_NORMAL: 42859084Sbrian prompt_Printf(prompt, "PPP enabled\n"); 42959084Sbrian log_Printf(LogPHASE, "Parent: PPP enabled\n"); 43059104Sbrian break; 43159084Sbrian case EX_REDIAL: 43259084Sbrian if (!sw.quiet) 43359084Sbrian prompt_Printf(prompt, "Attempting redial\n"); 43459084Sbrian continue; 43559084Sbrian case EX_RECONNECT: 43659084Sbrian if (!sw.quiet) 43759084Sbrian prompt_Printf(prompt, "Attempting reconnect\n"); 43859084Sbrian continue; 43959084Sbrian default: 44059084Sbrian prompt_Printf(prompt, "Child failed (%s)\n", 44159084Sbrian ex_desc((int)c)); 44259084Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 44359084Sbrian ex_desc((int) c)); 44459084Sbrian } 44559084Sbrian break; 44659084Sbrian } 44759084Sbrian if (ret != 1) { 44850059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 44950059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 45050059Sbrian } 45150059Sbrian close(bgpipe[0]); 45228679Sbrian } 45350059Sbrian return c; 45452396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 45536285Sbrian close(bgpipe[0]); 45650059Sbrian bundle->notify.fd = bgpipe[1]; 45750059Sbrian } 45850059Sbrian 45956350Sbrian bundle_ChangedPID(bundle); 46050059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 46136285Sbrian } 46220813Sjkh 46350059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 46436285Sbrian prompt_Destroy(prompt, 0); 46536285Sbrian close(STDOUT_FILENO); 46636285Sbrian close(STDERR_FILENO); 46736285Sbrian close(STDIN_FILENO); 46852396Sbrian if (!sw.fg) 46950059Sbrian setsid(); 47036285Sbrian } else { 47150059Sbrian /* -direct - STDIN_FILENO gets used by physical_Open */ 47236285Sbrian prompt_TtyInit(NULL); 47336285Sbrian close(STDOUT_FILENO); 47436285Sbrian close(STDERR_FILENO); 47526686Sbrian } 4766059Samurai } else { 47750059Sbrian /* -interactive */ 47832129Sbrian close(STDERR_FILENO); 47936285Sbrian prompt_TtyInit(prompt); 48036285Sbrian prompt_TtyCommandMode(prompt); 48136285Sbrian prompt_Required(prompt); 4826059Samurai } 48329696Sbrian 48452396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 48536431Sbrian DoLoop(bundle); 48636285Sbrian AbortProgram(EX_NORMAL); 4876059Samurai 48836285Sbrian return EX_NORMAL; 4896059Samurai} 4906059Samurai 4916059Samuraistatic void 49236431SbrianDoLoop(struct bundle *bundle) 4936059Samurai{ 49466898Sbrian fd_set *rfds, *wfds, *efds; 49537141Sbrian int i, nfds, nothing_done; 49637141Sbrian struct probe probe; 4976059Samurai 49837141Sbrian probe_Init(&probe); 49937141Sbrian 50066898Sbrian if ((rfds = mkfdset()) == NULL) { 50166898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 50266898Sbrian return; 50366898Sbrian } 50466898Sbrian 50566898Sbrian if ((wfds = mkfdset()) == NULL) { 50666898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 50766898Sbrian free(rfds); 50866898Sbrian return; 50966898Sbrian } 51066898Sbrian 51166898Sbrian if ((efds = mkfdset()) == NULL) { 51266898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 51366898Sbrian free(rfds); 51466898Sbrian free(wfds); 51566898Sbrian return; 51666898Sbrian } 51766898Sbrian 51853070Sbrian for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 51923598Sache nfds = 0; 52066898Sbrian zerofdset(rfds); 52166898Sbrian zerofdset(wfds); 52266898Sbrian zerofdset(efds); 5237001Samurai 52436314Sbrian /* All our datalinks, the tun device and the MP socket */ 52566898Sbrian descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 52625067Sbrian 52736314Sbrian /* All our prompts and the diagnostic socket */ 52866898Sbrian descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 52936314Sbrian 53058453Sbrian bundle_CleanDatalinks(bundle); 53136285Sbrian if (bundle_IsDead(bundle)) 53236285Sbrian /* Don't select - we'll be here forever */ 53336285Sbrian break; 53426551Sbrian 53545126Sbrian /* 53645126Sbrian * It's possible that we've had a signal since we last checked. If 53745126Sbrian * we don't check again before calling select(), we may end up stuck 53845126Sbrian * after having missed the event.... sig_Handle() tries to be as 53945126Sbrian * quick as possible if nothing is likely to have happened. 54045126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 54145126Sbrian * which will happen with a misconfigured device. 54245126Sbrian */ 54345126Sbrian if (sig_Handle()) 54445126Sbrian continue; 54545126Sbrian 54666898Sbrian i = select(nfds, rfds, wfds, efds, NULL); 54726696Sbrian 54836345Sbrian if (i < 0 && errno != EINTR) { 54936285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 55036285Sbrian if (log_IsKept(LogTIMER)) { 55136285Sbrian struct timeval t; 55236285Sbrian 55336285Sbrian for (i = 0; i <= nfds; i++) { 55466898Sbrian if (FD_ISSET(i, rfds)) { 55536285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 55666898Sbrian FD_CLR(i, rfds); 55736285Sbrian t.tv_sec = t.tv_usec = 0; 55866898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 55936285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 56036285Sbrian break; 56136285Sbrian } 56236285Sbrian } 56366898Sbrian if (FD_ISSET(i, wfds)) { 56436285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 56566898Sbrian FD_CLR(i, wfds); 56636285Sbrian t.tv_sec = t.tv_usec = 0; 56766898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 56836285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 56936285Sbrian break; 57036285Sbrian } 57136285Sbrian } 57266898Sbrian if (FD_ISSET(i, efds)) { 57336285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 57466898Sbrian FD_CLR(i, efds); 57536285Sbrian t.tv_sec = t.tv_usec = 0; 57666898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 57736285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 57836285Sbrian break; 57936285Sbrian } 58036285Sbrian } 58136285Sbrian } 58228679Sbrian } 58328679Sbrian break; 5848857Srgrimes } 5856059Samurai 58643693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 58743693Sbrian 58836345Sbrian sig_Handle(); 58936345Sbrian 59036345Sbrian if (i <= 0) 59136345Sbrian continue; 59236345Sbrian 59336285Sbrian for (i = 0; i <= nfds; i++) 59466898Sbrian if (FD_ISSET(i, efds)) { 59558038Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 59658038Sbrian /* We deal gracefully with link descriptor exceptions */ 59741654Sbrian if (!bundle_Exception(bundle, i)) { 59841654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 59941654Sbrian break; 60041654Sbrian } 6016059Samurai } 60228679Sbrian 60336285Sbrian if (i <= nfds) 60436285Sbrian break; 60528536Sbrian 60637141Sbrian nothing_done = 1; 60737141Sbrian 60866898Sbrian if (descriptor_IsSet(&server.desc, rfds)) { 60966898Sbrian descriptor_Read(&server.desc, bundle, rfds); 61037141Sbrian nothing_done = 0; 61137141Sbrian } 61232039Sbrian 61366898Sbrian if (descriptor_IsSet(&bundle->desc, rfds)) { 61466898Sbrian descriptor_Read(&bundle->desc, bundle, rfds); 61537141Sbrian nothing_done = 0; 61637141Sbrian } 61737141Sbrian 61866898Sbrian if (descriptor_IsSet(&bundle->desc, wfds)) 61966898Sbrian if (!descriptor_Write(&bundle->desc, bundle, wfds) && nothing_done) { 62037141Sbrian /* 62137141Sbrian * This is disasterous. The OS has told us that something is 62237141Sbrian * writable, and all our write()s have failed. Rather than 62337141Sbrian * going back immediately to do our UpdateSet()s and select(), 62437141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 62537141Sbrian */ 62637141Sbrian struct timeval t; 62736285Sbrian 62837141Sbrian t.tv_sec = 0; 62937141Sbrian t.tv_usec = 100000; 63037141Sbrian select(0, NULL, NULL, NULL, &t); 63137141Sbrian } 63253070Sbrian } 63336285Sbrian 63436285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6356059Samurai} 636