home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume6
/
pserv
< prev
next >
Wrap
Text File
|
1989-03-06
|
19KB
|
840 lines
Newsgroups: comp.sources.misc
From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Message-Id: <8808112056.AA16787@ACC-SB-UNIX.ARPA>
Subject: v06i054: PSERV sample programs
Reply-To: lars@ACC-SB-UNIX.ARPA (Lars J Poulsen)
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