/* Realms of Aurealis Rerouter */
/* James Rhone */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#include <sys/un.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
void watch(int port);
int init_socket(int port);
void nonblock(int s);
int reaper();
int goodnight();
extern int errno;
#define MAX_STRING_LENGTH 8192
/* global mother descriptor */
int mother;
int main(int argc, char **argv)
{
int port;
char buf[128];
if (argc != 2)
{
printf("usage: %s <port#>\n",*argv);
exit(0);
}
if ((port = atoi(argv[1])) <= 1024) {
fputs("Illegal port #\n", stderr);
exit(0);
}
watch(port);
return 1;
}
int reaper()
{
int status;
int pid;
while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0)
printf("Child %d exited.\n\r", pid);
}
int goodnight()
{
printf("Signal received. Closing mother connection.\n");
printf("Killing children.\n");
close(mother);
exit(3);
}
int passivesock(char *service, char *protocol, int qlen)
{
struct servent *pse;
struct protoent *ppe;
struct sockaddr_in sin;
int s, type;
u_short portbase = 0;
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
if (pse = getservbyname(service, protocol))
sin.sin_port = htons(ntohs((u_short)pse->s_port) + portbase);
else
if ((sin.sin_port = htons((u_short)atoi(service))) == 0)
{
printf("can't get %s service entry\n",service);
exit(0);
}
if ((ppe = getprotobyname(protocol)) == 0)
{
printf("can't get %s proto entry\n",protocol);
exit(0);
}
if (!strcmp(protocol, "udp"))
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
{
printf("cant create socket\n");
exit (0);
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
printf("cant bind\n");
exit (0);
}
if (type == SOCK_STREAM && listen(s, qlen) < 0)
{
printf("cant listen on stream socket\n");
exit (0);
}
return s;
}
int passiveTCP(char *service, int qlen)
{
return passivesock(service, "tcp", qlen);
}
void interface_to_roa(int sok)
{
struct sockaddr_in srvadr_in;
struct hostent *sp;
int addrlen;
int mud;
char buf[MAX_STRING_LENGTH];
int cnt;
int opt;
addrlen = sizeof(struct sockaddr_in);
memset((char *)&srvadr_in, 0, addrlen);
srvadr_in.sin_family = AF_INET;
sp = gethostbyname("sc27.dreamscape.com");
if (!sp)
{
printf("could not get hostname.\n");
exit(1);
}
srvadr_in.sin_addr.s_addr = ((struct in_addr *)(sp->h_addr))->s_addr;
srvadr_in.sin_port = htons(4000);
mud = socket(PF_INET, SOCK_STREAM, 0);
if (mud < 0)
{
perror("Init-mud-socket");
exit(0);
}
#if defined(SO_SNDBUF)
opt = MAX_STRING_LENGTH + 128;
if (setsockopt(mud, SOL_SOCKET, SO_SNDBUF, (char *) &opt, sizeof(opt)) < 0)
{
perror("setsockopt SNDBUF");
exit(1);
}
#endif
opt = 1;
if (setsockopt(mud, SOL_SOCKET, SO_REUSEADDR, (char *) & opt, sizeof (opt)) < 0)
{
perror ("setsockopt REUSEADDR");
exit (0);
}
#if defined(SO_LINGER)
{
struct linger ld;
ld.l_onoff = 0; ld.l_linger = 0;
if (setsockopt(mud, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)) < 0)
{
perror("setsockopt LINGER");
exit(1);
}
}
#endif
if (connect(mud, (struct sockaddr *)&srvadr_in, addrlen) < 0)
{
printf("couldnt connect to roa.sunyit.edu.\n");
perror("connect: ");
exit(1);
}
nonblock(mud);
nonblock(sok);
printf("Child %d connected to RoA.\n", getpid());
for ( ; ; )
{
errno = 0;
if ((cnt = recv(mud, buf, MAX_STRING_LENGTH, 0)) < 0)
if (errno != EAGAIN)
{
perror("first recv: ");
break;
}
if (cnt > 0)
{
buf[cnt] = '\0';
if ((cnt = send(sok, buf, strlen(buf), 0)) < 0)
{
*buf = '\0';
break;
}
}
errno = 0;
if ((cnt = recv(sok, buf, MAX_STRING_LENGTH, 0)) < 0)
if (errno != EAGAIN)
{
perror("second recv: ");
break;
}
if (cnt > 0)
{
buf[cnt] = '\0';
if ((cnt = send(mud, buf, strlen(buf), 0)) < 0)
{
*buf = '\0';
break;
}
}
}
close(sok);
close(mud);
printf("Child %d connection closed.\n", getpid());
exit(3);
}
void watch(int port)
{
int con;
signal (SIGCHLD, (void *) reaper);
signal (SIGINT, (void *) goodnight);
signal (SIGTERM, (void *) goodnight);
signal (SIGHUP, (void *) goodnight);
signal (SIGABRT, (void *) goodnight);
mother = init_socket(port);
printf("mother socket opened on port %d\n",port);
for (; ; )
{
con = accept(mother, (struct sockaddr *) 0, 0);
if (con < 0) continue;
if (!fork())
{
printf("Connection detected, Child %d forked.\n",getpid());
interface_to_roa(con);
close(con);
exit(0);
}
else
close(con);
}
}
int init_socket(int port)
{
int s;
char *opt;
char hostname[1024];
struct sockaddr_in sa;
struct hostent *hp;
bzero(&sa, sizeof(struct sockaddr_in ));
gethostname(hostname, 1023);
hp = gethostbyname(hostname);
if (!hp)
{
perror("gethostbyname");
exit(0);
}
sa.sin_family = hp->h_addrtype;
sa.sin_port = htons(port);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
perror("Init-socket");
exit(0);
}
if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) & opt, sizeof (opt)) < 0)
{
perror ("setsockopt REUSEADDR");
exit (0);
}
#ifdef USE_LINGER
struct linger ld;
ld.l_onoff = 1;
ld.l_linger = 1000;
if (setsockopt(s, SOL_SOCKET, SO_LINGER, &ld, sizeof(ld)) < 0)
{
perror("setsockopt LINGER");
exit(0);
}
#endif
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
perror("bind");
close(s);
exit(0);
}
listen(s, 5);
return(s);
}
void nonblock(int s)
{
int flags;
flags = fcntl(s, F_GETFL);
flags |= O_NONBLOCK;
if (fcntl(s, F_SETFL, flags) < 0) {
perror("Fatal error executing nonblock (comm.c)");
exit(1);
}
}