* Finished the "arbitrary service" registration.
authorArt Cancro <ajc@citadel.org>
Thu, 9 Dec 1999 00:22:58 +0000 (00:22 +0000)
committerArt Cancro <ajc@citadel.org>
Thu, 9 Dec 1999 00:22:58 +0000 (00:22 +0000)
* Eliminated "special" master socket for Citadel protocol - just register it
  like any other protocol.
* Began initial implementation of native SMTP service.

citadel/ChangeLog
citadel/Makefile.in
citadel/citserver.c
citadel/citserver.h
citadel/dynloader.c
citadel/serv_smtp.c [new file with mode: 0644]
citadel/server.h
citadel/sysdep.c

index 450aea79fd32c46a692b955ed05aa7e079b0cfea..d9d64edecaaff11b028b2b96ceedc08641447352 100644 (file)
@@ -1,4 +1,10 @@
 $Log$
+Revision 1.425  1999/12/09 00:22:58  ajc
+* Finished the "arbitrary service" registration.
+* Eliminated "special" master socket for Citadel protocol - just register it
+  like any other protocol.
+* Began initial implementation of native SMTP service.
+
 Revision 1.424  1999/12/08 18:09:10  ajc
 * Added CtdlRegisterServiceHook() and its data type, for implementing arbitrary
   TCP-based services directly in the Citadel server.  Not finished yet.
@@ -1476,4 +1482,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
        * Initial CVS import 
-
index 861ef8c89fd398da680ac7b18f141a68f53eba59..e00c9d2aa03daedfdb8757034c1c450e891d08c6 100644 (file)
@@ -26,7 +26,7 @@ SERV_ICQ=@SERV_ICQ@
 CLIENT_TARGETS=citadel$(EXEEXT) whobbs$(EXEEXT)
 SERVER_TARGETS=citserver setup $(CHKPWD)
 SERV_MODULES=modules/serv_chat$(SO) modules/serv_vcard$(SO) \
-       modules/serv_upgrade$(SO) \
+       modules/serv_upgrade$(SO) modules/serv_smtp$(SO) \
        modules/serv_expire$(SO) $(SERV_ICQ)
 UTIL_TARGETS=aidepost netmailer netproc netsetup msgform readlog rcit \
        stats citmail netpoll mailinglist userlist sendcommand \
@@ -70,7 +70,8 @@ SOURCES=aidepost.c citadel.c citmail.c citserver.c client_chat.c commands.c \
        serv_info.c serv_test.c setup.c snprintf.c stats.c serv_vcard.c \
        support.c sysdep.c tools.c user_ops.c userlist.c serv_expire.c \
        whobbs.c sendcommand.c mime_parser.c base64.c qpdecode.c getutline.c \
-       auth.c chkpwd.c client_icq.c html.c vcard.c serv_upgrade.c
+       auth.c chkpwd.c client_icq.c html.c vcard.c serv_upgrade.c \
+       serv_smtp.c
 
 DEP_FILES=$(SOURCES:.c=.d)
 
@@ -129,6 +130,12 @@ modules/serv_test.so: serv_test.mo
 modules/serv_test.mo: serv_test.mo
        ln -f serv_test.mo modules
 
+modules/serv_smtp.so: serv_smtp.mo
+       $(LINK_SHARED) -o modules/serv_smtp.so serv_smtp.mo
+
+modules/serv_smtp.mo: serv_smtp.mo
+       ln -f serv_smtp.mo modules
+
 modules/serv_expire.so: serv_expire.mo
        $(LINK_SHARED) -o modules/serv_expire.so serv_expire.mo
 
