home *** CD-ROM | disk | FTP | other *** search
- From decwrl!ucbvax!tut.cis.ohio-state.edu!mailrus!cornell!batcomputer!itsgw!steinmetz!uunet!allbery Fri Mar 24 22:24:26 PST 1989
- Article 819 of comp.sources.misc:
- Path: decwrl!ucbvax!tut.cis.ohio-state.edu!mailrus!cornell!batcomputer!itsgw!steinmetz!uunet!allbery
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Newsgroups: comp.sources.misc
- Subject: v06i054: PSERV sample programs
- Message-ID: <8808112056.AA16787@ACC-SB-UNIX.ARPA>
- Date: 7 Mar 89 02:49:39 GMT
- Sender: allbery@uunet.UU.NET
- Reply-To: lars@ACC-SB-UNIX.ARPA (Lars J Poulsen)
- Lines: 833
- Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 6, Issue 54
- Submitted-by: lars@ACC-SB-UNIX.ARPA (Lars J Poulsen)
- Archive-name: pserv
-
- PSERV - a sample piece of functional TCP/IP Berkeley socket programming.
-
- Every so often, programmers new to socket programming ask for working
- examples. I will give you this small example to play with.
-
- This program is a minimal remote spooling package, intended to solve
- a personal problem: I use every day two VMS systems and a Unix system.
- In my work area we have a LaserWriter connected to the Unix system,
- but I have to ride a sloooow elevator two floors to get to a VMS printer.
-
- I really wanted to write a small "lpd" client, but found that this
- would require the cooperation of system managers on both machines, since
- (1) LPD will only accept commands from known hosts
- (2) LPD will only accept connections from privileged ports (<1024)
- and the Wollongong VMS package enforces this also; you need
- system privileges to get a low-numbered port on WIN/TCP.
-
- So I decided to write my own mini protocol. This program illustrates
- the basic mechanism used by any server/client pair, and is small enough
- to dink around with fairly safely. [After all, if the system lets an
- unprivileged user do it, it must be safe :-) ?]
-
- The client runs un 4.3BSD or VMS/WIN/TCP; the server runs on 4.3BSD.
-
- Enjoy.
-
- / Lars Poulsen
- ACC Customer Service
- --------------------------------- Cut Here --------------------------------
- # This is a shell archive. Remove anything before this line
- # then unpack it by saving it in a file and typing "sh file"
- # (Files unpacked will be owned by you and have default permissions).
- # This archive contains the following files:
- # ./copytoheap.c
- # ./filename.c
- # ./listen.c
- # ./rmtprint.c
- # ./strpak.c
- # ./Makefile
- #
- if `test ! -s ./copytoheap.c`
- then
- echo "writing ./copytoheap.c"
- cat > ./copytoheap.c << '\Rogue\Monster\'
- static char rcsid[] = "$Header: copytoheap.c,v 3.5 87/05/26 14:16:25 lars Production $";
-
- #include <stdio.h>
-
- extern char *malloc();
- extern int strlen();
-
- char *
- copytoheap(string)
- char *string;
- {
- char *temp;
- int size;
- if (string == NULL) return NULL;
- size = strlen(string)+1;
- if (size > 64*1024)
- {
- fprintf(stderr,"copytoheap: object too large (%d bytes)\n",size);
- exit(-1);
- }
- temp = malloc(size);
- strcpy(temp,string);
- return temp;
- }
- \Rogue\Monster\
- else
- echo "will not over write ./copytoheap.c"
- fi
- if `test ! -s ./filename.c`
- then
- echo "writing ./filename.c"
- cat > ./filename.c << '\Rogue\Monster\'
- static char rcsid[] = "$Header: filename.c,v 3.3 88/08/07 19:00:37 lars Exp $";
-
- /* filename.c - extract the FILENAME part from a pathname string
- * written by Lars Poulsen <lars@acc.arpa>
- * for the ACC PSR system
- *
- * $Header: filename.c,v 3.3 88/08/07 19:00:37 lars Exp $
- *
- * $Log: filename.c,v $
- * Revision 3.3 88/08/07 19:00:37 lars
- * handle vms-filenames also:
- * if name contains a slash, it's a unix name.
- * else, if it has "]" or ":", cut off what's before those.
- *
- * Revision 3.2 87/05/18 13:36:19 lars
- * First stable version of PSR after pf_get/pf_write went in
- *
- * Revision 3.1 87/05/16 21:16:55 lars
- * At end of splitting up (First stable version)
- *
- */
- extern char *rindex();
-
- char *
- filename(path)
- char *path;
- {
- char *ptr;
-
- /* first deal with unix filenames */
- ptr = rindex(path, '/');
- if (ptr)
- return ++ptr;
- /* now deal with vmsisms */
-
- ptr = rindex(path, ']');
- if (ptr)
- return ++ptr;
- ptr = rindex(path, ':');
- if (ptr)
- return ++ptr;
- return path;
- }
- \Rogue\Monster\
- else
- echo "will not over write ./filename.c"
- fi
- if `test ! -s ./listen.c`
- then
- echo "writing ./listen.c"
- cat > ./listen.c << '\Rogue\Monster\'
- /* listen.c - a server daemon to match "rmtprint"
- *
- * Written by Lars Poulsen <lars@acc-sb-unix.arpa>
- * August 1988
- *
- * This is a simple example of a TCP based network server.
- */
- #include <ctype.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <pwd.h>
-
- #define MY_PORT 12345
- #define ANY_PORT 0
- #define DEFPRT "mac7"
- #define FORKING 1
-
- extern int errno;
-
- extern char *asctime();
- extern struct tm *localtime();
- extern char *mktemp();
- extern long time();
-
- extern char *copytoheap();
- extern char *filename();
-
- char *what_alarm = NULL;
- char temp_name[40];
- int forking = 0;
- extern char *home_directory();
- extern exit_server();
- extern timeout();
- extern wait_child();
-
- char *
- tstamp()
- {
- long time_now;
- char *temp;
-
- time_now = time(0);
- temp = asctime(localtime(&time_now)) + 4;
- temp[12] = 0;
- return temp;
- }
-
- main(argc, argv)
- int argc;
- char *argv[];
-
- {
- int s,
- cs;
- struct sockaddr_in my_name;
- struct sockaddr_in any_name;
- struct sockaddr_in his_name;
- int idsw;
- int his_addr_len;
-
- forking = FORKING; /* done this way in case it is an expression */
-
- signal(SIGALRM, timeout);
- signal(SIGCHLD, wait_child);
- signal(SIGTERM, exit_server);
- printf("%s Print server starting - defprt = %s\n", tstamp(), DEFPRT);
- fflush(stdout);
-
- s = socket(AF_INET, SOCK_STREAM, 0); /* protocol #0 is IP */
- if (0)
- printf("tcp: got socket fd=%d (Hex: %x)\n", s, s);
-
- bzero((char *) &my_name, sizeof(my_name));
- my_name.sin_family = AF_INET;
- my_name.sin_port = htons(MY_PORT);
- my_name.sin_addr.s_addr = INADDR_ANY;
-
- idsw = bind(s, &my_name, sizeof(my_name));
- if (idsw != 0)
- printf("tcp: bind returned %d - errno = %d\n", idsw, errno);
-
- bzero((char *) &any_name, sizeof(any_name));
- any_name.sin_family = AF_INET;
- any_name.sin_port = htons(ANY_PORT);
- any_name.sin_addr.s_addr = INADDR_ANY;
- idsw = listen(s, 0);
- if (idsw != 0)
- printf("listen: listen returned %d - errno = %d\n", idsw, errno);
- next_in_file:
- alarm(0);
- bzero((char *) &his_name, sizeof(his_name));
- his_addr_len = sizeof(his_name);
- cs = accept(s, &his_name, &his_addr_len);
- if (cs < 0)
- {
- printf("listen: accept failed, errno = %d his_addr_len = %d\n",
- errno, his_addr_len);
- fflush(stdout);
- exit(errno);
- }
- process_a_file(cs);
- goto next_in_file;
- }
-
- process_a_file(cs)
- {
- int bcnt;
- char buffer[512];
- int ofd;
- char printer[20],
- rmtuser[40],
- rmtfile[80];
- int file_size = 0;
- int idsw;
-
- if (forking)
- {
- idsw = fork();
- if (idsw < 0)
- {
- printf("%s listen: Fatal error - fork() failed with error = %d\n",
- tstamp(), -idsw);
- exit(-idsw);
- }
- if (idsw != 0) /* parent listens for next connection */
- {
- close(cs);
- return;
- }
- }
- what_alarm = "Reading Command Line";
- alarm(30);
-
- if (get_command(cs, printer, rmtuser, rmtfile) != 0)
- {
- printf("%s Bad incoming commnd %s %s %s\n",
- tstamp(), printer, rmtuser, rmtfile);
- fflush(stdout);
- close(cs);
- return;
- }
- printf("%s Received connection %s %s %s\n",
- tstamp(), printer, rmtuser, rmtfile);
- fflush(stdout);
-
- ofd = open_out_file(printer, rmtuser, rmtfile);
-
- what_alarm = "Receiving File";
- alarm(30);
- while (bcnt = recv(cs, buffer, sizeof(buffer), 0))
- {
- write(ofd, buffer, bcnt);
- alarm(30);
- file_size += bcnt;
- if (buffer[bcnt - 1] == 0)
- break;
- }
- close(cs);
- printf("%s Received %d bytes for %s %s %s\r\n",
- tstamp(), file_size, printer, rmtuser, rmtfile);
- fflush(stdout);
-
- what_alarm = "Printing File";
- alarm(5);
- if (strcmp(printer, "save") != 0)
- {
- check_printer(printer, DEFPRT);
- sprintf(buffer, "lpr -P %s -r -s %s", printer, temp_name);
- idsw = system(buffer);
- if (idsw)
- {
- printf("listen: lpr command returned %d\n", idsw);
- fflush(stdout);
- }
- }
- if (forking)
- exit(0);
- else
- return;
- }
-
- get_command(nfd, printer, rmtuser, rmtfile)
- int nfd;
- char *printer,
- *rmtuser,
- *rmtfile;
- {
- char c,
- *p;
- extern char readch();
-
- p = printer;
- while (isalnum(c = readch(nfd)))
- *(p++) = c;
- *p = 0;
- if (c != ' ')
- goto cmd_error;
-
- p = rmtuser;
- while (isalnum(c = readch(nfd)))
- *(p++) = c;
- *p = 0;
- if (c != ' ')
- goto cmd_error;
-
- p = rmtfile;
- while ((c = readch(nfd)) && (c > ' '))
- *(p++) = c;
- if (!isspace(c))
- goto cmd_error; /* space or \n */
- *p = 0;
- return 0;
- cmd_error:
- printf("syntax error in print command *p = %d\n", *p);
- printf("printer = %s user = %s filename = %s\n",
- printer, rmtuser, rmtfile);
- return -1;
- }
- char
- readch(fd)
- {
- char buf;
-
- begin:
- if (recv(fd, &buf, 1, 0) != 1)
- {
- printf("readch(%d) got error %d\n", fd, errno);
- return 0;
- }
- if (buf == 0)
- goto begin;
- return buf;
- }
-
- check_printer(printer, defprt)
- char *printer,
- *defprt;
- {
- char fname[80];
- int fd;
- int err;
-
- /* The following check is bad: If the device exists and is busy,
- we will wait forever for the daemon to exit... */
- if (0)
- {
- sprintf(fname, "/dev/%s", printer);
- errno = 0;
- fd = open(fname, 0, 0);
- err = errno;
- close(fd);
- if (errno == ENOENT)
- goto failed;
- }
- sprintf(fname, "/usr/spool/%s", printer);
- errno = 0;
- fd = open(fname, 0, 0);
- err = errno;
- close(fd);
- if (errno)
- goto failed;
-
- return;
- failed:
- printf("%s Failed to open %s - errno = %d\n",
- tstamp, fname, err);
- printf("%s %s is not a valid printer, %s substituted\n",
- tstamp, printer, defprt);
- fflush(stdout);
- strcpy(printer, defprt);
- return;
- }
-
- /* alarm clock is used to debug hang's */
- timeout()
- {
- printf("%s Fatal Timeout While %s\n", tstamp(), what_alarm);
- exit(2);
- }
-
- /* dummy child handler - just get rid of <defunct> child */
- wait_child()
- {
- wait(0);
- }
-
- /* clean exit on a simple "kill" */
- exit_server()
- {
- printf("%s Received SIGTERM - exiting\n", tstamp());
- exit(0);
- }
-
- open_out_file(printer, rmtuser, rmtfile)
- char *printer,
- *rmtuser,
- *rmtfile;
- {
- int ofd;
- char *directory;
-
- rmtfile = filename(rmtfile);
- if ((directory = home_directory(rmtuser)) == NULL)
- directory = "/tmp";
- sprintf(temp_name, "%s/%s", directory, rmtfile);
- if ((ofd = open(temp_name, 0) < 0) && errno == ENOENT)
- /* no such file exists */
- ofd = creat(temp_name, 0644);
- if (ofd >= 0)
- return ofd;
-
- close(ofd);
-
- strcpy(temp_name, "/tmp/spoolXXXXXX");
- (void) mktemp(temp_name);
- ofd = creat(temp_name, 0644);
- return ofd;
- }
- char *
- home_directory(name)
- char *name;
- {
- struct passwd *pw;
- char *hd;
-
- setpwent();
- for (pw = getpwent(); pw; pw = getpwent())
- {
- if (strcmp_nocase(pw->pw_name, name) == 0)
- break;
- }
- if (pw)
- hd = copytoheap(pw->pw_dir);
- else
- hd = NULL;
- if (forking && !geteuid())
- setuid(pw->pw_uid); /* try to set this child to the right userid */
- endpwent();
- return hd;
- }
- \Rogue\Monster\
- else
- echo "will not over write ./listen.c"
- fi
- if `test ! -s ./rmtprint.c`
- then
- echo "writing ./rmtprint.c"
- cat > ./rmtprint.c << '\Rogue\Monster\'
- #include <stdio.h>
- #include <signal.h>
- #ifdef VAXC
- #include "twg$tcp:[netdist.include.sys]types.h"
- #include "twg$tcp:[netdist.include]errno.h"
- #include "twg$tcp:[netdist.include.sys]socket.h"
- #include "twg$tcp:[netdist.include.netinet]in.h"
- #include "twg$tcp:[netdist.include]netdb.h"
- #else
- #include <sys/types.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #define uerrno errno
- #endif
-
- #define MY_PORT 0
- #define HIS_PORT 12345
-
- extern int uerrno;
- extern timeout();
- char *what_alarm = "Name Service";
-
- main(argc, argv)
- int argc;
- char *argv[];
-
- {
- int s;
- struct sockaddr_in my_name;
- struct sockaddr_in his_name;
- int idsw;
- int namelen;
- struct hostent *gethostbyname(),
- *salt_ent;
- u_long *found_addr;
- struct servent *sp;
- char buffer[512];
- int bcnt;
- int ifd;
- char cmdbuf[80];
- int null = 0;
-
- if (argc != 4)
- {
- printf("usage: rmtprint host printer file\n");
- exit(1);
- }
- s = socket(AF_INET, SOCK_STREAM, 0); /* protocol #0 is IP */
- if (0)
- printf("tcp: got socket fd=%d (Hex: %x)\n", s, s);
-
- bzero((char *) &my_name, sizeof(my_name));
- my_name.sin_family = AF_INET;
- my_name.sin_port = MY_PORT;
- my_name.sin_addr.s_addr = INADDR_ANY;
-
- idsw = bind(s, &my_name, sizeof(my_name));
- if (idsw != 0)
- printf("tcp: bind returned %d - uerrno = %d\n", idsw, uerrno);
-
- signal(SIGALRM, timeout);
- alarm(30);
- salt_ent = gethostbyname(argv[1]);
- if (salt_ent) found_addr = (u_long *)salt_ent->h_addr_list[0];
- if ((salt_ent == NULL) || (found_addr == 0))
- {
- printf("rmtprint: %s is not a known host\n", argv[1]);
- exit(2);
- }
- bzero((char *) &his_name, sizeof(his_name));
- his_name.sin_family = AF_INET;
- sp = getservbyname("rmtprint", "tcp");
- if (sp)
- his_name.sin_port = sp->s_port;
- else
- his_name.sin_port = htons(HIS_PORT);
- bcopy(salt_ent->h_addr_list[0], &his_name.sin_addr, salt_ent->h_length);
-
- what_alarm = "Connection Request";
- alarm(30);
- idsw = connect(s, &his_name, sizeof(my_name));
- if (idsw != 0)
- {
- idsw = uerrno;
- printf("rmtprint: Connect to %s port %d returned Unix error %d\n",
- argv[1], ntohs(his_name.sin_port), idsw);
- if (idsw == 61)
- printf("rmtprint: Connection refused by %s - server not running ?\n",
- argv[1]);
- exit(2);
- }
- what_alarm = "Sending Command Line";
- alarm(30);
- sprintf(cmdbuf, "%s %s %s\n", argv[2], getenv("USER"), argv[3]);
- send(s, cmdbuf, strlen(cmdbuf), 0);
- what_alarm = "Sending File";
- ifd = open(argv[3], 0, 0);
- if (ifd < 0)
- {idsw = errno;
- printf("rmtprint: Failed to open %s errno = %d\n", argv[3], idsw);
- exit(idsw);
- }
- bcnt = read(ifd, buffer, sizeof(buffer));
- while (bcnt > 0)
- {
- alarm(30);
- send(s, buffer, bcnt, 0);
- bcnt = read(ifd, buffer, sizeof(buffer));
- }
- if (errno) printf("rmtprint: read ended with errno = %d\n",errno);
- close(ifd);
- sleep(1);
- send(s, &null, 1, 0);
- recv(s, buffer, sizeof(buffer), 0);
- close(s);
- exit(1);
- }
- timeout()
- {
- printf("rmtprint: Fatal timeout during %s\n", what_alarm);
- exit(4);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./rmtprint.c"
- fi
- if `test ! -s ./strpak.c`
- then
- echo "writing ./strpak.c"
- cat > ./strpak.c << '\Rogue\Monster\'
- static char rcsid[] = "$Header: strpak.c,v 1.10 88/08/07 20:18:49 lars Exp $";
- #include <stdio.h>
- #include <ctype.h>
- extern char *index();
- extern char *malloc();
-
- char *
- str_firstline(multi_field)
- char *multi_field;
- {
- char *end_of_line;
- static int i = 0;
- static char buf[4][80];
- i = (i+1)&3;
- strncpy(buf[i], multi_field, 80);
- if (end_of_line = index(buf[i],'\n')) *end_of_line = 0;
- return buf[i];
- }
-
- char *
- str_firstword(multi_field)
- char *multi_field;
- {
- char *end_of_line;
- static int i = 0;
- static char buf[4][80];
- i = (i+1)&3;
- strncpy(buf[i], multi_field, 80);
- for (end_of_line = buf[i]; isalpha(*end_of_line); end_of_line++);
- *end_of_line = 0;
- return buf[i];
- }
-
- char *str_join3(a,b,c)
- char *a, *b, *c;
- {
- int size = strlen(a) + strlen(b) + strlen(c) +1;
- char *new;
- char *pp;
-
- pp = new = malloc(size);
- if (new == NULL) return NULL;
- if (a != NULL) while (*a) *(pp++) = *(a++);
- if (b != NULL) while (*b) *(pp++) = *(b++);
- if (c != NULL) while (*c) *(pp++) = *(c++);
- *pp = 0;
- return new;
- }
-
- int str_lines(string)
- char *string;
- {
- char *pp = string;
- char c;
- int count = 1;
-
- if (string == NULL) return 0;
- if (strlen(string) == 0) return 0;
-
- while(c = *pp++)
- if (c == '\n')
- count ++;
- return count;
- }
-
- int str_longest(string)
- char *string;
- {
- int lines, longest = 0, total;
- int thislen;
- char *thisline, *nextline;
-
- if (string == NULL) return 0;
- if ((total = strlen(string)) == 0) return 0;
- lines = str_lines(string);
- thisline = string;
- while (--lines)
- {
- nextline = index(thisline,'\n') + 1;
- if (nextline == NULL)
- {
- fprintf(stderr,"str_longest: Program bug !!\n");
- exit(-1);
- }
- thislen = nextline - thisline - 1;
- if (thislen > longest) longest = thislen;
- thisline = nextline;
- }
- thislen = strlen(thisline);
- if (thislen > longest) longest = thislen;
- return longest;
- }
-
- char *
- str_trim(string)
- char *string;
- {
- char *pp;
- int length;
- static int i = 0;
- static char buf[4][80];
-
- if (string == NULL) return NULL;
- i = (i+1)&3;
-
- pp = string + strlen(string) - 1;
- while ((*pp == 0) || (*pp == ' ') || (*pp == '\n')
- || (*pp == '\t') || (*pp == '_'))
- pp--;
- length = pp - string + 1;
- if (length <= 0) return NULL;
- strncpy(buf[i],string, length);
- buf[i][length] = 0;
- return buf[i];
- }
-
- #define MAXINIT 3
- char *
- str_initials(name)
- char *name;
- {
- static char init[4][MAXINIT + 1];
- static int i = 0;
- int j;
- char *p;
- char c;
-
- if (name == NULL)
- return "";
- if (strlen(name) == 0)
- return "";
-
- i = (++i) & 3;
- j = 0;
- p = name;
-
- while ((c = *(p++)) && (j < MAXINIT))
- if (isupper(c))
- init[i][j++] = c;
- init[i][j] = 0;
- return init[i];
- }
-
- /*
- * Compare strings (at most n bytes): s1>s2: >0 s1==s2: 0 s1<s2: <0
- */
-
- strncmp_nocase(s1, s2, n)
- register char *s1, *s2;
- register n;
- {
- register char c1, c2;
-
- while (--n >= 0)
- {
- c1 = *s1++;
- if (c1 == 0) return 0;
- if (isupper(c1)) c1 = tolower(c1);
-
- c2 = *s2++;
- if (c2 == 0) return 0;
- if (isupper(c2)) c2 = tolower(c2);
-
- if (c1 != c2) break;
- }
- return(n<0 ? 0 : c1 - c2);
- }
- strcmp_nocase(s1, s2)
- register char *s1, *s2;
- {
- register char c1, c2;
-
- while (1)
- {
- c1 = *s1++;
- if (isupper(c1)) c1 = tolower(c1);
- c2 = *s2++;
- if (isupper(c2)) c2 = tolower(c2);
-
- if (c1 == 0) break;
- if (c2 == 0) break;
- if (c1 != c2) break;
- }
- return(c1 - c2);
- }
- \Rogue\Monster\
- else
- echo "will not over write ./strpak.c"
- fi
- if `test ! -s ./Makefile`
- then
- echo "writing ./Makefile"
- cat > ./Makefile << '\Rogue\Monster\'
- all: listen rmtprint
-
- listen: listen.o copytoheap.o filename.o strpak.o
- cc -o listen -g listen.o copytoheap.o filename.o strpak.o
-
- rmtprint: rmtprint.o
- cc -o rmtprint -g rmtprint.o
-
- listen.o: listen.c
-
- rmtprint.o: rmtprint.c
-
- copytoheap.o: copytoheap.c
-
- filename.o: filename.c
-
- strpak.o: strpak.c
- \Rogue\Monster\
- else
- echo "will not over write ./Makefile"
- fi
- echo "Finished archive 1 of 1"
- # if you want to concatenate archives, remove anything after this line
- exit
-
-
-