From: Art Cancro Date: Thu, 9 Dec 1999 00:22:58 +0000 (+0000) Subject: * Finished the "arbitrary service" registration. X-Git-Tag: v7.86~7398 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=629b54b830c1cc3dac3c136f9b398c3fe2c1fe3e * 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. --- diff --git a/citadel/ChangeLog b/citadel/ChangeLog index 450aea79f..d9d64edec 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -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 Fri Jul 10 1998 Art Cancro * Initial CVS import - diff --git a/citadel/Makefile.in b/citadel/Makefile.in index 861ef8c89..e00c9d2aa 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -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 diff --git a/citadel/citserver.c b/citadel/citserver.c index 1245332c2..7b8cc1af8 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -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, ""); } diff --git a/citadel/citserver.h b/citadel/citserver.h index 8c344a252..2c9d2b35a 100644 --- a/citadel/citserver.h +++ b/citadel/citserver.h @@ -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); diff --git a/citadel/dynloader.c b/citadel/dynloader.c index a9e734ca3..4d26b5945 100644 --- a/citadel/dynloader.c +++ b/citadel/dynloader.c @@ -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 index 000000000..87aef1acb --- /dev/null +++ b/citadel/serv_smtp.c @@ -0,0 +1,76 @@ +/* $Id$ */ +#include "sysdep.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "citadel.h" +#include "server.h" +#include +#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$"; +} diff --git a/citadel/server.h b/citadel/server.h index e603a0312..662ef3ae9 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -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; diff --git a/citadel/sysdep.c b/citadel/sysdep.c index 56812c88d..b5ad3bc44 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -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) {