home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume18 / superser.ver < prev    next >
Encoding:
Text File  |  1989-04-20  |  31.9 KB  |  1,464 lines

  1. Path: wugate!wucs1!uunet!bbn.com!rsalz
  2. From: rsalz@uunet.uu.net (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v18i106:  "Super" network server for easy service-building
  5. Message-ID: <1680@papaya.bbn.com>
  6. Date: 19 Apr 89 18:59:23 GMT
  7. Lines: 1454
  8. Approved: rsalz@uunet.UU.NET
  9.  
  10. Submitted-by: koreth@ssyx.UCSC.EDU (Steven Grimm)
  11. Posting-number: Volume 18, Issue 106
  12. Archive-name: superserver
  13.  
  14. This program allows individual users to set up network services without
  15. having to worry about the intricacies of socket I/O.  It is similar in
  16. function to the "rsh" program, but restricts the commands which can be
  17. executed by remote users.  No .rhosts or password is required, since
  18. the remote user can only execute commands from a specified (presumably
  19. safe) list.
  20.  
  21. The service programs think they're talking to a pipe (because they are).
  22. Stdin and stdout are redirected to the pipe; stderr is mapped to stdout.
  23. Shell scripts can be offered as network services, but make sure you have
  24. execute permission on them and that the line "#!/bin/sh" (or csh, or
  25. whatever shell you're using) appears at the top of the file, or UNIX won't
  26. recognize it as an executable-format file.
  27.  
  28. #!/bin/sh
  29. # shar:    Shell Archiver  (v1.22)
  30. #
  31. #    Run the following text with /bin/sh to create:
  32. #      MANIFEST
  33. #      Makefile
  34. #      NOTES
  35. #      client.1
  36. #      client.c
  37. #      common.h
  38. #      server.1
  39. #      server.c
  40. #      socket.c
  41. #      supersrv.8
  42. #      supersrv.c
  43. #
  44. sed 's/^X//' << 'SHAR_EOF' > MANIFEST &&
  45. XThis shar file should contain:
  46. X
  47. XMANIFEST    This file
  48. XMakefile    To build everything
  49. XNOTES        Various implementation notes, wish list, etc.
  50. Xclient.1    Manual page for the client program
  51. Xclient.c    The client program
  52. Xcommon.h    Definitions common to all three programs
  53. Xserver.1    Manual page for the server program
  54. Xserver.c    The server program
  55. Xsocket.c    Various blackbox IPC routines used by everything
  56. Xsupersrv.8    Manual page for the supersrv program
  57. Xsupersrv.c    The supersrv program
  58. SHAR_EOF
  59. chmod 0600 MANIFEST || echo "restore of MANIFEST fails"
  60. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  61. X#
  62. X# SuperServer
  63. X#
  64. X# by Steven Grimm, koreth@ssyx.ucsc.edu
  65. X#
  66. X
  67. XCFLAGS = -O
  68. X
  69. XSUPERO = supersrv.o socket.o
  70. XSERVERO = server.o socket.o
  71. XCLIO = client.o socket.o
  72. X
  73. Xall: supersrv server client
  74. X
  75. Xsupersrv: $(SUPERO)
  76. X    $(CC) $(CFLAGS) $(SUPERO) -o $@
  77. X
  78. Xserver: $(SERVERO)
  79. X    $(CC) $(CFLAGS) $(SERVERO) -o $@
  80. X
  81. Xclient: $(CLIO)
  82. X    $(CC) $(CFLAGS) $(CLIO) -o $@
  83. X
  84. Xclean:
  85. X    /bin/rm -f $(SUPERO) $(SERVERO) $(CLIO) supersrv server client core
  86. X
  87. Xinstall: all
  88. X    install -s -c -m 755 supersrv /usr/local
  89. X    install -s -c -m 755 server /usr/local
  90. X    install -s -c -m 755 client /usr/local
  91. SHAR_EOF
  92. chmod 0600 Makefile || echo "restore of Makefile fails"
  93. sed 's/^X//' << 'SHAR_EOF' > NOTES &&
  94. XThis program allows individual users to set up network services without
  95. Xhaving to worry about the intricacies of socket I/O.  It is similar in
  96. Xfunction to the "rsh" program, but restricts the commands which can be
  97. Xexecuted by remote users.  No .rhosts or password is required, since
  98. Xthe remote user can only execute commands from a specified (presumably
  99. Xsafe) list.
  100. X
  101. XThe service programs think they're talking to a pipe (because they are).
  102. XStdin and stdout are redirected to the pipe; stderr is mapped to stdout.
  103. XShell scripts can be offered as network services, but make sure you have
  104. Xexecute permission on them and that the line "#!/bin/sh" (or csh, or
  105. Xwhatever shell you're using) appears at the top of the file, or UNIX won't
  106. Xrecognize it as an executable-format file.
  107. X
  108. XThe server consists of two layers.  The bottom layer (subserver) is
  109. Xexecuted by a user when he wants to advertise services.  It reads a
  110. Xconfiguration file from the user's home directory, which contains a
  111. Xlist of service names and full path specifications.  It then checks for
  112. Xthe existence of the top layer (the super-server), and runs the
  113. Xsuperserver program if it was not already active.  In any case, the
  114. Xserver connects to the superserver, registers its service-names, and
  115. Xawaits a request.
  116. X
  117. XThe superserver accepts connections from remote locations, usually
  118. Xinitiated with the "client" program.  It reads a line of input from the
  119. Xclient program, which specifies the name of the desired service.  If
  120. Xone of the subservers has advertised the requested service, the
  121. Xsuperserver forks off a child process.  The child writes the name of
  122. Xthe requested service to the appropriate subserver, then acts as a
  123. Xmailman, shuffling bytes between the remote user and the subserver
  124. Xuntil one of them disconnects.  Meanwhile, the parent superserver
  125. Xwaits for another connection, and the whole bloody mess starts over.
  126. X
  127. XThe client-supersrv handshaking looks like this (all lines are newline-
  128. Xterminated, so you could talk to supersrv with telnet, for instance):
  129. X
  130. Xclient                supersrv
  131. X------                --------
  132. X                welcome message
  133. Xservice name
  134. Xusername (or empty line)
  135. Xarg1
  136. Xarg2
  137. Xarg3
  138. X .
  139. X .
  140. X .
  141. Xargn
  142. Xblank line
  143. X
  144. X
  145. XIf a superserver process is killed, all its subservers try to restart
  146. Xit until one of them succeeds.  If a server process is killed, the
  147. Xsuperserver removes all its services from the listing.  Some braindamaged
  148. XBSD implementations can take up to five minutes to figure out that a
  149. Xprocess has died and that its socket addresses are no longer in use, so
  150. Xkilling a superserver might result in a short interruption of service.
  151. X
  152. XSending a HUP signal to a server causes it to reload its database.
  153. X
  154. X
  155. XWish list:
  156. X
  157. X    If exec-ing a program fails because of an invalid file format, we
  158. Xshould try to run the program from sh, since it's probably a script without
  159. Xthe #!/bin/sh at the top.
  160. X
  161. X    Some form of logging would be nice, so people can tell who's
  162. Xusing which services.
  163. X
  164. X    Signal-passing and standard error support a la rsh would be neat, too.
  165. X
  166. X    Support for interactive programs by automatically allocating a pty
  167. Xbefore running a program would be helpful.  Some form of environment passing
  168. Xwould also need to be implemented for programs that use termcap.
  169. X
  170. XIf you have questions, comments, bug reports, large amounts of excess cash,
  171. Xhorny women, etc., send a letter to koreth@ssyx.ucsc.edu.
  172. X
  173. SHAR_EOF
  174. chmod 0600 NOTES || echo "restore of NOTES fails"
  175. sed 's/^X//' << 'SHAR_EOF' > client.1 &&
  176. X.TH CLIENT 1 "14 July 1988"
  177. X.SH NAME
  178. Xclient \- use a network service
  179. X.SH SYNOPSIS
  180. X.B client
  181. X[
  182. X.B \-u
  183. X.I username
  184. X]
  185. X.I host
  186. X.I servicename
  187. X[
  188. X.I arguments
  189. X]
  190. X.SH DESCRIPTION
  191. X.I Client
  192. Xinterfaces with services offered through
  193. X.IR server (1).
  194. XSpecify the hostname and service; the service must be offered
  195. Xby someone on the appropriate host.  To get a list of services
  196. Xoffered on 
  197. X.I host,
  198. Xuse the
  199. X.B LIST
  200. Xservice, which is always present.  Any 
  201. X.I arguments
  202. Xafter the
  203. X.I servicename
  204. Xare passed to the service.  Be careful of passing
  205. Xfilenames, as remote machines generally can't read files on the
  206. Xlocal host.
  207. X.SH OPTIONS
  208. X.IP \-u
  209. XIf two services of the same name are offered by different users,
  210. Xuse the
  211. X.I \-u
  212. Xoption to select the desired user.  If this flag is not given,
  213. Xthe client will pick the first service whose name matches the
  214. Xrequested one.
  215. X.SH EXAMPLES
  216. X.ft C
  217. X% client ssyx.ucsc.edu fortune -l
  218. X.ft R
  219. X.PP
  220. XThis connects to machine "ssyx.ucsc.edu" and prints out a long
  221. Xfortune.
  222. X.sp 1
  223. X.ft C
  224. X% client -u geek doofus.foo.bar LIST
  225. X.ft R
  226. X.PP
  227. XThis lists all services offered by user "geek" on host
  228. X"doofus.foo.bar".
  229. X.SH "SEE ALSO"
  230. Xrsh(1), server(1), supersrv(8)
  231. X.SH DIAGNOSTICS
  232. XIf no services are offered on a host,
  233. X.I client
  234. Xsays "clientsock: connection refused".
  235. X.SH AUTHOR
  236. XSteven Grimm (koreth@ssyx.ucsc.edu, ...!ucbvax!ssyx!koreth)
  237. SHAR_EOF
  238. chmod 0600 client.1 || echo "restore of client.1 fails"
  239. sed 's/^X//' << 'SHAR_EOF' > client.c &&
  240. X#include "common.h"
  241. X
  242. Xmain(argc, argv)
  243. Xchar **argv;
  244. X{
  245. X    int thirty;
  246. X    char c, user[16];
  247. X    int fd, i;
  248. X
  249. X    if (argc < 3)
  250. X    {
  251. Xusage:
  252. X        fprintf(stderr, "usage: %s [-u user] host cmd [parms]\n", argv[0]);
  253. X        exit(-1);
  254. X    }
  255. X
  256. X    user[0] = 0;
  257. X
  258. X    if (argv[1][0] == '-')
  259. X        switch(argv[1][1])
  260. X        {
  261. X        case 'u':
  262. X            strncpy(user, argv[2], 15);
  263. X            user[15] = 0;
  264. X            argv += 2;
  265. X            argc -= 2;
  266. X            if (argc < 3)
  267. X                goto usage;
  268. X            break;
  269. X        default:
  270. X            fprintf(stderr, "-%c flag unknown\n", argv[1][1]);
  271. X            break;
  272. X        }
  273. X
  274. X    thirty = 30;
  275. X
  276. X    fd = clientsock(argv[1], SUPERPORT);
  277. X    if (fd < 0)
  278. X    {
  279. X        switch(fd) {
  280. X        case -9999:
  281. X            fprintf(stderr, "%s: host unknown\n", argv[1]);
  282. X            break;
  283. X        case -ECONNREFUSED:
  284. X            fprintf(stderr, "No services on %s\n", argv[1]);
  285. X            break;
  286. X        default:
  287. X            perror("clientsock");
  288. X            break;
  289. X        }
  290. X        exit(-1);
  291. X    }
  292. X
  293. X    setsockopt(fd, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  294. X
  295. X    do
  296. X        read(fd, &c, 1);
  297. X    while (c != '\n');
  298. X
  299. X    writeln(fd, argv[2]);
  300. X    writeln(fd, user);
  301. X
  302. X    if (argc > 3)
  303. X        for (i=3; i<argc; i++)
  304. X            writeln(fd, argv[i]);
  305. X
  306. X    writeln(fd, "");
  307. X
  308. X    shuffle(fd);
  309. X
  310. X    fcntl(0, F_SETFL, 0);
  311. X    close(fd);
  312. X}
  313. X
  314. Xwriteln(fd, string)
  315. Xint fd;
  316. Xchar *string;
  317. X{
  318. X    write(fd, string, strlen(string));
  319. X    write(fd, "\n", 1);
  320. X}
  321. X
  322. X/*
  323. X * Shuffle bytes between stdin/out and the socket.  This forks off
  324. X * once so that one process handles dataflow in each direction (that's
  325. X * how rsh does it, and it makes the code a lot prettier...)
  326. X */
  327. Xshuffle(subsrv)
  328. Xint subsrv;        /* this will probably always be 3... */
  329. X{
  330. X    fd_set reed, tread, other;
  331. X    int pid, numread, buf[BUFSIZ];
  332. X
  333. X    pid = fork();
  334. X    if (pid < 0)
  335. X    {
  336. X        perror("fork");
  337. X        close(subsrv);
  338. X        exit(-1);
  339. X    }
  340. X
  341. X    FD_ZERO(&reed);
  342. X    FD_ZERO(&other);
  343. X
  344. X    if (!pid)
  345. X    {
  346. X        close(1);
  347. X        close(2);
  348. X
  349. X        while (1)
  350. X        {
  351. X            numread = read(0, buf, sizeof(buf));
  352. X            if (numread <= 0)
  353. X                break;
  354. X            write(subsrv, buf, numread);
  355. X        }
  356. X        close(subsrv);
  357. X        exit(0);
  358. X    }
  359. X    else
  360. X    {
  361. X        close(0);
  362. X        close(2);
  363. X
  364. X        while (1)
  365. X        {
  366. X            numread = read(subsrv, buf, sizeof(buf));
  367. X            if (numread <= 0)
  368. X                break;
  369. X            write(1, buf, numread);
  370. X        }
  371. X
  372. X        kill(pid, SIGKILL);
  373. X    }
  374. X}
  375. X
  376. SHAR_EOF
  377. chmod 0600 client.c || echo "restore of client.c fails"
  378. sed 's/^X//' << 'SHAR_EOF' > common.h &&
  379. X/*
  380. X * Common.h
  381. X *
  382. X * Definitions common to both the sub- and superserver.
  383. X */
  384. X
  385. X/*
  386. X * Common include files
  387. X */
  388. X#include <stdio.h>
  389. X#include <signal.h>
  390. X#include <errno.h>
  391. X#include <fcntl.h>
  392. X#include <sys/param.h>
  393. X#include <sys/ioctl.h>
  394. X#include <sys/time.h>
  395. X#include <sys/socket.h>
  396. X
  397. X/*
  398. X * This is the port number that the superserver listens on.
  399. X */
  400. X#define SUPERPORT    3502
  401. X
  402. X/*
  403. X * Common external variables.
  404. X */
  405. Xextern int errno;
  406. X
  407. SHAR_EOF
  408. chmod 0600 common.h || echo "restore of common.h fails"
  409. sed 's/^X//' << 'SHAR_EOF' > server.1 &&
  410. X.TH SERVER 1 "14 July 1988"
  411. X.SH NAME
  412. Xserver \- offer network services
  413. X.SH SYNOPSIS
  414. X.B server
  415. X.SH DESCRIPTION
  416. X.I Server
  417. Xallows users to offer services to other users, possibly on remote
  418. Xhosts.  Any program (or shell script) that a user has execute permission
  419. Xon can be offered as a service.
  420. X.PP
  421. XIf a server is the first to start up on a machine, the super-server
  422. X.IR supersrv (8)
  423. Xis automatically started by
  424. X.I server,
  425. Xwhich then tells
  426. X.I supersrv
  427. Xwhich services the user wants to offer.
  428. X.I Server
  429. Xlooks for a file called
  430. X.I .services
  431. Xin the user's home directory, which consists of a list of service names
  432. Xand pathnames.
  433. X.SH EXAMPLE
  434. X.nf
  435. X.ft C
  436. X% cat .services
  437. Xfortune /usr/games/fortune
  438. Xw       /usr/ucb/w
  439. Xwho     /bin/who
  440. Xcrash   /g/f/v/foobar/kill-the-system
  441. X% server
  442. X%
  443. X.ft R
  444. X.SH DISCUSSION
  445. XMost programs should work without any problems as services.  The service
  446. Xthinks it's talking to a pipe; interactive programs work as long as they
  447. Xdon't attempt to set any special terminal modes or use
  448. X.IR termcap (3)
  449. Xor
  450. X.IR curses (3)
  451. Xto try to update the client's screen.  These restrictions are the same as
  452. Xthose of
  453. X.IR rsh (1);
  454. X.IR client (1)
  455. Xis similar to
  456. X.I rsh
  457. Xexcept that security is handled differently.
  458. X.PP
  459. XIf
  460. X.I supersrv
  461. Xgoes away (usually as a result of a kill command from a user who hasn't
  462. Xread this or doesn't know why there's an extra process running next to his
  463. Xserver), all the
  464. X.I server
  465. Xprocesses on the system will keep trying to restart
  466. X.I supersrv
  467. Xuntil one of them succeeds.  Since it can take a while for TCP ports to
  468. Xclear after their binding process has died on some implementations of
  469. XBSD, killing a
  470. X.I supersrv
  471. Xmay result in a short interruption of service.
  472. X.PP
  473. XSending a hangup signal (SIGHUP) to a
  474. X.I server
  475. Xprocess will cause it to reload its services database, so it isn't
  476. Xnecessary to rerun the program if the services list is changed.
  477. X.SH FILES
  478. X.TS
  479. X$HOME/.services    services list
  480. X.TE
  481. X.SH "SEE ALSO"
  482. Xclient(1), supersrv(8)
  483. X.SH BUGS
  484. X.I Server
  485. Xdoesn't sense when another server is being run by the same user; thus a
  486. Xuser could run several servers at the same time, most of which would never
  487. Xbe used.  Duplicate service names would appear in the service list.
  488. X.PP
  489. XShell scripts offered as services must have the line "#!/bin/sh" (or csh,
  490. Xor whatever shell is being used) at the top, or
  491. X.I server
  492. Xwon't be able to execute them.
  493. X.SH AUTHOR
  494. XSteven Grimm (koreth@ssyx.ucsc.edu, ...!ucbvax!ssyx!koreth)
  495. SHAR_EOF
  496. chmod 0600 server.1 || echo "restore of server.1 fails"
  497. sed 's/^X//' << 'SHAR_EOF' > server.c &&
  498. X#include "common.h"
  499. X#include <sys/file.h>
  500. X#include <pwd.h>
  501. X
  502. X/*
  503. X * SubServer main module.
  504. X */
  505. X
  506. X#define    RCFILE    "/.services"    /* File to grab services from */
  507. X
  508. Xchar *getenv();
  509. X
  510. X/*
  511. X * This linked list structure is used to keep track of the
  512. X * services we're offering.
  513. X */
  514. Xstruct service {
  515. X    char    name[20];        /* Service name */
  516. X    char    path[MAXPATHLEN];    /* Service path */
  517. X    struct service *next;        /* Next element... */
  518. X} *list;
  519. X
  520. X/*
  521. X * Read in a services file and set up the linked list of
  522. X * services.  Test each service to be sure we can offer it.
  523. X * Returns 0 if there are no services offered.
  524. X */
  525. Xgetservices()
  526. X{
  527. X    FILE    *fp;
  528. X    char    filename[MAXPATHLEN], *home;
  529. X
  530. X    home = getenv("HOME");
  531. X    if (! home)
  532. X    {
  533. X        fprintf(stderr, "no home directory\n");
  534. X        return(0);
  535. X    }
  536. X
  537. X    strcpy(filename, home);
  538. X    strcat(filename, RCFILE);
  539. X
  540. X    fp = fopen(filename, "r");
  541. X    if (! fp)
  542. X    {
  543. X        perror("couldn't open services file");
  544. X        return(0);
  545. X    }
  546. X
  547. X    list = NULL;
  548. X
  549. X    while (! feof(fp))
  550. X    {
  551. X        char    servname[20], format[20];
  552. X
  553. X        servname[0] = 0;
  554. X        sprintf(format, "%%20s\t%%%d[^\n]", MAXPATHLEN);
  555. X        fscanf(fp, format, servname, filename);
  556. X        getc(fp);
  557. X        
  558. X        if (servname[0] && filename[0])
  559. X        {
  560. X            struct service *temp;
  561. X
  562. X            if (access(filename, X_OK))
  563. X            {
  564. X                fprintf(stderr, "warning: can't execute %s\n",
  565. X                    filename);
  566. X                continue;
  567. X            }
  568. X
  569. X            temp = (struct service *) malloc(sizeof(struct service));
  570. X            strcpy(temp->name, servname);
  571. X            strcpy(temp->path, filename);
  572. X            temp->next = list;
  573. X            list = temp;
  574. X        }
  575. X    }
  576. X    fclose(fp);
  577. X    return 1;
  578. X}
  579. X
  580. X
  581. X/*
  582. X * Reap children.
  583. X */
  584. Xsigchld()
  585. X{
  586. X    return wait(0);
  587. X}
  588. X
  589. Xint    fd;
  590. X
  591. X/*
  592. X * Reload the database.
  593. X * We do this by killing the old list element by element then calling
  594. X * getservices(), and closing the socket file descriptor so the main
  595. X * loop will have to reregister our services.
  596. X */
  597. Xreload()
  598. X{
  599. X    struct service *cur, *next;
  600. X
  601. X    cur = list;
  602. X    while (cur)
  603. X    {
  604. X        next = cur->next;
  605. X        free(cur);
  606. X        cur = next;
  607. X    }
  608. X
  609. X    if (! getservices())
  610. X        exit(-1);
  611. X    close(fd);
  612. X    fd = -1;    /* prevent another close... */
  613. X}
  614. X
  615. Xmain(argc, argv, envp)
  616. Xchar **argv, **envp;
  617. X{
  618. X    int thirty;
  619. X    struct service *cur;
  620. X    struct passwd *pw;
  621. X    char    service[80], user[16];
  622. X
  623. X    if (! getservices())
  624. X        exit(0);
  625. X
  626. X    if (fork())
  627. X        exit(0);
  628. X
  629. X    close(0);
  630. X    close(1);
  631. X    close(2);
  632. X
  633. X    fd = open("/dev/tty", O_RDWR);
  634. X    if (fd >= 0)
  635. X    {
  636. X        ioctl(fd, TIOCNOTTY, 0);
  637. X        close(fd);
  638. X    }
  639. X    else
  640. X        printf("warning: couldn't disassociate from tty\n");
  641. X
  642. X/*
  643. X * Handle signals.  We want to reap children, so we should handle SIGCHLDs;
  644. X * we also want to let the user reload his services database, which we do
  645. X * with SIGHUP.
  646. X */
  647. X    signal(SIGCHLD, sigchld);
  648. X    signal(SIGHUP, reload);
  649. X
  650. X    thirty = 30;
  651. X
  652. X    pw = getpwuid(getuid());
  653. X    if (pw == NULL)
  654. X    {
  655. X        printf("warning: couldn't get UID\n");
  656. X        user[0] = '\n';
  657. X        user[1] = '\0';
  658. X    }
  659. X    else
  660. X    {
  661. X        strncpy(user, pw->pw_name, sizeof(user)-2);
  662. X        user[sizeof(user)-1] = '\0';
  663. X        strcat(user, "\n");
  664. X    }
  665. X    
  666. X    while (1)
  667. X    {
  668. X        char c;
  669. X
  670. X        fd = clientsock("localhost", SUPERPORT);
  671. X        if (fd < 0)
  672. X            if (errno == ECONNREFUSED)
  673. X            {
  674. X                start_super(argv[0], envp);
  675. X/*
  676. X * Give the superserver time to fire up.
  677. X */
  678. X                sleep(5);
  679. X                continue;
  680. X            }
  681. X            else
  682. X            {
  683. X                perror("superserver connect");
  684. X                exit(-1);
  685. X            }
  686. X
  687. X        thirty = 30;
  688. X        setsockopt(fd, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  689. X        c = 0;
  690. X        do
  691. X            if (read(fd, &c, 1) < 0 && errno != EINTR)
  692. X                break;
  693. X        while (c != '\n');
  694. X
  695. X        if (c != '\n')
  696. X            continue;
  697. X
  698. X        write(fd, "REGISTER\n", 9);
  699. X        write(fd, user, strlen(user));
  700. X
  701. X        for (cur = list; cur; cur = cur->next)
  702. X        {
  703. X            write(fd, cur->name, strlen(cur->name));
  704. X            write(fd, "\n", 1);
  705. X        }
  706. X        write(fd, "\n", 1);
  707. X
  708. X        service[0] = 0;
  709. X        if (read(fd, service, 20) < 0 && errno != EBADF && errno != EINTR)
  710. X        {
  711. X            perror("read");
  712. X            exit(-1);
  713. X        }
  714. X
  715. X        if (service[0])
  716. X            do_service(service, fd, envp);
  717. X        if (fd >= 0)
  718. X            close(fd);
  719. X    }
  720. X}
  721. X
  722. X
  723. X/*
  724. X * Provide the service.  Fork off and keep reading parameters until
  725. X * they are terminated by an empty line, then pass them to the program
  726. X * specified by the service.
  727. X */
  728. Xdo_service(service, fd, envp)
  729. Xchar *service;
  730. Xint fd;
  731. Xchar **envp;
  732. X{
  733. X    struct service *cur;
  734. X    char    *argv[256], input[256];
  735. X    int    curarg = 0, index = 0, thirty = 60;
  736. X
  737. X    if (fork())
  738. X        return;
  739. X
  740. X    argv[curarg++] = service;
  741. X
  742. X    while (1) {
  743. X        read(fd, &input[index], 1);
  744. X        if (input[index] == '\r')
  745. X            continue;
  746. X        if (input[index] == '\n')
  747. X        {
  748. X            if (! index)
  749. X                break;
  750. X
  751. X            argv[curarg] = (char *)malloc(index+1);
  752. X            bcopy(input, argv[curarg], index);
  753. X            argv[curarg][index] = 0;
  754. X
  755. X            index = 0;
  756. X            curarg++;
  757. X        }
  758. X        else
  759. X            index++;
  760. X    }
  761. X
  762. X    dup2(fd, 0);
  763. X    dup2(fd, 1);
  764. X    dup2(fd, 2);
  765. X    setsockopt(0, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  766. X    setsockopt(1, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  767. X    setsockopt(2, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  768. X    if (fd > 2)
  769. X        close(fd);
  770. X
  771. X    argv[curarg] = NULL;
  772. X
  773. X    for (cur = list; cur; cur = cur->next)
  774. X        if (! strcmp(cur->name, service))
  775. X            break;
  776. X
  777. X    if (! cur)        /* service not there */
  778. X        exit(0);
  779. X
  780. X    execve(cur->path, argv, envp);
  781. X    perror("execve");
  782. X    exit(0);
  783. X}
  784. X
  785. Xchar *superv[] = { "/bin/sh", "-c", "supersrv", NULL };
  786. X
  787. Xstart_super(argv0, envp)
  788. Xchar *argv0, **envp;
  789. X{
  790. X    char *lastslash, argcopy[MAXPATHLEN], *rindex();
  791. X
  792. X    strcpy(argcopy, argv0);
  793. X/*
  794. X * If a path was given, try to find the superserver in the
  795. X * same directory as the subserver...
  796. X */
  797. X    if (lastslash = rindex(argcopy, '/'))
  798. X    {
  799. X        char path[MAXPATHLEN];
  800. X
  801. X        *lastslash = 0;
  802. X        strcpy(path, argcopy);
  803. X        strcat(path, "/supersrv");
  804. X        if (! access(path, X_OK))
  805. X        {
  806. X            if (! fork())
  807. X                execve(path, superv+2, envp);
  808. X            return;
  809. X        }
  810. X    }
  811. X
  812. X/*
  813. X * Otherwise, start up a shell to scan along the user's
  814. X * $PATH.
  815. X */
  816. X    if (! fork())
  817. X        execve(superv[0], superv, envp);
  818. X}
  819. X
  820. SHAR_EOF
  821. chmod 0600 server.c || echo "restore of server.c fails"
  822. sed 's/^X//' << 'SHAR_EOF' > socket.c &&
  823. X/*
  824. X** SOCKET.C
  825. X**
  826. X** Written by Steven Grimm (koreth@ssyx.ucsc.edu) on 11-26-87 (Thanksgiving)
  827. X** Please distribute widely, but leave my name here.
  828. X**
  829. X** Various black-box routines for socket manipulation, so I don't have to
  830. X** remember all the structure elements.
  831. X** Of course, I still have to remember how to call these routines.
  832. X*/
  833. X
  834. X#include <sys/types.h>
  835. X#include <sys/time.h>
  836. X#include <sys/socket.h>
  837. X#include <netinet/in.h>
  838. X#include <netdb.h>
  839. X#include <stdio.h>
  840. X
  841. X#ifndef FD_SET        /* for 4.2BSD */
  842. X#define FD_SETSIZE      (sizeof(fd_set) * 8)
  843. X#define FD_SET(n, p)    (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
  844. X#define FD_CLR(n, p)    (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
  845. X#define FD_ISSET(n, p)  (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
  846. X#define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
  847. X#endif
  848. X
  849. Xextern int errno;
  850. X
  851. X/*
  852. X** serversock()
  853. X**
  854. X** Creates an internet socket, binds it to an address, and prepares it for
  855. X** subsequent accept() calls by calling listen().
  856. X**
  857. X** Input: port number desired, or 0 for a random one
  858. X** Output: file descriptor of socket, or a negative error
  859. X*/
  860. Xint serversock(port)
  861. Xint port;
  862. X{
  863. X    int    sock, x;
  864. X    struct    sockaddr_in server;
  865. X
  866. X    sock = socket(AF_INET, SOCK_STREAM, 0);
  867. X    if (sock < 0)
  868. X        return -errno;
  869. X
  870. X    bzero(&server, sizeof(server));
  871. X    server.sin_family = AF_INET;
  872. X    server.sin_addr.s_addr = INADDR_ANY;
  873. X    server.sin_port = htons(port);
  874. X
  875. X    x = bind(sock, &server, sizeof(server));
  876. X    if (x < 0)
  877. X    {
  878. X        close(sock);
  879. X        return -errno;
  880. X    }
  881. X
  882. X    listen(sock, 5);
  883. X
  884. X    return sock;
  885. X}
  886. X
  887. X/*
  888. X** portnum()
  889. X**
  890. X** Returns the internet port number for a socket.
  891. X**
  892. X** Input: file descriptor of socket
  893. X** Output: inet port number
  894. X*/
  895. Xint portnum(fd)
  896. Xint fd;
  897. X{
  898. X    int    length, err;
  899. X    struct    sockaddr_in address;
  900. X
  901. X    length = sizeof(address);
  902. X    err = getsockname(fd, &address, &length);
  903. X    if (err < 0)
  904. X        return -errno;
  905. X
  906. X    return ntohs(address.sin_port);
  907. X}
  908. X
  909. X/*
  910. X** clientsock()
  911. X**
  912. X** Returns a connected client socket.
  913. X**
  914. X** Input: host name and port number to connect to
  915. X** Output: file descriptor of CONNECTED socket, or a negative error (-9999
  916. X**         if the hostname was bad).
  917. X*/
  918. Xint clientsock(host, port)
  919. Xchar *host;
  920. Xint port;
  921. X{
  922. X    int    sock;
  923. X    struct    sockaddr_in server;
  924. X    struct    hostent *hp, *gethostbyname();
  925. X
  926. X    hp = gethostbyname(host);
  927. X    if (hp == NULL)
  928. X        return -9999;
  929. X
  930. X    sock = socket(AF_INET, SOCK_STREAM, 0);
  931. X    if (sock < 0)
  932. X        return -errno;
  933. X
  934. X    bzero(&server, sizeof(server));
  935. X    server.sin_family = AF_INET;
  936. X    bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
  937. X    server.sin_port = htons(port);
  938. X
  939. X    if (connect(sock, &server, sizeof(server)) < 0)
  940. X    {
  941. X        close(sock);
  942. X        return -errno;
  943. X    }
  944. X
  945. X    return sock;
  946. X}
  947. X
  948. X/*
  949. X** readable()
  950. X**
  951. X** Poll a socket for pending input.  Returns immediately.  This is a front-end
  952. X** to waitread() below.
  953. X**
  954. X** Input: file descriptor to poll
  955. X** Output: 1 if data is available for reading
  956. X*/
  957. Xreadable(fd)
  958. Xint fd;
  959. X{
  960. X    return(waitread(fd, 0));
  961. X}
  962. X
  963. X/*
  964. X** waitread()
  965. X**
  966. X** Wait for data on a file descriptor for a little while.
  967. X**
  968. X** Input: file descriptor to watch
  969. X**      how long to wait, in seconds, before returning
  970. X** Output: 1 if data was available
  971. X**       0 if the timer expired or a signal occurred.
  972. X*/
  973. Xwaitread(fd, time)
  974. Xint fd, time;
  975. X{
  976. X    fd_set readbits, other;
  977. X    struct timeval timer;
  978. X    int ret;
  979. X
  980. X    timerclear(&timer);
  981. X    timer.tv_sec = time;
  982. X    FD_ZERO(&readbits);
  983. X    FD_ZERO(&other);
  984. X    FD_SET(fd, &readbits);
  985. X
  986. X    ret = select(fd+1, &readbits, &other, &other, &timer);
  987. X    if (FD_ISSET(fd, &readbits))
  988. X        return 1;
  989. X    return 0;
  990. X}
  991. X
  992. SHAR_EOF
  993. chmod 0600 socket.c || echo "restore of socket.c fails"
  994. sed 's/^X//' << 'SHAR_EOF' > supersrv.8 &&
  995. X.TH SUPERSRV 8 "July 14, 1988"
  996. X.SH NAME
  997. Xsupersrv \- manage network services
  998. X.SH SYNOPSIS
  999. X.B supersrv
  1000. X.SH DESCRIPTION
  1001. X.I Supersrv
  1002. Xkeeps track of which services (see
  1003. X.IR server (1))
  1004. Xare offered on a host.  It is automatically started by
  1005. X.I server
  1006. Xif it isn't already running; users should never have to run
  1007. X.I supersrv
  1008. Xexplicitly.
  1009. X.SH "SEE ALSO"
  1010. Xserver(1), client(1)
  1011. X.SH AUTHOR
  1012. XSteven Grimm (koreth@ssyx.ucsc.edu, ...!ucbvax!ssyx!koreth)
  1013. X.SH DISCUSSION
  1014. XThe superserver accepts connections from remote locations, usually
  1015. Xinitiated with the "telnet" program.  It reads a line of input from the
  1016. Xclient program, which specifies the name of the desired service.  If
  1017. Xone of the subservers has advertised the requested service, the
  1018. Xsuperserver forks off a child process.  The child writes the name of
  1019. Xthe requested service to the appropriate subserver, then acts as a
  1020. Xmailman, shuffling bytes between the remote user and the subserver
  1021. Xuntil one of them disconnects.  Meanwhile, the parent superserver
  1022. Xwaits for another connection, and the whole bloody mess starts over.
  1023. X.PP
  1024. XIf a superserver process is killed, all its subservers try to restart
  1025. Xit until one of them succeeds.
  1026. X.PP
  1027. X.I Supersrv
  1028. Xlistens on port number 3502; it's possible to request services via
  1029. Xthe
  1030. X.IR telnet (1)
  1031. Xprogram, though the
  1032. X.IR client (1)
  1033. Xinterface is preferred.  The fields sent by
  1034. X.I client,
  1035. Xterminated by newlines, are:
  1036. X.PP
  1037. Xservice name or LIST
  1038. X.br
  1039. Xusername to request service from (blank for any)
  1040. X.br
  1041. Xcommand line arguments, one per line (optional)
  1042. X.br
  1043. Xterminating blank line
  1044. X.PP
  1045. XThus, a session could look like this:
  1046. X.PP
  1047. X%
  1048. X.B telnet ucsco.ucsc.edu 3502
  1049. X.br
  1050. XTrying...
  1051. X.br
  1052. XConnected to UCSCO.UCSC.EDU.
  1053. X.br
  1054. XSuperServer -- enter service desired.
  1055. X.br
  1056. X.B webster <newline>
  1057. X.br
  1058. X.B <newline>
  1059. X.br
  1060. X.B topiary
  1061. X.br
  1062. X.B <newline>
  1063. X.br
  1064. X.IP 1.
  1065. Xto.pi.ary \\'to--pe--.er-e-\\ aj [L topiarius, fr. topia ornamental
  1066. Xgardening, irreg. fr. Gk topo]s place : of, relating to, or being the
  1067. Xpractice or art of training, cutting, and trimming trees or shrubs into odd
  1068. Xor ornamental shapes; also : characterized by such work
  1069. X.IP 2.
  1070. Xtopiary n : topiary art or gardening; also : a topiary garden
  1071. X.PP
  1072. XConnection closed by foreign host.
  1073. X.PP
  1074. XNote:
  1075. X.I supersrv
  1076. Xshould be placed in a directory that is in users' search paths, as
  1077. X.I server
  1078. Xneeds to find it.
  1079. X
  1080. SHAR_EOF
  1081. chmod 0600 supersrv.8 || echo "restore of supersrv.8 fails"
  1082. sed 's/^X//' << 'SHAR_EOF' > supersrv.c &&
  1083. X#include "common.h"
  1084. X
  1085. Xextern int errno;
  1086. X
  1087. X/*
  1088. X * SuperServer.
  1089. X */
  1090. X
  1091. X#define WELCOME    "SuperServer -- enter service desired.\n"
  1092. X#define NOSERV    "Service not offered.\n"
  1093. X
  1094. Xint thirty;
  1095. X
  1096. X/*
  1097. X * This structure is used to keep the database of available services.
  1098. X */
  1099. Xstruct service {
  1100. X    char    name[20];    /* Service name */
  1101. X    int    fd;        /* File descriptor that offers it */
  1102. X    struct service *next;    /* Next service in list */
  1103. X} *list = (struct service *)0;
  1104. X
  1105. Xchar users[NOFILE][16];        /* user connected to each fd */
  1106. X
  1107. Xmain(argc, argv)
  1108. Xchar **argv;
  1109. X{
  1110. X    struct itimerval it;        /* Alarm! */
  1111. X    int    fd_so,            /* Socket() file descriptor */
  1112. X        fd_co;            /* Connected file descriptor */
  1113. X    short    portno;            /* Port number to listen on */
  1114. X    char    request[80];
  1115. X    extern int sigchld();
  1116. X
  1117. X/*
  1118. X * First things first: put ourselves in the background.
  1119. X */
  1120. X    if (fork())
  1121. X        exit(0);
  1122. X
  1123. X    portno = SUPERPORT;
  1124. X    thirty = 30;
  1125. X
  1126. X/*
  1127. X * Set up the server socket on the appropriate port number and listen on it.
  1128. X */
  1129. X    fd_so = serversock(portno);
  1130. X    if (fd_so < 0)
  1131. X    {
  1132. X        perror("serversock");
  1133. X        exit(-1);
  1134. X    }
  1135. X
  1136. X    (void)listen(fd_so, 5);
  1137. X    setsockopt(fd_so, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  1138. X    fcntl(fd_so, F_SETOWN, getpid());
  1139. X
  1140. X/*
  1141. X * And we'll need to accomodate child processes...
  1142. X */
  1143. X    signal(SIGCHLD, sigchld);
  1144. X
  1145. X/*
  1146. X * Now keep accepting connections and interpreting them.
  1147. X */
  1148. X    while (1)
  1149. X    {
  1150. X        fd_co = getcon(fd_so);
  1151. X
  1152. X        if (fd_co < 0)
  1153. X        {
  1154. X            perror("accept");
  1155. X            exit(0);
  1156. X        }
  1157. X
  1158. X        fcntl(fd_co, F_SETOWN, getpid());
  1159. X        setsockopt(fd_co,SOL_SOCKET,SO_LINGER,&thirty, sizeof(thirty));
  1160. X
  1161. X        do {
  1162. X            write(fd_co, WELCOME, sizeof(WELCOME)-1);
  1163. X        } while (! getline(fd_co, request, sizeof(request)-1));
  1164. X
  1165. X        if (handle(fd_co, request))
  1166. X            close(fd_co);
  1167. X    }
  1168. X}
  1169. X
  1170. X/*
  1171. X * Get a connection, or handle a disconnected server.
  1172. X */
  1173. Xgetcon(old)
  1174. Xint old;
  1175. X{
  1176. X    struct    service *cur;
  1177. X    fd_set    reed, tread, other;
  1178. X    int    firstfd;
  1179. X
  1180. X    FD_ZERO(&reed);
  1181. X    FD_ZERO(&other);
  1182. X
  1183. X    for (cur = list; cur; cur = cur->next)
  1184. X        FD_SET(cur->fd, &reed);
  1185. X    FD_SET(old, &reed);
  1186. X
  1187. X    while (1)
  1188. X    {
  1189. X        tread = reed;
  1190. X        select(NOFILE, &tread, &other, &other, 0);
  1191. X        if (FD_ISSET(old, &tread))
  1192. X            break;
  1193. X        while (firstfd = ffs(tread))
  1194. X        {
  1195. X            killfd(--firstfd);
  1196. X            close(firstfd);
  1197. X            FD_CLR(firstfd, &tread);
  1198. X            FD_CLR(firstfd, &reed);
  1199. X        }
  1200. X    }
  1201. X    return( accept(old, 0, 0) );
  1202. X}
  1203. X
  1204. X
  1205. X/*
  1206. X * Get an input line from a file descriptor.  This is probably very slow.
  1207. X * Since it's only called once, though...
  1208. X */
  1209. Xgetline(fd, buf, len)
  1210. Xint fd, len;
  1211. Xchar *buf;
  1212. X{
  1213. X    int    index = 0;
  1214. X    char    c;
  1215. X
  1216. X    while (read(fd, &c, 1) == 1)
  1217. X    {
  1218. X        if (c == '\n')
  1219. X            break;
  1220. X
  1221. X        if (c == '\r')
  1222. X            continue;
  1223. X
  1224. X        if (index < len)
  1225. X            buf[index++] = c;
  1226. X    }
  1227. X
  1228. X    buf[index] = 0;
  1229. X    return index;
  1230. X}
  1231. X
  1232. X
  1233. X/*
  1234. X * Handle a user request.  This will either be "REGISTER" or some
  1235. X * user-defined function.
  1236. X */
  1237. Xhandle(fd, string)
  1238. Xint fd;
  1239. Xchar *string;
  1240. X{
  1241. X    struct service *cur;
  1242. X    char user[16];
  1243. X
  1244. X/*
  1245. X * If a subserver wants to register itself, grab service
  1246. X * names from it until it outputs an empty line.
  1247. X */
  1248. X    if (!strcmp(string, "REGISTER"))
  1249. X    {
  1250. X        char name[20];
  1251. X
  1252. X        if (! getline(fd, users[fd], 15))
  1253. X            return 1;
  1254. X
  1255. X        while (getline(fd, name, 19))
  1256. X        {
  1257. X            cur = (struct service *)malloc(sizeof(*cur));
  1258. X            strcpy(cur->name, name);
  1259. X            cur->fd = fd;
  1260. X            cur->next = list;
  1261. X            list = cur;
  1262. X        }
  1263. X        return 0;    /* Keep file descriptor open */
  1264. X    }
  1265. X
  1266. X    getline(fd, user, 15);
  1267. X
  1268. X    if (!strcmp(string, "LIST"))
  1269. X    {
  1270. X        char buf[80];
  1271. X
  1272. X        write(fd, "Username\tService\n--------\t-------\n", 34);
  1273. X
  1274. X        for (cur = list; cur; cur = cur->next)
  1275. X        {
  1276. X            if (user[0] && strcmp(user, users[cur->fd]))
  1277. X                continue;
  1278. X            sprintf(buf, "%-8s\t%s\n", users[cur->fd], cur->name);
  1279. X            write(fd, buf, strlen(buf));
  1280. X        }
  1281. X        return 1;
  1282. X    }
  1283. X
  1284. X    for (cur = list; cur; cur=cur->next)
  1285. X        if (! strcmp(string, cur->name))
  1286. X            if ((! user[0]) || (! strcmp(user, users[cur->fd])))
  1287. X                break;
  1288. X
  1289. X    if (! cur)
  1290. X    {
  1291. X        write(fd, NOSERV, sizeof(NOSERV));
  1292. X        return 1;
  1293. X    }
  1294. X
  1295. X    write(cur->fd, string, 20);
  1296. X
  1297. X    shuffle(cur->fd, fd);
  1298. X
  1299. X    return 1;
  1300. X}
  1301. X
  1302. Xsigchld()
  1303. X{
  1304. X    wait(0);
  1305. X}
  1306. X
  1307. X/*
  1308. X * Kill all entries in the linked list with a certain file
  1309. X * descriptor.
  1310. X */
  1311. Xkillfd(fd)
  1312. Xint fd;
  1313. X{
  1314. X    struct service *cur, *temp;
  1315. X
  1316. X    while (list && list->fd == fd)
  1317. X    {
  1318. X        temp = list->next;
  1319. X        free(list);
  1320. X        list = temp;
  1321. X    }
  1322. X
  1323. X    if (list)
  1324. X        for (cur = list; cur; cur = cur->next)
  1325. X            while (cur->next && cur->next->fd == fd)
  1326. X            {
  1327. X                temp = cur->next;
  1328. X                cur->next = cur->next->next;
  1329. X                free(temp);
  1330. X            }
  1331. X}
  1332. X
  1333. X
  1334. X/*
  1335. X * This is the kludgy part.  We want to effectively connect the
  1336. X * client and the appropriate subserver.  Since there's no way to
  1337. X * connect two sockets together, we have to fork off a child and
  1338. X * sit there shuffling bytes back and forth between the two file
  1339. X * descriptors.  When one of them shuts down, we shut the other one
  1340. X * down and die.
  1341. X *
  1342. X * For now, since only one client can be talking to each subserver
  1343. X * at a given time, we erase all the subserver's services from the
  1344. X * service list.  It will reconnect when it's done.
  1345. X */
  1346. X#ifndef MIN
  1347. X#define MIN(x,y)    (((x)>(y))?(y):(x))
  1348. X#endif
  1349. X
  1350. Xshuffle(subsrv, client)
  1351. Xint subsrv, client;
  1352. X{
  1353. X    int        fd;
  1354. X    fd_set        reed, rite, except;
  1355. X    extern void    quit();
  1356. X
  1357. X    killfd(subsrv);
  1358. X
  1359. X    if (fork())
  1360. X    {
  1361. X        close(subsrv);
  1362. X        return;
  1363. X    }
  1364. X
  1365. X    for (fd = 0; fd < NOFILE; fd++)
  1366. X        if (fd != client && fd != subsrv)
  1367. X            close(fd);
  1368. X
  1369. X    FD_ZERO(&reed);
  1370. X    FD_SET(client, &reed);
  1371. X    FD_SET(subsrv, &reed);
  1372. X    FD_ZERO(&rite);
  1373. X    except = reed;
  1374. X
  1375. X    fcntl(client, F_SETOWN, getpid());
  1376. X    fcntl(subsrv, F_SETOWN, getpid());
  1377. X/*    fcntl(client, F_SETFL, FNDELAY);
  1378. X    fcntl(subsrv, F_SETFL, FNDELAY);
  1379. X*/
  1380. X
  1381. X    signal(SIGURG, quit);
  1382. X    signal(SIGPIPE, quit);
  1383. X
  1384. X    while (1)
  1385. X    {
  1386. X        fd_set    tread, twrite, texcept;
  1387. X        int    numbytes, bsize, numread, zero = 0;
  1388. X        char    buf[4096];
  1389. X
  1390. X        tread = reed;
  1391. X        twrite = rite;
  1392. X        texcept = except;
  1393. X
  1394. X        select(NOFILE, &tread, &twrite, &texcept, (void *)0);
  1395. X
  1396. X        if (FD_ISSET(subsrv, &tread))
  1397. X        {
  1398. X            ioctl(subsrv, FIONREAD, &numbytes);
  1399. X            bsize = MIN(numbytes, sizeof(buf));
  1400. X            numread = read(subsrv, buf, bsize);
  1401. X            if (numread < 0 && errno != EWOULDBLOCK)
  1402. X            {
  1403. X                perror("subsrv");
  1404. X                exit(0);
  1405. X            }
  1406. X            if (! numread)
  1407. X            {
  1408. X                shutdown(client, 1);
  1409. X                shutdown(subsrv, 0);
  1410. X                FD_CLR(subsrv, &reed);
  1411. X            }
  1412. X            else
  1413. X                write(client, buf, numread);
  1414. X        }
  1415. X
  1416. X        if (FD_ISSET(client, &tread))
  1417. X        {
  1418. X            ioctl(client, FIONREAD, &numbytes);
  1419. X            bsize = MIN(numbytes, sizeof(buf));
  1420. X            numread = read(client, buf, bsize);
  1421. X            if (numread < 0 && errno != EWOULDBLOCK)
  1422. X            {
  1423. X                perror("client");
  1424. X                exit(0);
  1425. X            }
  1426. X            if (! numread)
  1427. X            {
  1428. X                shutdown(client, 0);
  1429. X                shutdown(subsrv, 1);
  1430. X                FD_CLR(client, &reed);
  1431. X            }
  1432. X            else
  1433. X                write(subsrv, buf, numread);
  1434. X        }
  1435. X
  1436. X/* If both sides were shut down, leave. */
  1437. X        if (! (FD_ISSET(client, &reed) || FD_ISSET(subsrv, &reed)))
  1438. X        {
  1439. X            close(client);
  1440. X            close(subsrv);
  1441. X            exit(0);
  1442. X        }
  1443. X
  1444. X        if (FD_ISSET(client, &texcept) || FD_ISSET(subsrv, &texcept))
  1445. X        {
  1446. X            close(client);
  1447. X            close(subsrv);
  1448. X            exit(0);
  1449. X        }
  1450. X    }
  1451. X}
  1452. X
  1453. Xvoid quit()
  1454. X{
  1455. X    exit(0);
  1456. X}
  1457. X
  1458. SHAR_EOF
  1459. chmod 0600 supersrv.c || echo "restore of supersrv.c fails"
  1460. exit 0
  1461.  
  1462. -- 
  1463. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  1464.