/* * Simple faucet program -- take a command-line provided number of connections * from the net and dump output. Purely sequential. * * Equivalent to * sh -c "netd -c1 -p 5103 -- /bin/sh -c 'cat 1>&3' 3>&1" */ #ifndef lint static char *copyright = "\n\ \n\ Copyright (c) 1994 by Bennet Yee.\n\ \n\ This material was developed by the author. Permission to copy this\n\ software, to redistribute it, and to use it for any purpose is hereby\n\ granted, subject to the following five restrictions.\n\ \n\ 1. Any copy made of this software must include this copyright notice in\n\ full.\n\ \n\ 2. All materials containing this software or derivatives thereof must\n\ provide this software in source form or provide a means of obtaining\n\ this software in source form; no fees may be charged for this software\n\ except those for covering media costs and handling.\n\ \n\ 3. All materials developed as a consequence of the use of this software\n\ shall duly acknowledge such use, in accordance with the usual standards\n\ of acknowledging credit in academic research.\n\ \n\ 4. The author makes no warranty or representation that the operation\n\ of this software will be error-free, and the author is under no\n\ obligation to provide any services, by way of maintenance, update, or\n\ otherwise.\n\ \n\ 5. In conjunction with products arising from the use of this material,\n\ there shall be no use of the names of the author, of Carnegie-Mellon\n\ University, nor of any adaptation thereof in any advertising,\n\ promotional, or sales literature without prior written consent from the\n\ author and Carnegie-Mellon University in each case.\n\ \n\ If you have questions, you can contact the author at bsy@cs.cmu.edu\n\ \n\ Users of this software is requested to make their best efforts (a) to\n\ return to the author any improvements or extensions that they make, so\n\ that these may be included in future releases; (b) to document clearly\n\ any improvements or extensions made to this software; and (c) to inform\n\ the author of noteworthy uses of this software. Any improvements or\n\ extensions to this software may be placed under different copyright\n\ restrictions by the author of those improvements or extensions. That\n\ those improvements or extensions be placed under the same copyright as\n\ this software is encouraged.\n\ "; #endif /* lint */ #include #include #include #include #include #include #include #include "comp_environ.h" extern int getopt(int,char *const *,const char *), optind; extern char *optarg; char *me; usage() { fprintf(stderr, "Usage: %s [-c count] [-p port] [-u unix-socket-path] [-P]\n" "\t-c -- number of connections before exiting\n" "\t-p -- TCP port number for socket (network access)\n" "\t-u -- Unix domain path for socket (host-only access)\n" "\t-P -- automatically chose TCP port number and\n" "\t print it to stderr, and then run in background\n",me); } main(int ac, char **av) { int opt; int32 port = -1; uint16 uport; char *udpath = 0; int count = 1, auto_port = 0; struct sockaddr_in name,sa; struct sockaddr *ud_sa; int ms,s,ud_sz,sz; char *buf,*bufin,*bufout; int pgsz,bufuse,lowmask; int nr,nw,nnw; extern char *strrchr(const char *,char); #if defined(_POSIX_VERSION) pgsz = sysconf(_SC_PAGESIZE); #elif __hppa pgsz = NBPG; #else pgsz = getpagesize(); #endif if (!(me = strrchr(av[0],'/'))) me = av[0]; else ++me; while ((opt = getopt(ac,av,"c:p:u:P")) != EOF) switch (opt) { case 'c': count = atoi(optarg); break; case 'p': port = atoi(optarg); break; case 'u': udpath = optarg; break; case 'P': auto_port = 1; break; default: usage(); exit(1); } /* * We try to make I/O buffer to be page aligned, so that kernels * that understand page swapping for I/O can do so. This can * avoid the copyin/out overhead. Network input will probably need * copying from mbuf's to user buffers anyhow (most implementations) * but at least the output can be optimized to mark-as-copy-on-write * at the write syscall, and then discard/swap the clean (shadow) page * at the read syscall. */ if ((pgsz-1)&pgsz) { fprintf(stderr,"%s: WARNING: Internal Error: system page not a power of two.\n",me); bufin = buf = malloc(bufuse = pgsz); } else { lowmask = (pgsz-1)^pgsz; lowmask ^= (lowmask+1)>>1; buf = malloc(bufuse = 5*pgsz); if (((unsigned long) buf) & lowmask) { /* find next page boundary */ bufin = (char *) (((unsigned long) buf) | lowmask); ++bufin; bufuse -= pgsz; } else { bufin = buf; } } if (udpath && (port != -1 || auto_port)) { fprintf(stderr,"%s: TCP port (-p/P) and unix domain path (-u) are mutually exclusive\n",me); usage(); exit(1); } if (!udpath) { if (port != -1 && auto_port) { fprintf(stderr,"%s: TCP port specifier (-p) and automatic port selection (-P) are mutually exclusive\n",me); usage(); exit(1); } if (port == -1 && !auto_port) { fprintf(stderr,"%s: no TCP port specified (-p) and automatic port selection not enabled (-P)\n",me); usage(); exit(1); } if (port != -1) { if ((uport = port) != port) { fprintf(stderr,"%s: TCP port specifier not a 16-bit value\n",me); usage(); exit(1); } } else { uport = 1024 + getuid(); } if ((ms = socket(PF_INET,SOCK_STREAM,0)) == -1) { perror(me); exit(1); } if (1) { int set = 1; if (setsockopt(ms,SOL_SOCKET,SO_REUSEADDR,(const char *) &set, sizeof(set)) == -1) { perror(me); exit(1); } } memset((char *)&name,0,sizeof(name)); name.sin_family = AF_INET; name.sin_port = htons(uport); while (bind(ms,(struct sockaddr *) &name,sizeof(name)) == -1) { if (auto_port) { uport++; name.sin_port = htons(uport); continue; } else { perror(me); exit(1); } } if (auto_port) { switch (fork()) { case 0: break; case -1: perror(me); exit(1); default: fprintf(stderr,"%d\n",(int) uport); exit(0); } } } else { if ((ms = socket(PF_UNIX,SOCK_STREAM,0)) == -1) { perror(me); exit(1); } ud_sz = sizeof *ud_sa + strlen(udpath) + 1 - sizeof ud_sa->sa_data; if (!(ud_sa = (struct sockaddr *) malloc(ud_sz))) { perror(me); exit(1); } memset(ud_sa,0,ud_sz); strcpy(ud_sa->sa_data,udpath); if (bind(ms,ud_sa,ud_sz) == -1) { perror(me); exit(1); } } /* if count > SOMAXCONN, does kernel silently ignore? */ if (listen(ms,count) == -1) { perror(me); exit(1); } while (--count >= 0) { sz = sizeof sa; s = accept(ms,(struct sockaddr *) &sa,&sz); while ((nr = read(s,bufin,bufuse)) > 0) { bufout = bufin; nw = nr; while (nw) { /* stdout might be network socket */ if ((nnw = write(1,bufin,nw)) < 0) { perror(me); exit(1); } bufout += nnw; nw -= nnw; } } } return 0; }