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