index 1245332c27d7ccc98e8b977b24a9a4ebbc220a6d..7b8cc1af8b34c952698e273f2b6f47559b9c5c29 100644 (file)
@@ -847,7 +847,7 @@ void cmd_scdn(char *argbuf)
 
 
 /*
- * 
+ * Back-end function for starting a session
  */
 void begin_session(struct CitContext *con)
 {
@@ -883,7 +883,17 @@ void begin_session(struct CitContext *con)
        if ((config.c_maxsessions > 0)&&(num_sessions > config.c_maxsessions))
                con->nologin = 1;
 
-       if (con->nologin==1) {
+       lprintf(3, "citserver[%3d]: started.\n", con->cs_pid);
+
+       /* Run any session startup routines registered by loadable modules */
+       PerformSessionHooks(EVT_START);
+
+       rec_log(CL_CONNECT, "");
+}
+
+
+void citproto_begin_session() {
+       if (CC->nologin==1) {
                cprintf("%d %s: Too many users are already online "
                        "(maximum is %d)\n",
                        ERROR+MAX_SESSIONS_EXCEEDED,
@@ -893,13 +903,6 @@ void begin_session(struct CitContext *con)
                cprintf("%d %s Citadel/UX server ready.\n",
                        OK, config.c_nodename);
                }
-
-       lprintf(3, "citserver[%3d]: started.\n", con->cs_pid);
-
-       /* Run any session startup routines registered by loadable modules */
-       PerformSessionHooks(EVT_START);
-
-       rec_log(CL_CONNECT, "");
 }
 
 
index 8c344a252ecc8d1879dbb9271dbea1ced52eb17a..2c9d2b35a7b09c5f352bb4d21c7d436164e605d5 100644 (file)
@@ -29,6 +29,7 @@ int CtdlGetDynamicSymbol(void);
 void enter_housekeeping_cmd(char *);
 void do_command_loop(void);
 void begin_session(struct CitContext *con);
+void citproto_begin_session(void);
 void GenerateRoomDisplay(char *real_room,
                         struct CitContext *viewed,
                         struct CitContext *viewer);
index a9e734ca320de4af6af705412ff6a39008ff1130..4d26b594526294387d3a4e628cf30bc67b62797a 100644 (file)
@@ -240,6 +240,7 @@ void CtdlRegisterServiceHook(int tcp_port,
        newfcn->tcp_port = tcp_port;
        newfcn->h_greeting_function = h_greeting_function;
        newfcn->h_command_function = h_command_function;
+       newfcn->msock = (-1);
        ServiceHookTable = newfcn;
        lprintf(5, "Registered a new service (TCP port %d)\n", tcp_port);
 }
diff --git a/citadel/serv_smtp.c b/citadel/serv_smtp.c
new file mode 100644 (file)
index 0000000..87aef1a
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id$ */
+#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <limits.h>
+#include "citadel.h"
+#include "server.h"
+#include <time.h>
+#include "sysdep_decls.h"
+#include "citserver.h"
+#include "support.h"
+#include "config.h"
+#include "dynloader.h"
+#include "room_ops.h"
+#include "policy.h"
+#include "database.h"
+#include "msgbase.h"
+
+
+/*
+ * Here's where our SMTP session begins its happy day.
+ */
+void smtp_greeting(void) {
+
+       strcpy(CC->cs_clientname, "Citadel SMTP");
+
+       cprintf("220 %s Citadel/UX SMTP server ready\n",
+               config.c_fqdn);
+}
+
+
+/* 
+ * Main command loop for SMTP sessions.
+ */
+void smtp_command_loop(void) {
+       char cmdbuf[256];
+
+       time(&CC->lastcmd);
+       memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
+       if (client_gets(cmdbuf) < 1) {
+               lprintf(3, "SMTP socket is broken.  Ending session.\n");
+               CC->kill_me = 1;
+               return;
+       }
+       lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
+
+       if (!strncasecmp(cmdbuf,"QUIT",4)) {
+               cprintf("221 Later, dude!  Microsoft sucks!!\n");
+               CC->kill_me = 1;
+               return;
+               }
+
+       else {
+               cprintf("500 I'm afraid I can't do that, Dave.\n");
+       }
+
+}
+
+
+
+char *Dynamic_Module_Init(void)
+{
+       CtdlRegisterServiceHook(2525,
+                               smtp_greeting,
+                               smtp_command_loop);
+       return "$Id$";
+}
index e603a031271017469272a25b6635e9c5622ae47b..662ef3ae963eb7353f5232f5f87b0de90651603f 100644 (file)
@@ -72,7 +72,7 @@ struct CitContext {
        time_t lastidle;        /* For computing idle time */
        char lastcmdname[5];    /* name of last command executed */
        unsigned cs_flags;      /* miscellaneous flags */
-       int client_protocol;    /* Which protocol is this client speaking? */
+       void (*h_command_function) (void) ;     /* proto command function */
 
        /* feeping creaturisms... */
        int cs_clientdev;       /* client developer ID */
@@ -317,6 +317,7 @@ struct ServiceFunctionHook {
        int tcp_port;
        void (*h_greeting_function) (void) ;
        void (*h_command_function) (void) ;
+       int msock;
 };
 extern struct ServiceFunctionHook *ServiceHookTable;
 
index 56812c88d2ade52d4b8ba978fb0e82dad91e8c04..b5ad3bc4475e5163c144546c15460f5c51cd568e 100644 (file)
@@ -64,7 +64,6 @@ struct TheHeap *heap = NULL;
 pthread_mutex_t Critters[MAX_SEMAPHORES];      /* Things needing locking */
 pthread_key_t MyConKey;                                /* TSD key for MyContext() */
 
-int msock;                                     /* master listening socket */
 int verbosity = DEFAULT_VERBOSITY;             /* Logging level */
 
 struct CitContext masterCC;
@@ -267,9 +266,8 @@ int ig_tcp_server(int port_number, int queue_len)
        sin.sin_addr.s_addr = INADDR_ANY;
 
        if (port_number == 0) {
-               lprintf(1,
-                       "citserver: No port number specified.  Run setup.\n");
-               exit(1);
+               lprintf(1, "citserver: illegal port number specified\n");
+               return(-1);
        }
        
        sin.sin_port = htons((u_short)port_number);
@@ -278,7 +276,7 @@ int ig_tcp_server(int port_number, int queue_len)
        if (s < 0) {
                lprintf(1, "citserver: Can't create a socket: %s\n",
                        strerror(errno));
-               exit(errno);
+               return(-1);
        }
 
        /* Set the SO_REUSEADDR socket option, because it makes sense. */
@@ -287,12 +285,12 @@ int ig_tcp_server(int port_number, int queue_len)
 
        if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
                lprintf(1, "citserver: Can't bind: %s\n", strerror(errno));
-               exit(errno);
+               return(-1);
        }
 
        if (listen(s, queue_len) < 0) {
                lprintf(1, "citserver: Can't listen: %s\n", strerror(errno));
-               exit(errno);
+               return(-1);
        }
 
        return(s);
@@ -485,8 +483,7 @@ int client_gets(char *buf)
  * The system-dependent part of master_cleanup() - close the master socket.
  */
 void sysdep_master_cleanup(void) {
-       lprintf(7, "Closing master socket %d\n", msock);
-       close(msock);
+       /* FIX close all protocol master sockets here */
 }
 
 
@@ -767,12 +764,10 @@ int main(int argc, char **argv)
 
        /*
         * Bind the server to our favourite port.
-        * There is no need to check for errors, because ig_tcp_server()
-        * exits if it doesn't succeed.
         */
-       lprintf(7, "Attempting to bind to port %d...\n", config.c_port_number);
-       msock = ig_tcp_server(config.c_port_number, config.c_maxsessions);
-       lprintf(7, "Listening on socket %d\n", msock);
+       CtdlRegisterServiceHook(config.c_port_number,
+                               citproto_begin_session,
+                               do_command_loop);
 
        /*
         * Now that we've bound the socket, change to the BBS user id and its
@@ -839,16 +834,26 @@ int main(int argc, char **argv)
         * figure out what to put there.
         */
        FD_ZERO(&masterfds);
-       FD_SET(msock, &masterfds);
-       masterhighest = msock;
+       masterhighest = 0;
        FD_SET(rescan[0], &masterfds);
        if (rescan[0] > masterhighest) masterhighest = rescan[0];
 
        for (serviceptr = ServiceHookTable; serviceptr != NULL;
            serviceptr = serviceptr->next ) {
-               FD_SET(serviceptr->tcp_port, &masterfds);
-               if (serviceptr->tcp_port > masterhighest)
-                       masterhighest = serviceptr->tcp_port;
+               serviceptr->msock = ig_tcp_server(
+                       serviceptr->tcp_port, config.c_maxsessions);
+               if (serviceptr->msock >= 0) {
+                       FD_SET(serviceptr->msock, &masterfds);
+                       if (serviceptr->msock > masterhighest)
+                               masterhighest = serviceptr->msock;
+                       lprintf(7, "Bound to port %-5d (socket %d)\n",
+                               serviceptr->tcp_port,
+                               serviceptr->msock);
+               }
+               else {
+                       lprintf(1, "Unable to bind to port %d\n",
+                               serviceptr->tcp_port);
+               }
        }
 
 
@@ -889,6 +894,7 @@ void worker_thread(void) {
        fd_set readfds;
        int retval;
        struct CitContext *con= NULL;   /* Temporary context pointer */
+       struct ServiceFunctionHook *serviceptr;
        struct sockaddr_in fsin;        /* Data for master socket */
        int alen;                       /* Data for master socket */
        int ssock;                      /* Descriptor for client socket */
@@ -933,36 +939,47 @@ SETUP_FD: memcpy(&readfds, &masterfds, sizeof(fd_set) );
                /* Next, check to see if it's a new client connecting
                 * on the master socket.
                 */
-               else if (FD_ISSET(msock, &readfds)) {
-                       alen = sizeof fsin;
-                       ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
-                       if (ssock < 0) {
-                               lprintf(2, "citserver: accept() failed: %s\n",
-                                       strerror(errno));
-                       }
-                       else {
-                               lprintf(7, "citserver: New client socket %d\n",
-                                       ssock);
-
-                               /* New context will be created already set up
-                                * in the CON_EXECUTING state.
-                                */
-                               con = CreateNewContext();
-
-                               /* Assign our new socket number to it. */
-                               con->client_socket = ssock;
-                               con->client_protocol = config.c_port_number;
+               else for (serviceptr = ServiceHookTable; serviceptr != NULL;
+                    serviceptr = serviceptr->next ) {
+
+                       if (FD_ISSET(serviceptr->msock, &readfds)) {
+                               alen = sizeof fsin;
+                               ssock = accept(serviceptr->msock,
+                                       (struct sockaddr *)&fsin, &alen);
+                               if (ssock < 0) {
+                                       lprintf(2, "citserver: accept(): %s\n",
+                                               strerror(errno));
+                               }
+                               else {
+                                       lprintf(7, "citserver: "
+                                               "New client socket %d\n",
+                                               ssock);
+
+                                       /* New context will be created already
+                                       * set up in the CON_EXECUTING state.
+                                       */
+                                       con = CreateNewContext();
+
+                                       /* Assign new socket number to it. */
+                                       con->client_socket = ssock;
+                                       con->h_command_function =
+                                               serviceptr->h_command_function;
        
-                               /* Set the SO_REUSEADDR socket option */
-                               i = 1;
-                               setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,
-                                       &i, sizeof(i));
-
-                               pthread_setspecific(MyConKey, (void *)con);
-                               begin_session(con);
-                               pthread_setspecific(MyConKey, (void *)NULL);
-                               con->state = CON_IDLE;
-                               goto SETUP_FD;
+                                       /* Set the SO_REUSEADDR socket option */
+                                       i = 1;
+                                       setsockopt(ssock, SOL_SOCKET,
+                                               SO_REUSEADDR,
+                                               &i, sizeof(i));
+
+                                       pthread_setspecific(MyConKey,
+                                               (void *)con);
+                                       begin_session(con);
+                                       serviceptr->h_greeting_function();
+                                       pthread_setspecific(MyConKey,
+                                               (void *)NULL);
+                                       con->state = CON_IDLE;
+                                       goto SETUP_FD;
+                               }
                        }
                }
 
@@ -970,7 +987,7 @@ SETUP_FD:   memcpy(&readfds, &masterfds, sizeof(fd_set) );
                 * thread that the &readfds needs to be refreshed with more
                 * current data.
                 */
-               else if (FD_ISSET(rescan[0], &readfds)) {
+               if (FD_ISSET(rescan[0], &readfds)) {
                        read(rescan[0], &junk, 1);
                        goto SETUP_FD;
                }
@@ -1002,7 +1019,7 @@ SETUP_FD: memcpy(&readfds, &masterfds, sizeof(fd_set) );
                        /* We're bound to a session, now do *one* command */
                        if (bind_me != NULL) {
                                pthread_setspecific(MyConKey, (void *)bind_me);
-                               do_command_loop();
+                               CC->h_command_function();
                                pthread_setspecific(MyConKey, (void *)NULL);
                                bind_me->state = CON_IDLE;
                                if (bind_me->kill_me == 1) {