diff options
author | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-20 19:33:49 +0800 |
---|---|---|
committer | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-20 19:33:49 +0800 |
commit | 6c7b18b32d87c2a835f7e5c48faac4a8ad44668b (patch) | |
tree | e88e1b2b1007f4ddcd348a4a1bf1d13c515c4564 /daemon/innbbsd/inndchannel.c | |
parent | f59699c22c130373cda3cc4cb6fab5bae510bd5a (diff) | |
download | pttbbs-piaip.newlayout.tar pttbbs-piaip.newlayout.tar.gz pttbbs-piaip.newlayout.tar.bz2 pttbbs-piaip.newlayout.tar.lz pttbbs-piaip.newlayout.tar.xz pttbbs-piaip.newlayout.tar.zst pttbbs-piaip.newlayout.zip |
- (internal/exp) first draft of new layoutpiaip.newlayout
git-svn-id: http://opensvn.csie.org/pttbbs/branches/piaip.newlayout@4013 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'daemon/innbbsd/inndchannel.c')
-rw-r--r-- | daemon/innbbsd/inndchannel.c | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/daemon/innbbsd/inndchannel.c b/daemon/innbbsd/inndchannel.c new file mode 100644 index 00000000..fe5b74ef --- /dev/null +++ b/daemon/innbbsd/inndchannel.c @@ -0,0 +1,681 @@ +#include <stdlib.h> +#include "innbbsconf.h" +#include "daemon.h" +#include "bbslib.h" +#include "config.h" +#include "externs.h" +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "bbs.h" + +#define DEBUG +#undef DEBUG + +#ifndef MAXCLIENT +#define MAXCLIENT 500 +#endif + +#ifndef ChannelSize +#define ChannelSize 4096 +#endif + +#ifndef ReadSize +#define ReadSize 1024 +#endif + +#ifndef DefaultINNBBSPort +#define DefaultINNBBSPort "7777" +#endif + +#ifndef HIS_MAINT +#define HIS_MAINT +#define HIS_MAINT_HOUR 5 +#define HIS_MAINT_MIN 30 +#endif + +int Maxclient = MAXCLIENT; +ClientType *Channel = NULL; +ClientType INNBBSD_STAT; + +int Max_Art_Size = MAX_ART_SIZE; + +int inetdstart = 0; + +int Junkhistory = 0; + +char *REMOTEUSERNAME, *REMOTEHOSTNAME; + +static fd_set rfd, wfd, efd, orfd, owfd, oefd; + +int channelreader(ClientType *); + +void +clearfdset(fd) + int fd; +{ + FD_CLR(fd, &rfd); +} + +static void +channelcreate(client) + ClientType *client; +{ + buffer_t *in, *out; + in = &client->in; + out = &client->out; + if (in->data != NULL) + free(in->data); + in->data = (char *)mymalloc(ChannelSize); + in->left = ChannelSize; + in->used = 0; + if (out->data != NULL) + free(out->data); + out->data = (char *)mymalloc(ChannelSize); + out->used = 0; + out->left = ChannelSize; + client->ihavecount = 0; + client->ihaveduplicate = 0; + client->ihavefail = 0; + client->ihavesize = 0; + client->statcount = 0; + client->statfail = 0; + client->begin = time(NULL); +} + +void +channeldestroy(client) + ClientType *client; +{ + if (client->in.data != NULL) { + free(client->in.data); + client->in.data = NULL; + } + if (client->out.data != NULL) { + free(client->out.data); + client->out.data = NULL; + } +#if !defined(PowerBBS) && !defined(DBZSERVER) + if (client->ihavecount > 0 || client->statcount > 0) { + bbslog("%s@%s rec: %d dup: %d fail: %d size: %d, stat rec: %d fail: %d, time sec: %d\n", + client->username, client->hostname, client->ihavecount, + client->ihaveduplicate, client->ihavefail, client->ihavesize, + client->statcount, client->statfail, time(NULL) - client->begin); + INNBBSD_STAT.ihavecount += client->ihavecount; + INNBBSD_STAT.ihaveduplicate += client->ihaveduplicate; + INNBBSD_STAT.ihavefail += client->ihavefail; + INNBBSD_STAT.ihavesize += client->ihavesize; + INNBBSD_STAT.statcount += client->statcount; + INNBBSD_STAT.statfail += client->statfail; + } +#endif +} + +void +inndchannel(port, path) + char *port, *path; +{ + time_t tvec; + int i; + int bbsinnd; + int localbbsinnd; + struct timeval tout; + ClientType *client = (ClientType *) mymalloc(sizeof(ClientType) * Maxclient); + int localdaemonready = 0; + Channel = client; + + bbsinnd = pmain(port); + if (bbsinnd < 0) { + perror("pmain, existing"); + docompletehalt(0); + return; + } + FD_ZERO(&rfd); + FD_ZERO(&wfd); + FD_ZERO(&efd); + + localbbsinnd = p_unix_main(path); + if (localbbsinnd < 0) { + perror("local pmain, existing"); + /* + * Kaede if (!inetdstart) fprintf(stderr, "if no other innbbsd + * running, try to remove %s\n",path); + */ + close(bbsinnd); + return; + } else { + FD_SET(localbbsinnd, &rfd); + localdaemonready = 1; + } + + FD_SET(bbsinnd, &rfd); + tvec = time((time_t *) 0); + for (i = 0; i < Maxclient; ++i) { + client[i].fd = -1; + client[i].access = 0; + client[i].buffer[0] = '\0'; + client[i].mode = 0; + client[i].in.left = 0; + client[i].in.used = 0; + client[i].in.data = NULL; + client[i].out.left = 0; + client[i].out.used = 0; + client[i].out.data = NULL; + client[i].midcheck = 1; + } + for (;;) { + int nsel, i; + + /* + * When to maintain history files. + */ + time_t now; + static int maint = 0; + struct tm *local; + + if (INNBBSDshutdown()) { + HISclose(); + bbslog(" Shutdown Complete \n"); + docompletehalt(0); + exit(0); + } + time(&now); + local = localtime(&now); + if (local != NULL & local->tm_hour == His_Maint_Hour && + local->tm_min >= His_Maint_Min) { + if (!maint) { + bbslog(":Maint: start (%d:%d).\n", local->tm_hour, local->tm_min); + HISmaint(); + time(&now); + local = localtime(&now); + if (local != NULL) + bbslog(":Maint: end (%d:%d).\n", local->tm_hour, local->tm_min); + maint = 1; + } + } else { + maint = 0; + } + /* + * */ + /* + * in order to maintain history, timeout every 60 seconds in case no + * connections + */ + tout.tv_sec = 60; + tout.tv_usec = 0; + orfd = rfd; + if ((nsel = select(FD_SETSIZE, &orfd, NULL, NULL, &tout)) < 0) { + continue; + } + if (localdaemonready && FD_ISSET(localbbsinnd, &orfd)) { + int ns; + ns = tryaccept(localbbsinnd); + if (ns < 0) + continue; + for (i = 0; i < Maxclient; ++i) { + if (client[i].fd == -1) + break; + } + if (i == Maxclient) { + static char msg[] = "502 no free descriptors\r\n"; + printf("%s", msg); + write(ns, msg, sizeof(msg)); + close(ns); + continue; + } + client[i].fd = ns; + client[i].buffer[0] = '\0'; + client[i].mode = 0; + client[i].midcheck = 1; + channelcreate(&client[i]); + FD_SET(ns, &rfd); /* FD_SET(ns,&wfd); */ + { + strncpy(client[i].username, "localuser", 20); + strncpy(client[i].hostname, "localhost", 128); + client[i].Argv.in = fdopen(ns, "r"); + client[i].Argv.out = fdopen(ns, "w"); +#if !defined(PowerBBS) && !defined(DBZSERVER) + bbslog("connected from (%s@%s).\n", client[i].username, client[i].hostname); +#endif +#ifdef INNBBSDEBUG + printf("connected from (%s@%s).\n", client[i].username, client[i].hostname); +#endif +#ifdef DBZSERVER + fprintf(client[i].Argv.out, "200 %s InterNetNews DBZSERVER server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); +#else + fprintf(client[i].Argv.out, "200 %s InterNetNews INNBBSD server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); +#endif + fflush(client[i].Argv.out); + verboselog("UNIX Connect from %s@%s\n", client[i].username, client[i].hostname); + } + } + if (FD_ISSET(bbsinnd, &orfd)) { + int ns = tryaccept(bbsinnd), length; + struct sockaddr_in there; + char *name; + struct hostent *hp; + if (ns < 0) + continue; + for (i = 0; i < Maxclient; ++i) { + if (client[i].fd == -1) + break; + } + if (i == Maxclient) { + static char msg[] = "502 no free descriptors\r\n"; + printf("%s", msg); + write(ns, msg, sizeof(msg)); + close(ns); + continue; + } + client[i].fd = ns; + client[i].buffer[0] = '\0'; + client[i].mode = 0; + client[i].midcheck = 1; + channelcreate(&client[i]); + FD_SET(ns, &rfd); /* FD_SET(ns,&wfd); */ + length = sizeof(there); + if (getpeername(ns, (struct sockaddr *) & there, &length) >= 0) { + name = (char *)my_rfc931_name(ns, (struct sockaddr_in *)&there); + strncpy(client[i].username, name, 20); + hp = (struct hostent *) gethostbyaddr((char *)&there.sin_addr, sizeof(struct in_addr), there.sin_family); + if (hp) + strncpy(client[i].hostname, hp->h_name, 128); + else + strncpy(client[i].hostname, (char *)inet_ntoa(there.sin_addr), 128); + + client[i].Argv.in = fdopen(ns, "r"); + client[i].Argv.out = fdopen(ns, "w"); + if ((char *)search_nodelist(client[i].hostname, client[i].username) == NULL) { + bbslog(":Err: invalid connection (%s@%s).\n", client[i].username, client[i].hostname); + fprintf(client[i].Argv.out, "502 You are not in my access file. (%s@%s)\r\n", client[i].username, client[i].hostname); + fflush(client[i].Argv.out); + fclose(client[i].Argv.in); + fclose(client[i].Argv.out); + close(client[i].fd); + FD_CLR(client[i].fd, &rfd); + client[i].fd = -1; + continue; + } + bbslog("connected from (%s@%s).\n", client[i].username, client[i].hostname); +#ifdef INNBBSDEBUG + printf("connected from (%s@%s).\n", client[i].username, client[i].hostname); +#endif +#ifdef DBZSERVER + fprintf(client[i].Argv.out, "200 %s InterNetNews DBZSERVER server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); +#else + fprintf(client[i].Argv.out, "200 %s InterNetNews INNBBSD server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); +#endif + fflush(client[i].Argv.out); + verboselog("INET Connect from %s@%s\n", client[i].username, client[i].hostname); + } else { + } + + } + for (i = 0; i < Maxclient; ++i) { + int fd = client[i].fd; + if (fd < 0) { + continue; + } + if (FD_ISSET(fd, &orfd)) { + int nr; +#ifdef DEBUG + printf("before read i %d in.used %d in.left %d\n", i, client[i].in.used, client[i].in.left); +#endif + nr = channelreader(client + i); +#ifdef DEBUG + printf("after read i %d in.used %d in.left %d\n", i, client[i].in.used, client[i].in.left); +#endif + /* int nr=read(fd,client[i].buffer,1024); */ + if (nr <= 0) { + FD_CLR(fd, &rfd); + fclose(client[i].Argv.in); + fclose(client[i].Argv.out); + close(fd); + client[i].fd = -1; + channeldestroy(client + i); + continue; + } +#ifdef DEBUG + printf("nr %d %.*s", nr, nr, client[i].buffer); +#endif + if (client[i].access == 0) { + continue; + } + } + } + } +} + +void +commandparse(client) + ClientType *client; +{ + char *ptr, *lastend; + argv_t *Argv = &client->Argv; + int (*Main) (); + char *buffer = client->in.data; + buffer_t *in = &client->in; + int dataused; + int dataleft; + +#ifdef DEBUG + printf("%s %s buffer %s", client->username, client->hostname, buffer); +#endif + ptr = (char *)strchr(in->data + in->used, '\n'); + if (client->mode == 0) { + if (ptr == NULL) { + in->used += in->lastread; + in->left -= in->lastread; + return; + } else { + dataused = ptr - (in->data + in->used) + 1; + dataleft = in->lastread - dataused; + lastend = ptr + 1; + } + } else { + if (in->used >= 5) { + ptr = (char *)strstr(in->data + in->used - 5, "\r\n.\r\n"); + } else if (strncmp(in->data, ".\r\n", 3) == 0) { + ptr = in->data; + } else { + ptr = (char *)strstr(in->data + in->used, "\r\n.\r\n"); + } + if (ptr == NULL) { + in->used += in->lastread; + in->left -= in->lastread; + return; + } else { + ptr[2] = '\0'; + if (strncmp(in->data, ".\r\n", 3) == 0) + dataused = 3; + else + dataused = ptr - (in->data + in->used) + 5; + dataleft = in->lastread - dataused; + lastend = ptr + 5; + verboselog("Get: %s@%s end of data . size %d\n", client->username, client->hostname, in->used + dataused); + client->ihavesize += in->used + dataused; + } + } + if (client->mode == 0) { + struct Daemoncmd *dp; + Argv->argc = 0, Argv->argv = NULL, + Argv->inputline = buffer; + if (ptr != NULL) + *ptr = '\0'; + verboselog("Get: %s\n", Argv->inputline); + Argv->argc = argify(in->data + in->used, &Argv->argv); + if (ptr != NULL) + *ptr = '\n'; + dp = (struct Daemoncmd *) searchcmd(Argv->argv[0]); + Argv->dc = dp; + if (Argv->dc) { +#ifdef DEBUG + printf("enter command %s\n", Argv->argv[0]); +#endif + if (Argv->argc < dp->argc) { + fprintf(Argv->out, "%d Usage: %s\r\n", dp->errorcode, dp->usage); + fflush(Argv->out); + verboselog("Put: %d Usage: %s\n", dp->errorcode, dp->usage); + } else if (dp->argno != 0 && Argv->argc > dp->argno) { + fprintf(Argv->out, "%d Usage: %s\r\n", dp->errorcode, dp->usage); + fflush(Argv->out); + verboselog("Put: %d Usage: %s\n", dp->errorcode, dp->usage); + } else { + Main = Argv->dc->main; + if (Main) { + fflush(stdout); + (*Main) (client); + } + } + } else { + fprintf(Argv->out, "500 Syntax error or bad command\r\n"); + fflush(Argv->out); + verboselog("Put: 500 Syntax error or bad command\r\n"); + } + deargify(&Argv->argv); + } else { + if (Argv->dc) { +#ifdef DEBUG + printf("enter data mode\n"); +#endif + Main = Argv->dc->main; + if (Main) { + fflush(stdout); + (*Main) (client); + } + } + } + if (client->mode == 0) { + if (dataleft > 0) { + strncpy(in->data, lastend, dataleft); +#ifdef INNBBSDEBUG + printf("***** try to copy %x %x %d bytes\n", in->data, lastend, dataleft); +#endif + } else { + dataleft = 0; + } + in->left += in->used - dataleft; + in->used = dataleft; + } +} + +int +channelreader(client) + ClientType *client; +{ + int len; + char *ptr; + buffer_t *in = &client->in; + + if (in->left < ReadSize + 3) { + int need = in->used + in->left + ReadSize + 3; + need += need / 5; + in->data = (char *)myrealloc(in->data, need); + in->left = need - in->used; + verboselog("channelreader realloc %d\n", need); + } + len = read(client->fd, in->data + in->used, ReadSize); + + if (len <= 0) + return len; + + in->data[len + in->used] = '\0'; + in->lastread = len; +#ifdef DEBUG + printf("after read lastread %d\n", in->lastread); + printf("len %d client %d\n", len, strlen(in->data + in->used)); +#endif + + REMOTEHOSTNAME = client->hostname; + REMOTEUSERNAME = client->username; + if (client->mode == 0) { + if ((ptr = (char *)strchr(in->data, '\n')) != NULL) { + if (in->data[0] != '\r') + commandparse(client); + } + } else { + commandparse(client); + } + return len; +} + +void +do_command() +{ +} + +void +dopipesig(s) + int s; +{ + printf("catch sigpipe\n"); + signal(SIGPIPE, dopipesig); +} + +int +standaloneinit(port) + char *port; +{ + int ndescriptors; + FILE *pf; + char pidfile[24]; + ndescriptors = getdtablesize(); +#ifndef NOFORK + if (!inetdstart) + if (fork()) + exit(0); +#endif + + sprintf(pidfile, "/tmp/innbbsd-%s.pid", port); + /* + * Kaede if (!inetdstart) fprintf(stderr, "PID file is in %s\n", + * pidfile); + */ + { + int s; + for (s = 3; s < ndescriptors; s++) + (void)close(s); + } + pf = fopen(pidfile, "w"); + if (pf != NULL) { + fprintf(pf, "%d\n", getpid()); + fclose(pf); + } + return 0; +} + +extern char *optarg; +extern int opterr, optind; + +void +innbbsusage(name) + char *name; +{ + fprintf(stderr, "Usage: %s [options] [port [path]]\n", name); + fprintf(stderr, " -v (verbose log)\n"); + fprintf(stderr, " -h|? (help)\n"); + fprintf(stderr, " -n (not to use in core dbz)\n"); + fprintf(stderr, " -i (start from inetd with wait option)\n"); + fprintf(stderr, " -c connections (maximum number of connections accepted)\n"); + fprintf(stderr, " default=%d\n", Maxclient); + fprintf(stderr, " -j (keep history of junk article, default=none)\n"); +} + + +#ifdef DEBUGNGSPLIT +main() +{ + char **ngptr; + char buf[1024]; + gets(buf); + ngptr = (char **)BNGsplit(buf); + printf("line %s\n", buf); + while (*ngptr != NULL) { + printf("%s\n", *ngptr); + ngptr++; + } +} +#endif + +static time_t INNBBSDstartup; +int +innbbsdstartup(void) +{ + return INNBBSDstartup; +} + +int +main(argc, argv) + int argc; + char **argv; +{ + + char *port, *path; + int c, errflag = 0; + extern INNBBSDhalt(); + /* + * woju + */ + setgid(BBSGID); + setuid(BBSUID); + chdir(BBSHOME); + attach_SHM(); + resolve_boards(); + + port = DefaultINNBBSPort; + path = LOCALDAEMON; + Junkhistory = 0; + + time(&INNBBSDstartup); + openlog("innbbsd", LOG_PID | LOG_ODELAY, LOG_DAEMON); + while ((c = getopt(argc, argv, "c:f:s:vhidn?j")) != -1) + switch (c) { + case 'j': + Junkhistory = 1; + break; + case 'v': + verboseon("innbbsd.log"); + break; + case 'n': + hisincore(0); + break; + case 'c': + Maxclient = atoi(optarg); + if (Maxclient < 0) + Maxclient = 0; + break; + case 'i':{ + struct sockaddr_in there; + int len = sizeof(there); + int rel; + if ((rel = getsockname(0, (struct sockaddr *) & there, &len)) < 0) { + fprintf(stdout, "You must run -i from inetd with inetd.conf line: \n"); + fprintf(stdout, "service-port stream tcp wait bbs " BBSHOME "/innd/innbbsd innbbsd -i port\n"); + fflush(stdout); + exit(5); + } + inetdstart = 1; + startfrominetd(1); + } + break; + case 'd': + dbzdebug(1); + break; + case 's': + Max_Art_Size = atol(optarg); + if (Max_Art_Size < 0) + Max_Art_Size = 0; + break; + case 'h': + case '?': + default: + errflag++; + } + if (errflag > 0) { + innbbsusage(argv[0]); + return (1); + } + if (argc - optind >= 1) { + port = argv[optind]; + } + if (argc - optind >= 2) { + path = argv[optind + 1]; + } + standaloneinit(port); + + initial_bbs("feed"); + + /* + * Kaede if (!inetdstart) fprintf(stderr, "Try to listen in port %s and + * path %s\n", port, path); + */ + HISmaint(); + HISsetup(); + installinnbbsd(); + sethaltfunction(INNBBSDhalt); + + signal(SIGPIPE, dopipesig); + inndchannel(port, path); + HISclose(); + return 0; +} |