From 914e0ac3020b7c842f2a1fd975217f70fa705449 Mon Sep 17 00:00:00 2001
From: erdgeist <>
Date: Wed, 25 Apr 2012 05:48:16 +0000
Subject: [PATCH] Add functionality to distribute udp to several workers

---
 opentracker.c           | 11 ++++++++++-
 opentracker.conf.sample |  9 +++++++++
 ot_udp.c                | 31 ++++++++++++++++++++++++++++++-
 ot_udp.h                |  3 ++-
 4 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/opentracker.c b/opentracker.c
index 0c535ec..c735393 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -46,6 +46,7 @@ int          g_self_pipe[2];
 
 static char * g_serverdir;
 static char * g_serveruser;
+static unsigned int g_udp_workers;
 
 static void panic( const char *routine ) {
   fprintf( stderr, "%s: %s\n", routine, strerror(errno) );
@@ -328,7 +329,11 @@ static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) {
 
   io_setcookie( sock, (void*)proto );
 
-  io_wantread( sock );
+  if( (proto == FLAG_UDP) && g_udp_workers ) {
+    io_block( sock );
+    udp_init( sock, g_udp_workers );
+  } else
+    io_wantread( sock );
 
 #ifdef _DEBUG
   fputs( " success.\n", stderr);
@@ -416,6 +421,10 @@ int parse_configfile( char * config_filename ) {
       if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error;
       ot_try_bind( tmpip, tmpport, FLAG_UDP );
       ++bound;
+    } else if(!byte_diff(p,18,"listen.udp.workers" ) && isspace(p[18])) {
+      char *value = p + 18;
+      while( isspace(*value) ) ++value;
+      scan_uint( value, &g_udp_workers );
 #ifdef WANT_ACCESSLIST_WHITE
     } else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) {
       set_config_option( &g_accesslist_filename, p+17 );
diff --git a/opentracker.conf.sample b/opentracker.conf.sample
index f5d88d3..db45122 100644
--- a/opentracker.conf.sample
+++ b/opentracker.conf.sample
@@ -7,6 +7,15 @@
 #      If no listen option is given (here or on the command line), opentracker
 #      listens on 0.0.0.0:6969 tcp and udp.
 #
+#      The next variable determines if udp sockets are handled in the event
+#      loop (set it to 0, the default) or are handled in blocking reads in
+#      dedicated worker threads. You have to set this value before the
+#      listen.tcp_udp or listen.udp statements before it takes effect, but you
+#      can re-set it for each listen statement. Normally you should keep it at
+#      the top of the config file.
+#
+# listen.udp.workers 4
+#
 # listen.tcp_udp 0.0.0.0
 # listen.tcp_udp 192.168.0.1:80
 # listen.tcp_udp 10.0.0.5:6969
diff --git a/ot_udp.c b/ot_udp.c
index e891494..d3fb82a 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -4,6 +4,8 @@
    $id$ */
 
 /* System */
+#include <stdlib.h>
+#include <pthread.h>
 #include <string.h>
 #include <arpa/inet.h>
 #include <stdio.h>
@@ -120,8 +122,35 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
   return 1;
 }
 
-void udp_init( ) {
+static void* udp_worker( void * args ) {
+  int64 sock = (int64)args;
+  struct ot_workstruct ws;
+  memset( &ws, 0, sizeof(ws) );
 
+  ws.inbuf=malloc(G_INBUF_SIZE);
+  ws.outbuf=malloc(G_OUTBUF_SIZE);
+#ifdef    _DEBUG_HTTPERROR
+  ws.debugbuf=malloc(G_DEBUGBUF_SIZE);
+#endif
+
+  while( g_opentracker_running )
+    handle_udp6( sock, &ws );
+
+  free( ws.inbuf );
+  free( ws.outbuf );
+#ifdef    _DEBUG_HTTPERROR
+  free( ws.debugbuf );
+#endif
+  return NULL;
+}
+
+void udp_init( int64 sock, unsigned int worker_count ) {
+  pthread_t thread_id;
+#ifdef _DEBUG
+  fprintf( stderr, " installing %d workers on udp socket %ld", worker_count, (unsigned long)sock );
+#endif
+  while( worker_count-- )
+    pthread_create( &thread_id, NULL, udp_worker, (void *)sock );
 }
 
 const char *g_version_udp_c = "$Source$: $Revision$\n";
diff --git a/ot_udp.h b/ot_udp.h
index dea10ab..a4f6ce0 100644
--- a/ot_udp.h
+++ b/ot_udp.h
@@ -6,6 +6,7 @@
 #ifndef __OT_UDP_H__
 #define __OT_UDP_H__
 
-int handle_udp6( int64 serversocket, struct ot_workstruct *ws );
+void udp_init( int64 sock, unsigned int worker_count );
+int  handle_udp6( int64 serversocket, struct ot_workstruct *ws );
 
 #endif