#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
#include <string.h>
#include "snprintf.h"
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
int serv_sock;
}
-
-
-
-
void timeout(int signum)
{
exit(signum);
}
-int connectsock(char *host, char *service, char *protocol)
+int uds_connectsock(char *sockpath)
{
- struct hostent *phe;
- struct servent *pse;
- struct protoent *ppe;
- struct sockaddr_in sin;
- int s, type;
+ int s;
struct sockaddr_un sun;
- if ( (!strcmp(protocol, "unix")) || (atoi(service)<0) ) {
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_UNIX;
- sprintf(sun.sun_path, USOCKPATH, 0-atoi(service) );
-
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if (s < 0) {
- fprintf(stderr, "Can't create socket: %s\n",
- strerror(errno));
- exit(3);
- }
-
- if (connect(s, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
- fprintf(stderr, "can't connect: %s\n",
- strerror(errno));
- exit(3);
- }
-
- return s;
- }
-
-
- /* otherwise it's a network connection */
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ strncpy(sun.sun_path, sockpath, sizeof sun.sun_path);
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
-
- pse = getservbyname(service, protocol);
- if (pse) {
- sin.sin_port = pse->s_port;
- } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
- fprintf(stderr, "Can't get %s service entry: %s\n",
- service, strerror(errno));
- exit(3);
- }
- phe = gethostbyname(host);
- if (phe) {
- memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
- } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
- fprintf(stderr, "Can't get %s host entry: %s\n",
- host, strerror(errno));
- exit(3);
- }
- if ((ppe = getprotobyname(protocol)) == 0) {
- fprintf(stderr, "Can't get %s protocol entry: %s\n",
- protocol, strerror(errno));
- exit(3);
- }
- if (!strcmp(protocol, "udp")) {
- type = SOCK_DGRAM;
- } else {
- type = SOCK_STREAM;
- }
-
- s = socket(PF_INET, type, ppe->p_proto);
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0) {
- fprintf(stderr, "Can't create socket: %s\n", strerror(errno));
+ fprintf(stderr, "Can't create socket: %s\n",
+ strerror(errno));
exit(3);
}
- signal(SIGALRM, timeout);
- alarm(30);
- if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- fprintf(stderr, "can't connect to %s.%s: %s\n",
- host, service, strerror(errno));
+ if (connect(s, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
+ fprintf(stderr, "can't connect: %s\n",
+ strerror(errno));
exit(3);
}
- alarm(0);
- signal(SIGALRM, SIG_IGN);
- return (s);
+ return s;
}
-/*
- * convert service and host entries into a six-byte numeric in the format
- * expected by a SOCKS v4 server
- */
-void numericize(char *buf, char *host, char *service, char *protocol)
-{
- struct hostent *phe;
- struct servent *pse;
- struct sockaddr_in sin;
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
-
- pse = getservbyname(service, protocol);
- if (pse) {
- sin.sin_port = pse->s_port;
- } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
- fprintf(stderr, "Can't get %s service entry: %s\n",
- service, strerror(errno));
- exit(3);
- }
- buf[1] = (((sin.sin_port) & 0xFF00) >> 8);
- buf[0] = ((sin.sin_port) & 0x00FF);
-
- phe = gethostbyname(host);
- if (phe) {
- memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
- } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
- fprintf(stderr, "Can't get %s host entry: %s\n",
- host, strerror(errno));
- exit(3);
- }
- buf[5] = ((sin.sin_addr.s_addr) & 0xFF000000) >> 24;
- buf[4] = ((sin.sin_addr.s_addr) & 0x00FF0000) >> 16;
- buf[3] = ((sin.sin_addr.s_addr) & 0x0000FF00) >> 8;
- buf[2] = ((sin.sin_addr.s_addr) & 0x000000FF);
-}
/*
* input binary data from socket
strip_trailing_nonprint(fromline);
sprintf(buf, "%d", SMTP_PORT);
- serv_sock = connectsock("localhost", buf, "tcp");
+ serv_sock = uds_connectsock("smtp.socket");
serv_gets(buf);
fprintf(stderr, "%s\n", buf);
if (buf[0]!='2') cleanup(1);
}
void CtdlRegisterServiceHook(int tcp_port,
+ char *sockpath,
void (*h_greeting_function) (void),
void (*h_command_function) (void) )
{
mallok(sizeof(struct ServiceFunctionHook));
newfcn->next = ServiceHookTable;
newfcn->tcp_port = tcp_port;
+ newfcn->sockpath = sockpath;
newfcn->h_greeting_function = h_greeting_function;
newfcn->h_command_function = h_command_function;
- newfcn->msock = ig_tcp_server(tcp_port, config.c_maxsessions);
+
+ if (sockpath != NULL) {
+ newfcn->msock = ig_uds_server(sockpath, config.c_maxsessions);
+ }
+ else {
+ newfcn->msock = ig_tcp_server(tcp_port, config.c_maxsessions);
+ }
if (newfcn->msock >= 0) {
ServiceHookTable = newfcn;
void CtdlRegisterCleanupHook(void (*fcn_ptr)(void));
void CtdlRegisterProtoHook(void (*handler)(char *), char *cmd, char *desc);
void CtdlRegisterServiceHook(int tcp_port,
+ char *sockpath,
void (*h_greeting_function) (void),
void (*h_command_function) (void) ) ;
*
*/
-#define DEFAULT_HOST "127.0.0.1"
-#define DEFAULT_PORT "citadel"
+#define UDS "citadel unix domain socket type of thing"
+
+#define DEFAULT_HOST UDS
+#define DEFAULT_PORT "citadel"
#include "sysdep.h"
struct servent *pse;
struct protoent *ppe;
struct sockaddr_in sin;
- struct sockaddr_un sun;
int s, type;
-
- if ( (!strcmp(protocol, "unix")) || (atoi(service)<0) ) {
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_UNIX;
- sprintf(sun.sun_path, USOCKPATH, 0-atoi(service) );
-
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if (s < 0) {
- fprintf(stderr, "Can't create socket: %s\n",
- strerror(errno));
- logoff(3);
- }
-
- if (connect(s, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
- fprintf(stderr, "can't connect: %s\n",
- strerror(errno));
- logoff(3);
- }
-
- return s;
- }
-
-
- /* otherwise it's a network connection */
-
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
return (s);
}
+int uds_connectsock(char *sockpath)
+{
+ struct sockaddr_un sun;
+ int s;
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ strncpy(sun.sun_path, sockpath, sizeof sun.sun_path);
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ fprintf(stderr, "Can't create socket: %s\n",
+ strerror(errno));
+ logoff(3);
+ }
+
+ if (connect(s, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
+ fprintf(stderr, "can't connect: %s\n",
+ strerror(errno));
+ logoff(3);
+ }
+
+ return s;
+}
+
/*
* convert service and host entries into a six-byte numeric in the format
* expected by a SOCKS v4 server
char socks4[256];
char buf[256];
struct passwd *p;
+ char sockpath[256];
strcpy(cithost, DEFAULT_HOST); /* default host */
strcpy(citport, DEFAULT_PORT); /* default port */
server_is_local = 0;
if ((!strcmp(cithost, "localhost"))
- || (!strcmp(cithost, "127.0.0.1")))
+ || (!strcmp(cithost, "127.0.0.1"))
+ || (!strcmp(cithost, "uds")))
server_is_local = 1;
+ /* If we're using a unix domain socket we can do a bunch of stuff */
+ if (!strcmp(cithost, UDS)) {
+ sprintf(sockpath, "%s/citadel.socket", BBSDIR);
+ serv_sock = uds_connectsock(sockpath);
+ return;
+ }
+
/* if not using a SOCKS proxy server, make the connection directly */
if (strlen(socks4) == 0) {
serv_sock = connectsock(cithost, citport, "tcp");
{
SYM_POP3 = CtdlGetDynamicSymbol();
CtdlRegisterServiceHook(POP3_PORT,
+ NULL,
pop3_greeting,
pop3_command_loop);
CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP);
{
SYM_SMTP = CtdlGetDynamicSymbol();
SYM_SMTP_RECP = CtdlGetDynamicSymbol();
- CtdlRegisterServiceHook(SMTP_PORT,
+
+ CtdlRegisterServiceHook(SMTP_PORT, /* On the net... */
+ NULL,
smtp_greeting,
smtp_command_loop);
+
+ CtdlRegisterServiceHook(0, /* ...and locally */
+ "smtp.socket",
+ smtp_greeting,
+ smtp_command_loop);
+
create_room(SMTP_SPOOLOUT_ROOM, 3, "", 0);
CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
return "$Id$";
struct ServiceFunctionHook {
struct ServiceFunctionHook *next;
int tcp_port;
+ char *sockpath;
void (*h_greeting_function) (void) ;
void (*h_command_function) (void) ;
int msock;
* This is a generic function to set up a master socket for listening on
* a TCP port. The server shuts down if the bind fails.
*
- * If a negative number is specified, a Unix domain socket is created.
*/
int ig_tcp_server(int port_number, int queue_len)
{
struct sockaddr_in sin;
- struct sockaddr_un addr;
int s, i;
- int is_unix = 0;
- if (port_number < 0) {
- is_unix = 1;
- }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons((u_short)port_number);
- if (is_unix) {
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- sprintf(addr.sun_path, USOCKPATH, 0-port_number);
- }
- else {
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons((u_short)port_number);
+ s = socket(PF_INET, SOCK_STREAM,
+ (getprotobyname("tcp")->p_proto));
+
+ if (s < 0) {
+ lprintf(1, "citserver: Can't create a socket: %s\n",
+ strerror(errno));
+ return(-1);
}
- if (is_unix) {
- s = socket(AF_UNIX, SOCK_STREAM, 0);
+ i = 1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ lprintf(1, "citserver: Can't bind: %s\n",
+ strerror(errno));
+ return(-1);
}
- else {
- s = socket(PF_INET, SOCK_STREAM,
- (getprotobyname("tcp")->p_proto));
+
+ if (listen(s, queue_len) < 0) {
+ lprintf(1, "citserver: Can't listen: %s\n", strerror(errno));
+ return(-1);
}
+ return(s);
+}
+
+
+
+/*
+ * Create a Unix domain socket and listen on it
+ */
+int ig_uds_server(char *sockpath, int queue_len)
+{
+ struct sockaddr_un addr;
+ int s;
+
+ unlink(sockpath);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0) {
lprintf(1, "citserver: Can't create a socket: %s\n",
strerror(errno));
return(-1);
}
- /* Set the SO_REUSEADDR socket option, because it makes sense. */
- if (!is_unix) {
- i = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
- }
-
- if (is_unix) {
- if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- lprintf(1, "citserver: Can't bind: %s\n",
- strerror(errno));
- return(-1);
- }
- }
- else {
- if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
- lprintf(1, "citserver: Can't bind: %s\n",
- strerror(errno));
- return(-1);
- }
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ lprintf(1, "citserver: Can't bind: %s\n",
+ strerror(errno));
+ return(-1);
}
if (listen(s, queue_len) < 0) {
*/
void sysdep_master_cleanup(void) {
struct ServiceFunctionHook *serviceptr;
- char sockpath[256];
/*
* close all protocol master sockets
close(serviceptr->msock);
/* If it's a Unix domain socket, remove the file. */
- if (serviceptr->tcp_port < 0) {
- sprintf(sockpath, USOCKPATH, 0-(serviceptr->tcp_port));
- lprintf(9, "Removing <%s>\n", sockpath);
- unlink(sockpath);
+ if (serviceptr->sockpath != NULL) {
+ unlink(serviceptr->sockpath);
}
}
}
* Bind the server to our favorite ports.
*/
CtdlRegisterServiceHook(config.c_port_number, /* TCP */
+ NULL,
citproto_begin_session,
do_command_loop);
- CtdlRegisterServiceHook(0-config.c_port_number, /* Unix */
+ CtdlRegisterServiceHook(0, /* TCP */
+ "citadel.socket",
citproto_begin_session,
do_command_loop);
void begin_critical_section (int which_one);
void end_critical_section (int which_one);
int ig_tcp_server (int port_number, int queue_len);
+int ig_uds_server(char *sockpath, int queue_len);
struct CitContext *MyContext (void);
struct CitContext *CreateNewContext (void);
void InitMyContext (struct CitContext *con);