main.c revision 36709
1139823Simp/* 244165Sjulian * User Process PPP 344165Sjulian * 444165Sjulian * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 544165Sjulian * 644165Sjulian * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 744165Sjulian * 844165Sjulian * Redistribution and use in source and binary forms are permitted 944165Sjulian * provided that the above copyright notice and this paragraph are 1044165Sjulian * duplicated in all such forms and that any documentation, 1144165Sjulian * advertising materials, and other materials related to such 1244165Sjulian * distribution and use acknowledge that the software was developed 1344165Sjulian * by the Internet Initiative Japan, Inc. The name of the 1444165Sjulian * IIJ may not be used to endorse or promote products derived 1544165Sjulian * from this software without specific prior written permission. 1644165Sjulian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1744165Sjulian * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1844165Sjulian * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1944165Sjulian * 2044165Sjulian * $Id: main.c,v 1.129 1998/05/29 18:33:09 brian Exp $ 2144165Sjulian * 2244165Sjulian * TODO: 2344165Sjulian */ 2444165Sjulian 2544165Sjulian#include <sys/types.h> 2644165Sjulian#include <sys/socket.h> 2744165Sjulian#include <netinet/in.h> 2844165Sjulian#include <netinet/in_systm.h> 2944165Sjulian#include <netinet/ip.h> 3044165Sjulian#include <sys/un.h> 3144165Sjulian#include <net/if_tun.h> 3244165Sjulian 3350477Speter#include <errno.h> 3444165Sjulian#include <fcntl.h> 3544165Sjulian#include <paths.h> 3644165Sjulian#include <signal.h> 3744165Sjulian#include <stdio.h> 3844165Sjulian#include <string.h> 3944165Sjulian#include <sys/time.h> 4044165Sjulian#include <termios.h> 4144165Sjulian#include <unistd.h> 4244165Sjulian 4344165Sjulian#include "mbuf.h" 4474408Smdodd#include "log.h" 4574408Smdodd#include "defs.h" 46112285Smdodd#include "id.h" 4744165Sjulian#include "timer.h" 4844165Sjulian#include "fsm.h" 4944165Sjulian#include "lqr.h" 50112271Smdodd#include "hdlc.h" 51112271Smdodd#include "lcp.h" 5244165Sjulian#include "ccp.h" 53112271Smdodd#include "iplist.h" 5444165Sjulian#include "throughput.h" 5544165Sjulian#include "slcompress.h" 5644165Sjulian#include "ipcp.h" 5744165Sjulian#include "filter.h" 58184710Sbz#include "descriptor.h" 59112271Smdodd#include "link.h" 6044165Sjulian#include "mp.h" 6144165Sjulian#include "bundle.h" 62186119Sqingli#include "loadalias.h" 6344165Sjulian#include "auth.h" 64184710Sbz#include "systems.h" 65112271Smdodd#include "ip.h" 66112271Smdodd#include "sig.h" 67112271Smdodd#include "main.h" 6844165Sjulian#include "tun.h" 6944165Sjulian#include "server.h" 7074408Smdodd#include "prompt.h" 7144165Sjulian#include "chat.h" 7244165Sjulian#include "chap.h" 7344165Sjulian#include "datalink.h" 7444165Sjulian 7574408Smdodd#ifndef O_NONBLOCK 7674408Smdodd#ifdef O_NDELAY 7774408Smdodd#define O_NONBLOCK O_NDELAY 7844165Sjulian#endif 7974408Smdodd#endif 8074408Smdodd 8174408Smdoddstatic void DoLoop(struct bundle *); 8274408Smdoddstatic void TerminalStop(int); 8374408Smdoddstatic const char *ex_desc(int); 84163606Srwatson 85163606Srwatsonstatic struct bundle *SignalBundle; 86126907Srwatsonstatic struct prompt *SignalPrompt; 87112277Smdodd 88112277Smdoddvoid 89112273SmdoddCleanup(int excode) 90112294Smdodd{ 91112273Smdodd SignalBundle->CleaningUp = 1; 92112276Smdodd if (bundle_Phase(SignalBundle) != PHASE_DEAD) 9374408Smdodd bundle_Close(SignalBundle, NULL, 1); 94112297Smdodd} 95112297Smdodd 96112297Smdoddvoid 9744165SjulianAbortProgram(int excode) 98152296Sru{ 9944165Sjulian server_Close(SignalBundle); 100112296Smdodd log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 101111774Smdodd bundle_Close(SignalBundle, NULL, 1); 10244165Sjulian bundle_Destroy(SignalBundle); 103112296Smdodd log_Close(); 104112296Smdodd exit(excode); 10544165Sjulian} 10658313Slile 10758313Slilestatic void 108112297SmdoddCloseConnection(int signo) 109112297Smdodd{ 110112297Smdodd /* NOTE, these are manual, we've done a setsid() */ 111112297Smdodd sig_signal(SIGINT, SIG_IGN); 112112297Smdodd log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 113112297Smdodd bundle_Down(SignalBundle); 114112297Smdodd sig_signal(SIGINT, CloseConnection); 115112297Smdodd} 11644165Sjulian 11758313Slilestatic void 11844165SjulianCloseSession(int signo) 11944165Sjulian{ 12044165Sjulian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 121152315Sru Cleanup(EX_TERM); 122152315Sru} 123112297Smdodd 124112272Smdoddstatic pid_t BGPid = 0; 125112272Smdodd 126112272Smdoddstatic void 127152296SruKillChild(int signo) 128112297Smdodd{ 129112297Smdodd log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 130112297Smdodd kill(BGPid, SIGINT); 131112297Smdodd} 132112297Smdodd 13344165Sjulianstatic void 13444165SjulianTerminalCont(int signo) 13574408Smdodd{ 13674408Smdodd signal(SIGCONT, SIG_DFL); 13774408Smdodd prompt_Continue(SignalPrompt); 13874408Smdodd} 13974408Smdodd 14074408Smdoddstatic void 14174408SmdoddTerminalStop(int signo) 14274408Smdodd{ 143112274Smdodd prompt_Suspend(SignalPrompt); 14474408Smdodd signal(SIGCONT, TerminalCont); 14574408Smdodd raise(SIGSTOP); 146112274Smdodd} 14774408Smdodd 148112274Smdoddstatic void 149112274SmdoddBringDownServer(int signo) 15074408Smdodd{ 15174408Smdodd /* Drops all child prompts too ! */ 15244165Sjulian server_Close(SignalBundle); 15344165Sjulian} 15444165Sjulian 155112274Smdoddstatic const char * 156112274Smdoddex_desc(int ex) 157112274Smdodd{ 15844165Sjulian static char num[12]; 159112274Smdodd static const char *desc[] = { 160112274Smdodd "normal", "start", "sock", "modem", "dial", "dead", "done", 161112274Smdodd "reboot", "errdead", "hangup", "term", "nodial", "nologin" 162112274Smdodd }; 16344165Sjulian 16444165Sjulian if (ex >= 0 && ex < sizeof desc / sizeof *desc) 16544165Sjulian return desc[ex]; 16644165Sjulian snprintf(num, sizeof num, "%d", ex); 16744165Sjulian return num; 16844165Sjulian} 16944165Sjulian 17044165Sjulianstatic void 17184931SfjoeUsage(void) 17244165Sjulian{ 17374408Smdodd fprintf(stderr, 17474408Smdodd "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" 17574408Smdodd#ifndef NOALIAS 17674408Smdodd " [ -alias ]" 17774408Smdodd#endif 178120048Smdodd " [system]\n"); 179120048Smdodd exit(EX_START); 18074408Smdodd} 181120048Smdodd 18274408Smdoddstatic char * 183120048SmdoddProcessArgs(int argc, char **argv, int *mode) 184120048Smdodd{ 185152315Sru int optc, labelrequired, newmode; 186120048Smdodd char *cp; 187120048Smdodd 188152315Sru optc = labelrequired = 0; 189120048Smdodd *mode = PHYS_INTERACTIVE; 190120048Smdodd while (argc > 0 && **argv == '-') { 191120048Smdodd cp = *argv + 1; 192120048Smdodd newmode = Nam2mode(cp); 193120048Smdodd switch (newmode) { 194120048Smdodd case PHYS_NONE: 195120048Smdodd if (strcmp(cp, "alias") == 0) { 196120048Smdodd#ifndef NOALIAS 19774408Smdodd if (alias_Load() != 0) 19844165Sjulian#endif 19944165Sjulian log_Printf(LogWARN, "Cannot load alias library\n"); 20044165Sjulian optc--; /* this option isn't exclusive */ 20144165Sjulian } else 20244165Sjulian Usage(); 20344165Sjulian break; 204120047Smdodd 20544165Sjulian case PHYS_ALL: 20644165Sjulian Usage(); 20744165Sjulian break; 208152315Sru 20944165Sjulian case PHYS_AUTO: 21044165Sjulian case PHYS_BACKGROUND: 21144165Sjulian case PHYS_DDIAL: 21244165Sjulian labelrequired = 1; 21344165Sjulian /* fall through */ 21444165Sjulian 21544165Sjulian default: 21644165Sjulian *mode = newmode; 21758313Slile } 21844165Sjulian optc++; 21944165Sjulian argv++; 22044165Sjulian argc--; 22144165Sjulian } 22244165Sjulian 223112274Smdodd if (argc > 1) { 224112274Smdodd fprintf(stderr, "You may specify only one system label.\n"); 225112274Smdodd exit(EX_START); 22644165Sjulian } 227112274Smdodd 22844165Sjulian if (optc > 1) { 22944165Sjulian fprintf(stderr, "You may specify only one mode.\n"); 23044165Sjulian exit(EX_START); 23144165Sjulian } 23244165Sjulian 23344165Sjulian if (labelrequired && argc != 1) { 23444165Sjulian fprintf(stderr, "Destination system must be specified in" 23574408Smdodd " auto, background or ddial mode.\n"); 23674408Smdodd exit(EX_START); 23774408Smdodd } 23874408Smdodd 23974408Smdodd return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ 24044165Sjulian} 24174408Smdodd 24287914Sjlemonint 24387914Sjlemonmain(int argc, char **argv) 24474408Smdodd{ 24544627Sjulian char *name, *label; 24674408Smdodd int nfds, mode; 247186119Sqingli struct bundle *bundle; 24844165Sjulian struct prompt *prompt; 249112285Smdodd 250172930Srwatson nfds = getdtablesize(); 251112285Smdodd if (nfds >= FD_SETSIZE) 252112285Smdodd /* 253112285Smdodd * If we've got loads of file descriptors, make sure they're all 254112285Smdodd * closed. If they aren't, we may end up with a seg fault when our 255112308Smdodd * `fd_set's get too big when select()ing ! 256112308Smdodd */ 257148887Srwatson while (--nfds > 2) 258148887Srwatson close(nfds); 25944165Sjulian 26074408Smdodd name = strrchr(argv[0], '/'); 26174408Smdodd log_Open(name ? name + 1 : argv[0]); 262128636Sluigi 263128636Sluigi label = ProcessArgs(argc - 1, argv + 1, &mode); 26444627Sjulian 265186119Sqingli#ifdef __FreeBSD__ 266102291Sarchie /* 26796184Skbyanc * A FreeBSD hack to dodge a bug in the tty driver that drops output 26844627Sjulian * occasionally.... I must find the real reason some time. To display 26944627Sjulian * the dodgy behaviour, comment out this bit, make yourself a large 27058313Slile * routing table and then run ppp in interactive mode. The `show route' 27158313Slile * command will drop chunks of data !!! 272152315Sru */ 273112278Smdodd if (mode == PHYS_INTERACTIVE) { 27444627Sjulian close(STDIN_FILENO); 27558313Slile if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 27644627Sjulian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 27796184Skbyanc return 2; 27874408Smdodd } 27996184Skbyanc } 28096184Skbyanc#endif 28144627Sjulian 28244627Sjulian /* Allow output for the moment (except in direct mode) */ 28344627Sjulian if (mode == PHYS_DIRECT) 28444165Sjulian prompt = NULL; 28544165Sjulian else { 28644165Sjulian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 287186119Sqingli prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(mode)); 288128636Sluigi } 289128636Sluigi 29074408Smdodd ID0init(); 29174408Smdodd if (ID0realuid() != 0) { 292126951Smdodd char conf[200], *ptr; 293126951Smdodd 294126951Smdodd snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 295126951Smdodd do { 296126951Smdodd if (!access(conf, W_OK)) { 297126951Smdodd log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); 298126951Smdodd return -1; 299126951Smdodd } 300126951Smdodd ptr = conf + strlen(conf)-2; 301126951Smdodd while (ptr > conf && *ptr != '/') 302126951Smdodd *ptr-- = '\0'; 303126951Smdodd } while (ptr >= conf); 304126951Smdodd } 305126951Smdodd 306126951Smdodd if (!system_IsValid(label, prompt, mode)) { 307126951Smdodd fprintf(stderr, "You may not use ppp in this mode with this label\n"); 308126951Smdodd if (mode == PHYS_DIRECT) { 309126951Smdodd const char *l; 310126951Smdodd l = label ? label : "default"; 311126951Smdodd log_Printf(LogWARN, "Label %s rejected -direct connection\n", l); 312126951Smdodd } 313126951Smdodd log_Close(); 314126951Smdodd return 1; 315126951Smdodd } 316126951Smdodd 317126951Smdodd if ((bundle = bundle_Create(TUN_PREFIX, mode, (const char **)argv)) == NULL) { 318126951Smdodd log_Printf(LogWARN, "bundle_Create: %s\n", strerror(errno)); 31974408Smdodd return EX_START; 32074408Smdodd } 32174408Smdodd if (prompt) { 322186217Sqingli prompt->bundle = bundle; /* couldn't do it earlier */ 323128636Sluigi prompt_Printf(prompt, "Using interface: %s\n", bundle->ifp.Name); 324128636Sluigi } 32574408Smdodd SignalBundle = bundle; 32674408Smdodd 32774408Smdodd if (system_Select(bundle, "default", CONFFILE, prompt) < 0) 32874408Smdodd prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 32974408Smdodd 33074408Smdodd sig_signal(SIGHUP, CloseSession); 33174408Smdodd sig_signal(SIGTERM, CloseSession); 33274408Smdodd sig_signal(SIGINT, CloseConnection); 33374408Smdodd sig_signal(SIGQUIT, CloseSession); 334112278Smdodd sig_signal(SIGALRM, SIG_IGN); 33574408Smdodd signal(SIGPIPE, SIG_IGN); 336177599Sru 33774408Smdodd if (mode == PHYS_INTERACTIVE) 33874408Smdodd sig_signal(SIGTSTP, TerminalStop); 33974408Smdodd 34074408Smdodd sig_signal(SIGUSR2, BringDownServer); 34174408Smdodd 34274408Smdodd if (label) { 34374408Smdodd /* 34474408Smdodd * Set label both before and after system_Select ! 34574408Smdodd * This way, "set enddisc label" works during system_Select, and we 34674408Smdodd * also end up with the correct label if we have embedded load 34744165Sjulian * commands. 34874408Smdodd */ 34974408Smdodd bundle_SetLabel(bundle, label); 35044627Sjulian if (system_Select(bundle, label, CONFFILE, prompt) < 0) { 35144627Sjulian prompt_Printf(prompt, "Destination system (%s) not found.\n", label); 35244627Sjulian AbortProgram(EX_START); 35344627Sjulian } 35444627Sjulian bundle_SetLabel(bundle, label); 35544627Sjulian if (mode == PHYS_AUTO && 356108533Sschweikh bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 35744627Sjulian prompt_Printf(prompt, "You must \"set ifaddr\" with a peer address " 35844165Sjulian "in label %s for auto mode.\n", label); 35944627Sjulian AbortProgram(EX_START); 36044627Sjulian } 36144627Sjulian } 36274408Smdodd 363112278Smdodd if (mode != PHYS_INTERACTIVE) { 36474408Smdodd if (mode != PHYS_DIRECT) { 365112280Smdodd int bgpipe[2]; 36644627Sjulian pid_t bgpid; 36744165Sjulian 36874408Smdodd if (mode == PHYS_BACKGROUND && pipe(bgpipe)) { 36944165Sjulian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 370105598Sbrooks AbortProgram(EX_SOCK); 37144165Sjulian } 37274408Smdodd 37344165Sjulian bgpid = fork(); 37444165Sjulian if (bgpid == -1) { 375112274Smdodd log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 376112274Smdodd AbortProgram(EX_SOCK); 377112274Smdodd } 37874408Smdodd 37974408Smdodd if (bgpid) { 380111790Smdodd char c = EX_NORMAL; 38174408Smdodd 38274408Smdodd if (mode == PHYS_BACKGROUND) { 38374408Smdodd close(bgpipe[1]); 384112281Smdodd BGPid = bgpid; 38574408Smdodd /* If we get a signal, kill the child */ 386112268Smdodd signal(SIGHUP, KillChild); 387112268Smdodd signal(SIGTERM, KillChild); 388112268Smdodd signal(SIGINT, KillChild); 389112274Smdodd signal(SIGQUIT, KillChild); 39074408Smdodd 39174408Smdodd /* Wait for our child to close its pipe before we exit */ 39244165Sjulian if (read(bgpipe[0], &c, 1) != 1) { 39344165Sjulian prompt_Printf(prompt, "Child exit, no status.\n"); 39444165Sjulian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 39544165Sjulian } else if (c == EX_NORMAL) { 396111119Simp prompt_Printf(prompt, "PPP enabled.\n"); 39744165Sjulian log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 39844165Sjulian } else { 399112274Smdodd prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 400112291Smdodd log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 40144627Sjulian ex_desc((int) c)); 40244627Sjulian } 40344627Sjulian close(bgpipe[0]); 40444627Sjulian } 40544165Sjulian return c; 40644165Sjulian } else if (mode == PHYS_BACKGROUND) { 40744165Sjulian close(bgpipe[0]); 40844165Sjulian bundle->notify.fd = bgpipe[1]; 40944165Sjulian } 41044165Sjulian 41144165Sjulian bundle_LockTun(bundle); /* we have a new pid */ 41244165Sjulian 41344165Sjulian /* -auto, -dedicated, -ddial & -background */ 41474408Smdodd prompt_Destroy(prompt, 0); 41544165Sjulian close(STDOUT_FILENO); 41674408Smdodd close(STDERR_FILENO); 41774408Smdodd close(STDIN_FILENO); 418112279Smdodd setsid(); 41974408Smdodd } else { 420112279Smdodd /* -direct: STDIN_FILENO gets used by modem_Open */ 42174408Smdodd prompt_TtyInit(NULL); 422112279Smdodd close(STDOUT_FILENO); 423112279Smdodd close(STDERR_FILENO); 424112279Smdodd } 425112279Smdodd } else { 42644165Sjulian /* Interactive mode */ 42744165Sjulian close(STDERR_FILENO); 428130549Smlaier prompt_TtyInit(prompt); 429130549Smlaier prompt_TtyCommandMode(prompt); 43069152Sjlemon prompt_Required(prompt); 431130549Smlaier } 43244165Sjulian 43344165Sjulian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(mode)); 43444165Sjulian DoLoop(bundle); 43544165Sjulian AbortProgram(EX_NORMAL); 436112296Smdodd 43744165Sjulian return EX_NORMAL; 43844165Sjulian} 43944165Sjulian 44044165Sjulianstatic void 44144165SjulianDoLoop(struct bundle *bundle) 44244165Sjulian{ 44344165Sjulian fd_set rfds, wfds, efds; 44444165Sjulian int i, nfds; 44544165Sjulian 446112299Smdodd do { 44774408Smdodd nfds = 0; 44874408Smdodd FD_ZERO(&rfds); 44944165Sjulian FD_ZERO(&wfds); 450112299Smdodd FD_ZERO(&efds); 451112299Smdodd 452111888Sjlemon /* All our datalinks, the tun device and the MP socket */ 453112299Smdodd descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 45444165Sjulian 455112308Smdodd /* All our prompts and the diagnostic socket */ 456112308Smdodd descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 457112308Smdodd 458112308Smdodd if (bundle_IsDead(bundle)) 459112308Smdodd /* Don't select - we'll be here forever */ 460112308Smdodd break; 461112308Smdodd 462112308Smdodd i = select(nfds, &rfds, &wfds, &efds, NULL); 463112308Smdodd 464112308Smdodd if (i < 0 && errno != EINTR) { 465112308Smdodd log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 466112308Smdodd if (log_IsKept(LogTIMER)) { 467112308Smdodd struct timeval t; 468112308Smdodd 469112308Smdodd for (i = 0; i <= nfds; i++) { 470112308Smdodd if (FD_ISSET(i, &rfds)) { 471112308Smdodd log_Printf(LogTIMER, "Read set contains %d\n", i); 472112299Smdodd FD_CLR(i, &rfds); 473112299Smdodd t.tv_sec = t.tv_usec = 0; 474112299Smdodd if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 475112299Smdodd log_Printf(LogTIMER, "The culprit !\n"); 476112299Smdodd break; 477112299Smdodd } 478112299Smdodd } 479112299Smdodd if (FD_ISSET(i, &wfds)) { 480112286Smdodd log_Printf(LogTIMER, "Write set contains %d\n", i); 481112286Smdodd FD_CLR(i, &wfds); 482112286Smdodd t.tv_sec = t.tv_usec = 0; 483148887Srwatson if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 484148887Srwatson log_Printf(LogTIMER, "The culprit !\n"); 485112286Smdodd break; 48644165Sjulian } 487112308Smdodd } 488112308Smdodd if (FD_ISSET(i, &efds)) { 489112308Smdodd log_Printf(LogTIMER, "Error set contains %d\n", i); 490112308Smdodd FD_CLR(i, &efds); 491112308Smdodd t.tv_sec = t.tv_usec = 0; 492112308Smdodd if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 493112308Smdodd log_Printf(LogTIMER, "The culprit !\n"); 494112308Smdodd break; 495112308Smdodd } 496112308Smdodd } 497112308Smdodd } 498112308Smdodd } 499112308Smdodd break; 500112285Smdodd } 501172930Srwatson 502112285Smdodd sig_Handle(); 503112285Smdodd 504112286Smdodd if (i <= 0) 505112286Smdodd continue; 506112286Smdodd 507112299Smdodd for (i = 0; i <= nfds; i++) 50874408Smdodd if (FD_ISSET(i, &efds)) { 50958313Slile log_Printf(LogALERT, "Exception detected on descriptor %d\n", i); 510112280Smdodd break; 511112286Smdodd } 512112286Smdodd 513112286Smdodd if (i <= nfds) 514112286Smdodd break; 515112286Smdodd 516152315Sru if (descriptor_IsSet(&server.desc, &rfds)) 517112286Smdodd descriptor_Read(&server.desc, bundle, &rfds); 518112286Smdodd 519112286Smdodd if (descriptor_IsSet(&bundle->desc, &wfds)) 520112286Smdodd descriptor_Write(&bundle->desc, bundle, &wfds); 521112280Smdodd 522112280Smdodd if (descriptor_IsSet(&bundle->desc, &rfds)) 52344165Sjulian descriptor_Read(&bundle->desc, bundle, &rfds); 524126907Srwatson 525126907Srwatson } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); 52644165Sjulian 52744165Sjulian log_Printf(LogDEBUG, "DoLoop done.\n"); 52844165Sjulian} 52974408Smdodd