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