#include "bbs.h"
#include <stdlib.h>
#include "osdep.h"
#include "innbbsconf.h"
#include "daemon.h"
#include <signal.h>
#include <setjmp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "externs.h"
static jmp_buf timebuf;
static void
timeout(sig)
int sig;
{
longjmp(timebuf, sig);
}
extern int errno;
static void
reapchild(s)
int s;
{
int state;
while (waitpid(-1, &state, WNOHANG | WUNTRACED) > 0) {
/* printf("reaping child\n"); */
}
}
void
dokill(s)
int s;
{
kill(0, SIGKILL);
}
static int INETDstart = 0;
void
startfrominetd(int flag)
{
INETDstart = flag;
}
void
standalonesetup(fd)
int fd;
{
int on = 1;
struct linger foobar;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
foobar.l_onoff = 0;
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&foobar, sizeof(foobar)) < 0)
syslog(LOG_ERR, "setsockopt (SO_LINGER): %m");
}
static char *UNIX_SERVER_PATH;
static int (*halt) (int);
void
sethaltfunction(haltfunc)
int (*haltfunc) (int);
{
halt = haltfunc;
}
void
docompletehalt(s)
int s;
{
/*
* printf("try to remove %s\n", UNIX_SERVER_PATH);
* unlink(UNIX_SERVER_PATH);
*/
exit(0);
/* dokill(); */
}
void
doremove(s)
int s;
{
if (halt != NULL)
(*halt) (s);
else
docompletehalt(s);
}
int
initunixserver(path, protocol)
char *path;
char *protocol;
{
struct sockaddr_un s_un;
/* unix endpoint address */
struct protoent *pe; /* protocol information entry */
int s;
bzero((char *)&s_un, sizeof(s_un));
s_un.sun_family = AF_UNIX;
strcpy(s_un.sun_path, path);
if (protocol == NULL)
protocol = "tcp";
/* map protocol name to protocol number */
pe = getprotobyname(protocol);
if (pe == NULL) {
fprintf(stderr, "%s: Unknown protocol.\n", protocol);
return (-1);
}
/* Allocate a socket */
s = socket(PF_UNIX, strcmp(protocol, "tcp") ? SOCK_DGRAM : SOCK_STREAM, 0);
if (s < 0) {
printf("protocol %d\n", pe->p_proto);
perror("socket");
return -1;
}
/* standalonesetup(s); */
Signal(SIGHUP, SIG_IGN);
Signal(SIGUSR1, SIG_IGN);
Signal(SIGCHLD, reapchild);
UNIX_SERVER_PATH = path;
Signal(SIGINT, doremove);
Signal(SIGTERM, doremove);
chdir("/");
if (bind(s, (struct sockaddr *) & s_un, sizeof(struct sockaddr_un)) < 0) {
perror("bind");
perror(path);
return -1;
}
listen(s, 10);
return s;
}
int
initinetserver(service, protocol)
char *service;
char *protocol;
{
struct servent *se; /* service information entry */
struct protoent *pe; /* protocol information entry */
struct sockaddr_in sin; /* Internet endpoint address */
int port, s;
int randomport = 0;
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
if (!strcmp("0", service)) {
randomport = 1;
sin.sin_addr.s_addr = INADDR_ANY;
}
if (service == NULL)
service = DEFAULTPORT;
if (protocol == NULL)
protocol = "tcp";
/* map service name to port number */
/* service ---> port */
se = getservbyname(service, protocol);
if (se == NULL) {
port = htons((u_short) atoi(service));
if (port == 0 && !randomport) {
fprintf(stderr, "%s/%s: Unknown service.\n", service, protocol);
return (-1);
}
} else
port = se->s_port;
sin.sin_port = port;
/* map protocol name to protocol number */
pe = getprotobyname(protocol);
if (pe == NULL) {
fprintf(stderr, "%s: Unknown protocol.\n", protocol);
return (-1);
}
/* Allocate a socket */
s = socket(PF_INET, strcmp(protocol, "tcp") ? SOCK_DGRAM : SOCK_STREAM, pe->p_proto);
if (s < 0) {
perror("socket");
return -1;
}
standalonesetup(s);
Signal(SIGHUP, SIG_IGN);
Signal(SIGUSR1, SIG_IGN);
Signal(SIGCHLD, reapchild);
Signal(SIGINT, dokill);
Signal(SIGTERM, dokill);
chdir("/");
if (bind(s, (struct sockaddr *) & sin, sizeof(struct sockaddr_in)) < 0) {
perror("bind");
return -1;
}
listen(s, 10);
#ifdef DEBUG
{
int length = sizeof(sin);
getsockname(s, &sin, &length);
printf("portnum alocalted %d\n", sin.sin_port);
}
#endif
return s;
}
int
open_unix_listen(path, protocol, initfunc)
char *path;
char *protocol;
int (*initfunc) ARG((int));
{
int s;
s = initunixserver(path, protocol);
if (s < 0) {
return -1;
}
if (initfunc != NULL) {
printf("in inetsingleserver before initfunc s %d\n", s);
if ((*initfunc) (s) < 0) {
perror("initfunc error");
return -1;
}
printf("end inetsingleserver before initfunc \n");
}
return s;
}
int
open_listen(service, protocol, initfunc)
char *service;
char *protocol;
int (*initfunc) ARG((int));
{
int s;
if (!INETDstart)
s = initinetserver(service, protocol);
else
s = 0;
if (s < 0) {
return -1;
}
if (initfunc != NULL) {
printf("in inetsingleserver before initfunc s %d\n", s);
if ((*initfunc) (s) < 0) {
perror("initfunc error");
return -1;
}
printf("end inetsingleserver before initfunc \n");
}
return s;
}
int
inetsingleserver(service, protocol, serverfunc, initfunc)
char *service;
char *protocol;
int (*initfunc) ARG((int));
int (*serverfunc) ARG((int));
{
int s;
if (!INETDstart)
s = initinetserver(service, protocol);
else
s = 0;
if (s < 0) {
return -1;
}
if (initfunc != NULL) {
printf("in inetsingleserver before initfunc s %d\n", s);
if ((*initfunc) (s) < 0) {
perror("initfunc error");
return -1;
}
printf("end inetsingleserver before initfunc \n");
} {
int ns = tryaccept(s);
int result = 0;
if (ns < 0 && errno != EINTR) {
#ifdef DEBUGSERVER
perror("accept");
#endif
}
close(s);
if (serverfunc != NULL)
result = (*serverfunc) (ns);
close(ns);
return (result);
}
}
int
tryaccept(s)
int s;
{
int ns;
socklen_t fromlen;
struct sockaddr sockaddr; /* Internet endpoint address */
fromlen = sizeof(struct sockaddr_in);
#ifdef DEBUGSERVER
fputs("Listening again\n", stdout);
#endif
do {
ns = accept(s, &sockaddr, &fromlen);
errno = 0;
} while (ns < 0 && errno == EINTR);
return ns;
}
int
inetserver(service, protocol, serverfunc)
char *service;
char *protocol;
int (*serverfunc) ARG((int));
{
int s;
if (!INETDstart)
s = initinetserver(service, protocol);
else
s = 0;
if (s < 0) {
return -1;
}
for (;;) {
int ns = tryaccept(s);
int result = 0;
int pid;
if (ns < 0 && errno != EINTR) {
#ifdef DEBUGSERVER
perror("accept");
#endif
continue;
}
#ifdef DEBUGSERVER
fputs("Accept OK\n", stdout);
#endif
pid = fork();
if (pid == 0) {
close(s);
if (serverfunc != NULL)
result = (*serverfunc) (ns);
close(ns);
exit(result);
} else if (pid < 0) {
perror("fork");
return -1;
}
close(ns);
}
return 0;
}
int
inetclient(server, service, protocol)
char *server;
char *protocol;
char *service;
{
struct servent *se; /* service information entry */
struct hostent *he; /* host information entry */
struct protoent *pe; /* protocol information entry */
struct sockaddr_in sin; /* Internet endpoint address */
int port, s;
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
if (service == NULL)
service = DEFAULTPORT;
if (protocol == NULL)
protocol = "tcp";
if (server == NULL)
server = DEFAULTSERVER;
/* map service name to port number */
/* service ---> port */
se = getservbyname(service, protocol);
if (se == NULL) {
port = htons((u_short) atoi(service));
if (port == 0) {
fprintf(stderr, "%s/%s: Unknown service.\n", service, protocol);
return (-1);
}
} else
port = se->s_port;
sin.sin_port = port;
/* map server hostname to IP address, allowing for dotted decimal */
he = gethostbyname(server);
if (he == NULL) {
sin.sin_addr.s_addr = inet_addr(server);
if (sin.sin_addr.s_addr == INADDR_NONE) {
fprintf(stderr, "%s: Unknown host.\n", server);
return (-1);
}
} else
bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
/* map protocol name to protocol number */
pe = getprotobyname(protocol);
if (pe == NULL) {
fprintf(stderr, "%s: Unknown protocol.\n", protocol);
return (-1);
}
/* Allocate a socket */
s = socket(PF_INET, strcmp(protocol, "tcp") ? SOCK_DGRAM : SOCK_STREAM, pe->p_proto);
if (s < 0) {
perror("socket");
return -1;
}
if (setjmp(timebuf) == 0) {
Signal(SIGALRM, timeout);
alarm(5);
if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
alarm(0);
return -1;
}
} else {
alarm(0);
return -1;
}
alarm(0);
return s;
}