From 3eb8564b5dbdd82fc9b6d589c632cedbff52d9fb Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Sun, 23 Jun 2002 11:25:45 +0000
Subject: [PATCH] Initial support for UDP services.

---
 src/sbbs3/services.c | 109 ++++++++++++++++++++++++++++++++++++-------
 src/sbbs3/services.h |   3 ++
 2 files changed, 95 insertions(+), 17 deletions(-)

diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index 1a05100c52..b1a7664022 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -73,6 +73,7 @@
 
 #define MAX_SERVICES			128
 #define TIMEOUT_THREAD_WAIT		60		/* Seconds */
+#define MAX_UDP_BUF_LEN			8192	/* 8K */
 
 static services_startup_t* startup=NULL;
 static scfg_t	scfg;
@@ -101,6 +102,9 @@ typedef struct {
 	client_t*		client;
 	service_t*		service;
 	ulong			js_loop;
+	/* Initial UDP datagram */
+	BYTE*			udp_buf;
+	int				udp_len;
 } service_client_t;
 
 static service_t	*service;
@@ -580,6 +584,7 @@ static void js_service_thread(void* arg)
 	int						argc=0;
 	JSString*				arg_str;
 	JSObject*				argv;
+	JSString*				datagram;
 	JSObject*				js_glob;
 	JSScript*				js_script;
 	JSRuntime*				js_runtime;
@@ -708,6 +713,16 @@ static void js_service_thread(void* arg)
 	val = BOOLEAN_TO_JSVAL(JS_FALSE);
 	JS_SetProperty(js_cx, js_glob, "logged_in", &val);
 
+	if(service->options&SERVICE_OPT_UDP 
+		&& service_client.udp_buf != NULL
+		&& service_client.udp_len > 0) {
+		datagram = JS_NewStringCopyN(js_cx, service_client.udp_buf, service_client.udp_len);
+		val = STRING_TO_JSVAL(datagram);
+	} else
+		val = JSVAL_VOID;
+	JS_SetProperty(js_cx, js_glob, "datagram", &val);
+	FREE_AND_NULL(service_client.udp_buf);
+
 	js_script=JS_CompileFile(js_cx, js_glob, spath);
 
 	if(js_script==NULL) 
@@ -979,6 +994,8 @@ void DLLCALL services_thread(void* arg)
 	socklen_t		client_addr_len;
 	SOCKET			socket;
 	SOCKET			client_socket;
+	BYTE*			udp_buf = NULL;
+	int				udp_len;
 	int				i;
 	int				result;
 	ulong			total_clients;
@@ -1093,7 +1110,9 @@ void DLLCALL services_thread(void* arg)
 
 			service[i].socket=INVALID_SOCKET;
 
-			if((socket = open_socket(SOCK_STREAM))==INVALID_SOCKET) {
+			if((socket = open_socket(
+				(service[i].options&SERVICE_OPT_UDP) ? SOCK_DGRAM : SOCK_STREAM))
+				==INVALID_SOCKET) {
 				lprintf("!ERROR %d opening socket", ERROR_VALUE);
 				cleanup(1);
 				return;
@@ -1117,14 +1136,18 @@ void DLLCALL services_thread(void* arg)
 				continue;
 			}
 
-			lprintf("%04d %s socket bound to port %u"
-				,socket, service[i].protocol, service[i].port);
+			lprintf("%04d %s socket bound to %s port %u"
+				,socket, service[i].protocol
+				,service[i].options&SERVICE_OPT_UDP ? "UDP" : "TCP"
+				,service[i].port);
 
-			if(listen(socket,10)!=0) {
-				lprintf("%04d !ERROR %d listening on %s socket"
-					,socket, ERROR_VALUE, service[i].protocol);
-				close_socket(socket);
-				continue;
+			if(!(service[i].options&SERVICE_OPT_UDP)) {
+				if(listen(socket,10)!=0) {
+					lprintf("%04d !ERROR %d listening on %s socket"
+						,socket, ERROR_VALUE, service[i].protocol);
+					close_socket(socket);
+					continue;
+				}
 			}
 			service[i].socket=socket;
 			total_sockets++;
@@ -1205,15 +1228,61 @@ void DLLCALL services_thread(void* arg)
 					continue;
 
 				client_addr_len = sizeof(client_addr);
-				if((client_socket=accept(service[i].socket,
-					(struct sockaddr *)&client_addr,&client_addr_len))==INVALID_SOCKET) {
-					if(ERROR_VALUE == ENOTSOCK)
-            			lprintf("%04d %s socket closed while listening"
-							,service[i].socket, service[i].protocol);
-					else
-						lprintf("%04d %s !ERROR %d accept failed", 
-							service[i].socket, service[i].protocol, ERROR_VALUE);
-					break;
+
+				if(service[i].options&SERVICE_OPT_UDP) {
+					/* UDP */
+					if((udp_buf = (BYTE*)calloc(1, MAX_UDP_BUF_LEN)) == NULL) {
+						lprintf("%04d %s !ERROR %d allocating UDP buffer"
+							,service[i].socket, service[i].protocol, errno);
+						break;
+					}
+
+					udp_len = recvfrom(service[i].socket
+						,udp_buf, MAX_UDP_BUF_LEN, 0 /* flags */
+						,(struct sockaddr *)&client_addr, &client_addr_len);
+					if(udp_len<1) {
+						FREE_AND_NULL(udp_buf);
+						lprintf("%04d %s !ERROR %d recvfrom failed"
+							,service[i].socket, service[i].protocol, ERROR_VALUE);
+						break;
+					}
+
+					if((client_socket = open_socket(SOCK_DGRAM))
+						==INVALID_SOCKET) {
+						FREE_AND_NULL(udp_buf);
+						lprintf("%04d %s !ERROR %d opening socket"
+							,service[i].socket, service[i].protocol, ERROR_VALUE);
+						break;
+					}
+
+					/* Set client address as default addres for send/recv */
+					if(connect(client_socket
+						,(struct sockaddr *)&client_addr, client_addr_len)!=0) {
+						FREE_AND_NULL(udp_buf);
+						lprintf("%04d %s !ERROR %d connect failed"
+							,client_socket, service[i].protocol, ERROR_VALUE);
+						break;
+					}
+#if 0
+					if(send(client_socket,"test\r\n",6,0)!=6) {
+						FREE_AND_NULL(udp_buf);
+						lprintf("%04d %s !SEND TEST ERROR %d"
+						,client_socket, service[i].protocol, ERROR_VALUE);
+						break;
+					}
+#endif
+				} else { 
+					/* TCP */
+					if((client_socket=accept(service[i].socket
+						,(struct sockaddr *)&client_addr, &client_addr_len))==INVALID_SOCKET) {
+						if(ERROR_VALUE == ENOTSOCK)
+            				lprintf("%04d %s socket closed while listening"
+								,service[i].socket, service[i].protocol);
+						else
+							lprintf("%04d %s !ERROR %d accept failed" 
+								,service[i].socket, service[i].protocol, ERROR_VALUE);
+						break;
+					}
 				}
 				strcpy(host_ip,inet_ntoa(client_addr.sin_addr));
 
@@ -1236,6 +1305,7 @@ void DLLCALL services_thread(void* arg)
 #endif
 
 				if(trashcan(&scfg,host_ip,"ip")) {
+					FREE_AND_NULL(udp_buf);
 					lprintf("%04d !%s CLIENT BLOCKED in ip.can: %s"
 						,client_socket, service[i].protocol, host_ip);
 					mswait(3000);
@@ -1244,6 +1314,7 @@ void DLLCALL services_thread(void* arg)
 				}
 
 				if((client=malloc(sizeof(service_client_t)))==NULL) {
+					FREE_AND_NULL(udp_buf);
 					lprintf("%04d !%s ERROR allocating %u bytes of memory for service_client"
 						,client_socket, service[i].protocol, sizeof(service_client_t));
 					mswait(3000);
@@ -1259,6 +1330,10 @@ void DLLCALL services_thread(void* arg)
 				client->addr=client_addr;
 				client->service=&service[i];
 				client->service->clients++;		/* this should be mutually exclusive */
+				client->udp_buf=udp_buf;
+				client->udp_len=udp_len;
+
+				udp_buf = NULL;
 
 				SAFECOPY(cmd,service[i].cmd);
 				strlwr(cmd);
diff --git a/src/sbbs3/services.h b/src/sbbs3/services.h
index 24b31257f7..c5a3863fa6 100644
--- a/src/sbbs3/services.h
+++ b/src/sbbs3/services.h
@@ -81,6 +81,9 @@ typedef struct {
 
 } services_startup_t;
 
+/* Option bit definitions	*/
+#define SERVICE_OPT_UDP		(1<<0)	/* UDP Socket */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
-- 
GitLab