Thread View: comp.sources.reviewed
1 messages
1 total messages
Started by Steven Grimm
Sat, 01 Jun 1991 03:39
v01i003: supersrv - offer any program as a network service, Part02/02
Author: Steven Grimm
Date: Sat, 01 Jun 1991 03:39
Date: Sat, 01 Jun 1991 03:39
502 lines
11816 bytes
11816 bytes
Submitted-by: Steven Grimm <Steven.Grimm@Eng.Sun.COM>
Posting-number: Volume 1, Issue 3
Archive-name: supersrv/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 2)."
# Contents: supersrv.c
# Wrapped by csr@calvin.doc.ca on Fri May 31 23:28:09 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'supersrv.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'supersrv.c'\"
else
echo shar: Extracting \"'supersrv.c'\" \(8732 characters\)
sed "s/^X//" >'supersrv.c' <<'END_OF_FILE'
X#include "common.h"
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
Xextern int errno;
X
X/*
X * SuperServer.
X *
X * 1.2: REGISTER handler sends QUIT to all old servers running with the same
X * username.
X * 1.3: Fix infinite loop bug
X * Pass client IP address to server
X * 1.4: Services can have descriptions
X */
X
X#define WELCOME "SuperServer -- enter service desired.\n"
X#define NOSERV "Service not offered.\n"
X
Xint thirty;
X
X/*
X * This structure is used to keep the database of available services.
X */
Xstruct service {
X char name[20]; /* Service name */
X char desc[50]; /* Service description */
X int fd; /* File descriptor that offers it */
X struct service *next; /* Next service in list */
X} *list = (struct service *)0;
X
Xchar users[NOFILE][12]; /* user connected to each fd */
X
X/*
X * The peer of the most recent connection.
X */
Xstruct sockaddr_in rcon;
X
Xmain()
X{
X int fd_so, /* Socket() file descriptor */
X fd_co; /* Connected file descriptor */
X short portno; /* Port number to listen on */
X char request[80];
X extern int sigchld();
X
X/*
X * First things first: put ourselves in the background.
X */
X/* if (fork())
X exit(0);*/
X
X portno = SUPERPORT;
X thirty = 30;
X
X/*
X * Set up the server socket on the appropriate port number and listen on it.
X * If we get an address-already-in-use error, silently exit, since we're
X * presumably waiting for the TCP port to be cleared up, and will be executed
X * again by server.
X */
X fd_so = serversock(portno);
X if (fd_so < 0)
X {
X if (errno != EADDRINUSE)
X perror("serversock");
X exit(errno);
X }
X
X (void)listen(fd_so, 5);
X setsockopt(fd_so, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
X fcntl(fd_so, F_SETOWN, getpid());
X
X/*
X * And we'll need to accomodate child processes.
X */
X signal(SIGCHLD, sigchld);
X/*
X * We will catch broken pipes in our main loop, so don't fuss with signals.
X */
X signal(SIGPIPE, SIG_IGN);
X
X/*
X * Now keep accepting connections and interpreting them.
X */
X while (1)
X {
X fd_co = getcon(fd_so);
X
X if (fd_co < 0)
X {
X perror("accept");
X exit(0);
X }
X
X fcntl(fd_co, F_SETOWN, getpid());
X setsockopt(fd_co,SOL_SOCKET,SO_LINGER,&thirty, sizeof(thirty));
X
X write(fd_co, WELCOME, sizeof(WELCOME)-1);
X if (getline(fd_co, request, sizeof(request)-1))
X {
X if (handle(fd_co, request))
X close(fd_co);
X }
X else
X close(fd_co);
X }
X}
X
X/*
X * Get a connection, or handle a disconnected server.
X */
Xgetcon(old)
Xint old;
X{
X struct service *cur;
X fd_set reed, tread, other;
X int fd, size;
X
X FD_ZERO(&reed);
X FD_ZERO(&other);
X
X for (cur = list; cur; cur = cur->next)
X FD_SET(cur->fd, &reed);
X FD_SET(old, &reed);
X
X while (1)
X {
X tread = reed;
X select(NOFILE, &tread, NULL, NULL, NULL);
X if (FD_ISSET(old, &tread))
X break;
X for (fd = 0; fd < NOFILE; fd++)
X if (FD_ISSET(fd, &tread))
X {
X killfd(fd);
X close(fd);
X FD_CLR(fd, &reed);
X }
X }
X size = sizeof(rcon);
X return( accept(old, &rcon, &size) );
X}
X
X
X/*
X * Get an input line from a file descriptor. This is probably very slow.
X * Since it's only called once, though...
X */
Xgetline(fd, buf, len)
Xint fd, len;
Xchar *buf;
X{
X int index = 0;
X char c;
X
X while (read(fd, &c, 1) == 1)
X {
X if (c == '\n')
X break;
X
X if (c == '\r')
X continue;
X
X if (index < len)
X buf[index++] = c;
X }
X
X buf[index] = 0;
X return index;
X}
X
X
X/*
X * Handle a user request. This will either be "REGISTER" or some
X * user-defined function.
X */
Xhandle(fd, string)
Xint fd;
Xchar *string;
X{
X struct service *cur;
X char user[16], hisip[16];
X
X if (string[0] == '\0')
X return 1;
X/*
X * If a subserver wants to register itself, grab service
X * names from it until it outputs an empty line.
X */
X if (!strcmp(string, "REGISTER"))
X {
X char name[70];
X int i;
X
X if (! getline(fd, users[fd], 11))
X return 1;
X
X/*
X * If this user already has servers connected, kill them off.
X */
X for (i = 0; i < NOFILE; i++)
X if (i != fd && ! strcmp(users[i], users[fd]))
X {
X killfd(i);
X write(i, "QUIT\0xxxxxxxxxxxxxxx", 20);
X close(i);
X users[i][0] = '\0';
X }
X
X/*
X * Get service names. If there are descriptions, use those as well.
X */
X while (getline(fd, name, 69))
X {
X char *desc, *index();
X
X#ifdef DEBUG
X printf("supersrv got input '%s'\n", name);
X#endif
X desc = index(name, '\t');
X if (desc != NULL)
X *desc++ = '\0';
X
X cur = (struct service *)malloc(sizeof(*cur));
X strcpy(cur->name, name);
X if (desc != NULL)
X strcpy(cur->desc, desc);
X else
X cur->desc[0] = '\0';
X
X cur->fd = fd;
X cur->next = list;
X list = cur;
X }
X return 0; /* Keep file descriptor open */
X }
X
X getline(fd, user, 15);
X
X/*
X * Print a nicely-formatted list of services. If there aren't any services,
X * print a message to that effect.
X */
X if (!strcmp(string, "LIST"))
X {
X char buf[100], format[20];
X int maxlen = 10;
X#define LISTHEAD "Username Service\n-------- -------\n"
X#define NOSERVS "No services available.\n"
X
X if (list)
X {
X write(fd, LISTHEAD, sizeof(LISTHEAD)-1);
X
X for (cur = list; cur; cur = cur->next)
X if (maxlen < strlen(cur->name))
X maxlen = strlen(cur->name);
X sprintf(format, "%%-12s %%-%ds%%s\n", maxlen + 2);
X
X for (cur = list; cur; cur = cur->next)
X {
X if (user[0] && strcmp(user, users[cur->fd]))
X continue;
X sprintf(buf, format, users[cur->fd], cur->name,
X cur->desc);
X write(fd, buf, strlen(buf));
X }
X }
X else
X write(fd, NOSERVS, sizeof(NOSERVS)-1);
X return 1;
X
X }
X
X for (cur = list; cur; cur=cur->next)
X if (! strcmp(string, cur->name))
X if ((! user[0]) || (! strcmp(user, users[cur->fd])))
X break;
X
X if (! cur)
X {
X write(fd, NOSERV, sizeof(NOSERV));
X return 1;
X }
X
X write(cur->fd, string, 20);
X/*
X * 1.3: Write out the client's IP address (which we know will be in rcon.)
X */
X sprintf(hisip, "%s\n", inet_ntoa(rcon.sin_addr));
X write(cur->fd, hisip, strlen(hisip));
X
X shuffle(cur->fd, fd);
X
X return 1;
X}
X
Xsigchld()
X{
X wait(0);
X}
X
X/*
X * Kill all entries in the linked list with a certain file
X * descriptor.
X */
Xkillfd(fd)
Xint fd;
X{
X struct service *cur, *temp;
X
X while (list && list->fd == fd)
X {
X temp = list->next;
X free(list);
X list = temp;
X }
X
X if (list)
X for (cur = list; cur; cur = cur->next)
X while (cur->next && cur->next->fd == fd)
X {
X temp = cur->next;
X cur->next = cur->next->next;
X free(temp);
X }
X}
X
X
X/*
X * This is the kludgy part. We want to effectively connect the
X * client and the appropriate subserver. Since there's no way to
X * connect two sockets together, we have to fork off a child and
X * sit there shuffling bytes back and forth between the two file
X * descriptors. When one of them shuts down, we shut the other one
X * down and die.
X *
X * For now, since only one client can be talking to each subserver
X * at a given time, we erase all the subserver's services from the
X * service list. It will reconnect when it's done forking off the
X * service.
X */
X#ifndef MIN
X#define MIN(x,y) (((x)>(y))?(y):(x))
X#endif
X
Xshuffle(subsrv, client)
Xint subsrv, client;
X{
X int fd;
X fd_set reed, rite, except;
X extern void quit();
X
X killfd(subsrv);
X
X if (fork())
X {
X close(subsrv);
X return;
X }
X
X for (fd = 0; fd < NOFILE; fd++)
X if (fd != client && fd != subsrv)
X close(fd);
X
X FD_ZERO(&reed);
X FD_SET(client, &reed);
X FD_SET(subsrv, &reed);
X FD_ZERO(&rite);
X except = reed;
X
X fcntl(client, F_SETOWN, getpid());
X fcntl(subsrv, F_SETOWN, getpid());
X/* fcntl(client, F_SETFL, FNDELAY);
X fcntl(subsrv, F_SETFL, FNDELAY);
X*/
X
X signal(SIGURG, quit);
X signal(SIGPIPE, quit);
X
X while (1)
X {
X fd_set tread, twrite, texcept;
X int numbytes, bsize, numread;
X char buf[4096];
X
X tread = reed;
X twrite = rite;
X texcept = except;
X
X select(NOFILE, &tread, &twrite, &texcept, (void *)0);
X
X if (FD_ISSET(subsrv, &tread))
X {
X ioctl(subsrv, FIONREAD, &numbytes);
X bsize = MIN(numbytes, sizeof(buf));
X numread = read(subsrv, buf, bsize);
X if (numread < 0 && errno != EWOULDBLOCK)
X {
X perror("subsrv");
X exit(0);
X }
X if (! numread)
X {
X shutdown(client, 1);
X shutdown(subsrv, 0);
X FD_CLR(subsrv, &reed);
X }
X else
X write(client, buf, numread);
X }
X
X if (FD_ISSET(client, &tread))
X {
X ioctl(client, FIONREAD, &numbytes);
X bsize = MIN(numbytes, sizeof(buf));
X numread = read(client, buf, bsize);
X if (numread < 0 && errno != EWOULDBLOCK)
X {
X perror("client");
X exit(0);
X }
X if (! numread)
X {
X shutdown(client, 0);
X shutdown(subsrv, 1);
X FD_CLR(client, &reed);
X }
X else
X write(subsrv, buf, numread);
X }
X
X/* If both sides were shut down, leave. */
X if (! (FD_ISSET(client, &reed) || FD_ISSET(subsrv, &reed)))
X {
X close(client);
X close(subsrv);
X exit(0);
X }
X
X if (FD_ISSET(client, &texcept) || FD_ISSET(subsrv, &texcept))
X {
X close(client);
X close(subsrv);
X exit(0);
X }
X }
X}
X
Xvoid quit()
X{
X exit(0);
X}
X
END_OF_FILE
if test 8732 -ne `wc -c <'supersrv.c'`; then
echo shar: \"'supersrv.c'\" unpacked with wrong size!
fi
# end of 'supersrv.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked both archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...
--
Andrew Patrick acting as Comp.Sources.Reviewed Moderator
Department of Communications, Ottawa, CANADA
csr@calvin.doc.CA
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads