summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c878
1 files changed, 490 insertions, 388 deletions
diff --git a/opentracker.c b/opentracker.c
index 2ca9e06..f63db72 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -5,59 +5,59 @@
5 $Id$ */ 5 $Id$ */
6 6
7/* System */ 7/* System */
8#include <stdlib.h>
9#include <string.h>
10#include <arpa/inet.h> 8#include <arpa/inet.h>
11#include <sys/socket.h> 9#include <ctype.h>
12#include <unistd.h>
13#include <errno.h> 10#include <errno.h>
11#include <pthread.h>
12#include <pwd.h>
14#include <signal.h> 13#include <signal.h>
15#include <stdio.h> 14#include <stdio.h>
16#include <pwd.h> 15#include <stdlib.h>
17#include <ctype.h> 16#include <string.h>
18#include <pthread.h> 17#include <sys/socket.h>
18#include <unistd.h>
19#ifdef WANT_SYSLOGS 19#ifdef WANT_SYSLOGS
20#include <syslog.h> 20#include <syslog.h>
21#endif 21#endif
22 22
23/* Libowfat */ 23/* Libowfat */
24#include "socket.h" 24#include "byte.h"
25#include "io.h" 25#include "io.h"
26#include "iob.h" 26#include "iob.h"
27#include "byte.h"
28#include "scan.h"
29#include "ip6.h" 27#include "ip6.h"
28#include "scan.h"
29#include "socket.h"
30 30
31/* Opentracker */ 31/* Opentracker */
32#include "trackerlogic.h"
33#include "ot_mutex.h"
34#include "ot_http.h"
35#include "ot_udp.h"
36#include "ot_accesslist.h" 32#include "ot_accesslist.h"
37#include "ot_stats.h" 33#include "ot_http.h"
38#include "ot_livesync.h" 34#include "ot_livesync.h"
35#include "ot_mutex.h"
36#include "ot_stats.h"
37#include "ot_udp.h"
38#include "trackerlogic.h"
39 39
40/* Globals */ 40/* Globals */
41time_t g_now_seconds; 41time_t g_now_seconds;
42char * g_redirecturl; 42char *g_redirecturl;
43uint32_t g_tracker_id; 43uint32_t g_tracker_id;
44volatile int g_opentracker_running = 1; 44volatile int g_opentracker_running = 1;
45int g_self_pipe[2]; 45int g_self_pipe[2];
46 46
47static char * g_serverdir; 47static char *g_serverdir;
48static char * g_serveruser; 48static char *g_serveruser;
49static unsigned int g_udp_workers; 49static unsigned int g_udp_workers;
50 50
51static void panic( const char *routing ) __attribute__ ((noreturn)); 51static void panic(const char *routine) __attribute__((noreturn));
52static void panic( const char *routine ) { 52static void panic(const char *routine) {
53 fprintf( stderr, "%s: %s\n", routine, strerror(errno) ); 53 fprintf(stderr, "%s: %s\n", routine, strerror(errno));
54 exit( 111 ); 54 exit(111);
55} 55}
56 56
57static void signal_handler( int s ) { 57static void signal_handler(int s) {
58 if( s == SIGINT ) { 58 if (s == SIGINT) {
59 /* Any new interrupt signal quits the application */ 59 /* Any new interrupt signal quits the application */
60 signal( SIGINT, SIG_DFL); 60 signal(SIGINT, SIG_DFL);
61 61
62 /* Tell all other threads to not acquire any new lock on a bucket 62 /* Tell all other threads to not acquire any new lock on a bucket
63 but cancel their operations and return */ 63 but cancel their operations and return */
@@ -69,219 +69,232 @@ static void signal_handler( int s ) {
69 closelog(); 69 closelog();
70#endif 70#endif
71 71
72 exit( 0 ); 72 exit(0);
73 } else if( s == SIGALRM ) {
74 /* Maintain our copy of the clock. time() on BSDs is very expensive. */
75 g_now_seconds = time(NULL);
76 alarm(5);
77 } 73 }
78} 74}
79 75
80static void defaul_signal_handlers( void ) { 76static void defaul_signal_handlers(void) {
81 sigset_t signal_mask; 77 sigset_t signal_mask;
82 sigemptyset(&signal_mask); 78 sigemptyset(&signal_mask);
83 sigaddset (&signal_mask, SIGPIPE); 79 sigaddset(&signal_mask, SIGPIPE);
84 sigaddset (&signal_mask, SIGHUP); 80 sigaddset(&signal_mask, SIGHUP);
85 sigaddset (&signal_mask, SIGINT); 81 sigaddset(&signal_mask, SIGINT);
86 sigaddset (&signal_mask, SIGALRM); 82 sigaddset(&signal_mask, SIGALRM);
87 pthread_sigmask (SIG_BLOCK, &signal_mask, NULL); 83 pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
88} 84}
89 85
90static void install_signal_handlers( void ) { 86static void install_signal_handlers(void) {
91 struct sigaction sa; 87 struct sigaction sa;
92 sigset_t signal_mask; 88 sigset_t signal_mask;
93 sigemptyset(&signal_mask); 89 sigemptyset(&signal_mask);
94 90
95 sa.sa_handler = signal_handler; 91 sa.sa_handler = signal_handler;
96 sigemptyset(&sa.sa_mask); 92 sigemptyset(&sa.sa_mask);
97 sa.sa_flags = SA_RESTART; 93 sa.sa_flags = SA_RESTART;
98 if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1) ) 94 if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1))
99 panic( "install_signal_handlers" ); 95 panic("install_signal_handlers");
100 96
101 sigaddset (&signal_mask, SIGINT); 97 sigaddset(&signal_mask, SIGINT);
102 sigaddset (&signal_mask, SIGALRM); 98 pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL);
103 pthread_sigmask (SIG_UNBLOCK, &signal_mask, NULL);
104} 99}
105 100
106static void usage( char *name ) { 101static void usage(char *name) {
107 fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip] [-f config] [-s livesyncport]" 102 fprintf(stderr,
103 "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-f config] [-s livesyncport]"
108#ifdef WANT_ACCESSLIST_BLACK 104#ifdef WANT_ACCESSLIST_BLACK
109 " [-b blacklistfile]" 105 " [-b blacklistfile]"
110#elif defined ( WANT_ACCESSLIST_WHITE ) 106#elif defined(WANT_ACCESSLIST_WHITE)
111 " [-w whitelistfile]" 107 " [-w whitelistfile]"
112#endif 108#endif
113 "\n", name ); 109 "\n",
110 name);
114} 111}
115 112
116#define HELPLINE(opt,desc) fprintf(stderr, "\t%-10s%s\n",opt,desc) 113#define HELPLINE(opt, desc) fprintf(stderr, "\t%-10s%s\n", opt, desc)
117static void help( char *name ) { 114static void help(char *name) {
118 usage( name ); 115 usage(name);
119 116
120 HELPLINE("-f config","include and execute the config file"); 117 HELPLINE("-f config", "include and execute the config file");
121 HELPLINE("-i ip","specify ip to bind to (default: *, you may specify more than one)"); 118 HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)");
122 HELPLINE("-p port","specify tcp port to bind to (default: 6969, you may specify more than one)"); 119 HELPLINE("-p port", "do bind to tcp port (default: 6969, you may specify more than one)");
123 HELPLINE("-P port","specify udp port to bind to (default: 6969, you may specify more than one)"); 120 HELPLINE("-P port", "do bind to udp port (default: 6969, you may specify more than one)");
124 HELPLINE("-r redirecturl","specify url where / should be redirected to (default none)"); 121 HELPLINE("-r redirecturl", "specify url where / should be redirected to (default none)");
125 HELPLINE("-d dir","specify directory to try to chroot to (default: \".\")"); 122 HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")");
126 HELPLINE("-u user","specify user under whose privileges opentracker should run (default: \"nobody\")"); 123 HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")");
127 HELPLINE("-A ip","bless an ip address as admin address (e.g. to allow syncs from this address)"); 124 HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)");
128#ifdef WANT_ACCESSLIST_BLACK 125#ifdef WANT_ACCESSLIST_BLACK
129 HELPLINE("-b file","specify blacklist file."); 126 HELPLINE("-b file", "specify blacklist file.");
130#elif defined( WANT_ACCESSLIST_WHITE ) 127#elif defined(WANT_ACCESSLIST_WHITE)
131 HELPLINE("-w file","specify whitelist file."); 128 HELPLINE("-w file", "specify whitelist file.");
132#endif 129#endif
133 130
134 fprintf( stderr, "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -f ./opentracker.conf -i 10.1.1.23 -p 2710 -p 80\n" ); 131 fprintf(stderr, "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -f ./opentracker.conf -i 10.1.1.23 -p 2710 -p 80\n");
132 fprintf(stderr, " Here -i 127.0.0.1 selects the ip address for the next -p 6969 and -P 6969.\n");
133 fprintf(stderr, " If no port is bound from config file or command line, the last address given\n");
134 fprintf(stderr, " (or ::1 if none is set) will be used on port 6969.\n");
135} 135}
136#undef HELPLINE 136#undef HELPLINE
137 137
138static ssize_t header_complete( char * request, ssize_t byte_count ) { 138static ssize_t header_complete(char *request, ssize_t byte_count) {
139 ssize_t i = 0, state = 0; 139 ssize_t i = 0, state = 0;
140 140
141 for( i=1; i < byte_count; i+=2 ) 141 for (i = 1; i < byte_count; i += 2)
142 if( request[i] <= 13 ) { 142 if (request[i] <= 13) {
143 i--; 143 i--;
144 for( state = 0 ; i < byte_count; ++i ) { 144 for (state = 0; i < byte_count; ++i) {
145 char c = request[i]; 145 char c = request[i];
146 if( c == '\r' || c == '\n' ) 146 if (c == '\r' || c == '\n')
147 state = ( state >> 2 ) | ( ( c << 6 ) & 0xc0 ); 147 state = (state >> 2) | ((c << 6) & 0xc0);
148 else 148 else
149 break; 149 break;
150 if( state >= 0xa0 || state == 0x99 ) return i + 1; 150 if (state >= 0xa0 || state == 0x99)
151 return i + 1;
151 } 152 }
152 } 153 }
153 return 0; 154 return 0;
154} 155}
155 156
156static void handle_dead( const int64 sock ) { 157static void handle_dead(const int64 sock) {
157 struct http_data* cookie=io_getcookie( sock ); 158 struct http_data *cookie = io_getcookie(sock);
158 if( cookie ) { 159 if (cookie) {
159 size_t i; 160 size_t i;
160 for ( i = 0; i < cookie->batches; ++i) 161 for (i = 0; i < cookie->batches; ++i)
161 iob_reset( cookie->batch + i ); 162 iob_reset(cookie->batch + i);
162 free( cookie->batch ); 163 free(cookie->batch);
163 array_reset( &cookie->request ); 164 array_reset(&cookie->request);
164 if( cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK ) 165 if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER))
165 mutex_workqueue_canceltask( sock ); 166 mutex_workqueue_canceltask(sock);
166 free( cookie ); 167 free(cookie);
167 } 168 }
168 io_close( sock ); 169 io_close(sock);
169} 170}
170 171
171static void handle_read( const int64 sock, struct ot_workstruct *ws ) { 172static void handle_read(const int64 sock, struct ot_workstruct *ws) {
172 struct http_data* cookie = io_getcookie( sock ); 173 struct http_data *cookie = io_getcookie(sock);
173 ssize_t byte_count = io_tryread( sock, ws->inbuf, G_INBUF_SIZE ); 174 ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE);
174 175
175 if( byte_count == 0 || byte_count == -3 ) { 176 if (byte_count == 0 || byte_count == -3) {
176 handle_dead( sock ); 177 handle_dead(sock);
177 return; 178 return;
178 } 179 }
179 180
180 if( byte_count == -1) 181 if (byte_count == -1)
181 return; 182 return;
182 183
183 /* If we get the whole request in one packet, handle it without copying */ 184 /* If we get the whole request in one packet, handle it without copying */
184 if( !array_start( &cookie->request ) ) { 185 if (!array_start(&cookie->request)) {
185 if( ( ws->header_size = header_complete( ws->inbuf, byte_count ) ) ) { 186 if ((ws->header_size = header_complete(ws->inbuf, byte_count))) {
186 ws->request = ws->inbuf; 187 ws->request = ws->inbuf;
187 ws->request_size = byte_count; 188 ws->request_size = byte_count;
188 http_handle_request( sock, ws ); 189 http_handle_request(sock, ws);
189 } else 190 } else
190 array_catb( &cookie->request, ws->inbuf, (size_t)byte_count ); 191 array_catb(&cookie->request, ws->inbuf, (size_t)byte_count);
191 return; 192 return;
192 } 193 }
193 194
194 array_catb( &cookie->request, ws->inbuf, byte_count ); 195 array_catb(&cookie->request, ws->inbuf, byte_count);
195 if( array_failed( &cookie->request ) || array_bytes( &cookie->request ) > 8192 ) { 196 if (array_failed(&cookie->request) || array_bytes(&cookie->request) > 8192) {
196 http_issue_error( sock, ws, CODE_HTTPERROR_500 ); 197 http_issue_error(sock, ws, CODE_HTTPERROR_500);
197 return; 198 return;
198 } 199 }
199 200
200 while( ( ws->header_size = header_complete( array_start( &cookie->request ), array_bytes( &cookie->request ) ) ) ) { 201 while ((ws->header_size = header_complete(array_start(&cookie->request), array_bytes(&cookie->request)))) {
201 ws->request = array_start( &cookie->request ); 202 ws->request = array_start(&cookie->request);
202 ws->request_size = array_bytes( &cookie->request ); 203 ws->request_size = array_bytes(&cookie->request);
203 http_handle_request( sock, ws ); 204 http_handle_request(sock, ws);
204#ifdef WANT_KEEPALIVE 205#ifdef WANT_KEEPALIVE
205 if( !ws->keep_alive ) 206 if (!ws->keep_alive)
206#endif 207#endif
207 return; 208 return;
208 } 209 }
209} 210}
210 211
211static void handle_write( const int64 sock ) { 212static void handle_write(const int64 sock) {
212 struct http_data* cookie=io_getcookie( sock ); 213 struct http_data *cookie = io_getcookie(sock);
213 size_t i; 214 size_t i;
215 int chunked = 0;
214 216
215 /* Look for the first io_batch still containing bytes to write */ 217 /* Look for the first io_batch still containing bytes to write */
216 if( cookie ) 218 if (cookie) {
217 for( i = 0; i < cookie->batches; ++i ) 219 if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)
218 if( cookie->batch[i].bytesleft ) { 220 chunked = 1;
219 int64 res = iob_send( sock, cookie->batch + i );
220 221
221 if( res == -3 ) 222 for (i = 0; i < cookie->batches; ++i) {
222 break; 223 if (cookie->batch[i].bytesleft) {
224 int64 res = iob_send(sock, cookie->batch + i);
223 225
224 if( !cookie->batch[i].bytesleft ) 226 if (res == -3) {
227 handle_dead(sock);
228 return;
229 }
230
231 if (!cookie->batch[i].bytesleft)
225 continue; 232 continue;
226 233
227 if( res == -1 || res > 0 || i < cookie->batches - 1 ) 234 if (res == -1 || res > 0 || i < cookie->batches - 1)
228 return; 235 return;
229 } 236 }
237 }
238 }
230 239
231 handle_dead( sock ); 240 /* In a chunked transfer after all batches accumulated have been sent, wait for the next one */
241 if (chunked)
242 io_dontwantwrite(sock);
243 else
244 handle_dead(sock);
232} 245}
233 246
234static void handle_accept( const int64 serversocket ) { 247static void handle_accept(const int64 serversocket) {
235 struct http_data *cookie; 248 struct http_data *cookie;
236 int64 sock; 249 int64 sock;
237 ot_ip6 ip; 250 ot_ip6 ip;
238 uint16 port; 251 uint16 port;
239 tai6464 t; 252 tai6464 t;
240 253
241 while( ( sock = socket_accept6( serversocket, ip, &port, NULL ) ) != -1 ) { 254 while ((sock = socket_accept6(serversocket, ip, &port, NULL)) != -1) {
242 255
243 /* Put fd into a non-blocking mode */ 256 /* Put fd into a non-blocking mode */
244 io_nonblock( sock ); 257 io_nonblock(sock);
245 258
246 if( !io_fd( sock ) || 259 if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) {
247 !( cookie = (struct http_data*)malloc( sizeof(struct http_data) ) ) ) { 260 io_close(sock);
248 io_close( sock );
249 continue; 261 continue;
250 } 262 }
251 memset(cookie, 0, sizeof( struct http_data ) ); 263 memset(cookie, 0, sizeof(struct http_data));
252 memcpy(cookie->ip,ip,sizeof(ot_ip6)); 264 memcpy(cookie->ip, ip, sizeof(ot_ip6));
253 265
254 io_setcookie( sock, cookie ); 266 io_setcookie(sock, cookie);
255 io_wantread( sock ); 267 io_wantread(sock);
256 268
257 stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 269 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
258 270
259 /* That breaks taia encapsulation. But there is no way to take system 271 /* That breaks taia encapsulation. But there is no way to take system
260 time this often in FreeBSD and libowfat does not allow to set unix time */ 272 time this often in FreeBSD and libowfat does not allow to set unix time */
261 taia_uint( &t, 0 ); /* Clear t */ 273 taia_uint(&t, 0); /* Clear t */
262 tai_unix( &(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT) ); 274 tai_unix(&(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT));
263 io_timeout( sock, t ); 275 io_timeout(sock, t);
264 } 276 }
265 io_eagain(serversocket); 277 io_eagain(serversocket);
266} 278}
267 279
268static void * server_mainloop( void * args ) { 280static void *server_mainloop(void *args) {
269 struct ot_workstruct ws; 281 struct ot_workstruct ws;
270 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 282 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
271 struct iovec *iovector; 283 struct iovec *iovector;
272 int iovec_entries; 284 size_t iovec_entries;
285 int is_partial;
273 286
274 (void)args; 287 (void)args;
275 288
276 /* Initialize our "thread local storage" */ 289 /* Initialize our "thread local storage" */
277 ws.inbuf = malloc( G_INBUF_SIZE ); 290 ws.inbuf = malloc(G_INBUF_SIZE);
278 ws.outbuf = malloc( G_OUTBUF_SIZE ); 291 ws.outbuf = malloc(G_OUTBUF_SIZE);
279#ifdef _DEBUG_HTTPERROR 292#ifdef _DEBUG_HTTPERROR
280 ws.debugbuf= malloc( G_DEBUGBUF_SIZE ); 293 ws.debugbuf = malloc(G_DEBUGBUF_SIZE);
281#endif 294#endif
282 295
283 if( !ws.inbuf || !ws.outbuf ) 296 if (!ws.inbuf || !ws.outbuf)
284 panic( "Initializing worker failed" ); 297 panic("Initializing worker failed");
285 298
286#ifdef WANT_ARC4RANDOM 299#ifdef WANT_ARC4RANDOM
287 arc4random_buf(&ws.rand48_state[0], 3 * sizeof(uint16_t)); 300 arc4random_buf(&ws.rand48_state[0], 3 * sizeof(uint16_t));
@@ -291,298 +304,332 @@ static void * server_mainloop( void * args ) {
291 ws.rand48_state[2] = (uint16_t)random(); 304 ws.rand48_state[2] = (uint16_t)random();
292#endif 305#endif
293 306
294 for( ; ; ) { 307 for (;;) {
295 int64 sock; 308 int64 sock;
296 309
297 io_wait(); 310 io_wait();
298 311
299 while( ( sock = io_canread( ) ) != -1 ) { 312 while ((sock = io_canread()) != -1) {
300 const void *cookie = io_getcookie( sock ); 313 const void *cookie = io_getcookie(sock);
301 if( (intptr_t)cookie == FLAG_TCP ) 314 if ((intptr_t)cookie == FLAG_TCP)
302 handle_accept( sock ); 315 handle_accept(sock);
303 else if( (intptr_t)cookie == FLAG_UDP ) 316 else if ((intptr_t)cookie == FLAG_UDP)
304 handle_udp6( sock, &ws ); 317 handle_udp6(sock, &ws);
305 else if( (intptr_t)cookie == FLAG_SELFPIPE ) 318 else if ((intptr_t)cookie == FLAG_SELFPIPE)
306 io_tryread( sock, ws.inbuf, G_INBUF_SIZE ); 319 io_tryread(sock, ws.inbuf, G_INBUF_SIZE);
307 else 320 else
308 handle_read( sock, &ws ); 321 handle_read(sock, &ws);
309 } 322 }
310 323
311 while( ( sock = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 ) 324 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
312 http_sendiovecdata( sock, &ws, iovec_entries, iovector ); 325 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
313 326
314 while( ( sock = io_canwrite( ) ) != -1 ) 327 while ((sock = io_canwrite()) != -1)
315 handle_write( sock ); 328 handle_write(sock);
316 329
317 if( g_now_seconds > next_timeout_check ) { 330 if (g_now_seconds > next_timeout_check) {
318 while( ( sock = io_timeouted() ) != -1 ) 331 while ((sock = io_timeouted()) != -1)
319 handle_dead( sock ); 332 handle_dead(sock);
320 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 333 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
321 } 334 }
322 335
323 livesync_ticker(); 336 livesync_ticker();
324
325 /* Enforce setting the clock */
326 signal_handler( SIGALRM );
327 } 337 }
328 return 0; 338 return 0;
329} 339}
330 340
331static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) { 341static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) {
332 int64 sock = proto == FLAG_TCP ? socket_tcp6( ) : socket_udp6( ); 342 int64 sock = proto == FLAG_TCP ? socket_tcp6() : socket_udp6();
333
334#ifndef WANT_V6
335 if( !ip6_isv4mapped(ip) ) {
336 exerr( "V4 Tracker is V4 only!" );
337 }
338#else
339 if( ip6_isv4mapped(ip) ) {
340 exerr( "V6 Tracker is V6 only!" );
341 }
342#endif
343 343
344#ifdef _DEBUG 344#ifdef _DEBUG
345 { 345 {
346 char *protos[] = {"TCP","UDP","UDP mcast"}; 346 char *protos[] = {"TCP", "UDP", "UDP mcast"};
347 char _debug[512]; 347 char _debug[512];
348 int off = snprintf( _debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto] ); 348 int off = snprintf(_debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto]);
349 off += fmt_ip6c( _debug+off, ip); 349 off += fmt_ip6c(_debug + off, ip);
350 snprintf( _debug + off, sizeof(_debug)-off, "]:%d...", port); 350 snprintf(_debug + off, sizeof(_debug) - off, "]:%d...", port);
351 fputs( _debug, stderr ); 351 fputs(_debug, stderr);
352 } 352 }
353#endif 353#endif
354 354
355 if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 ) 355 if (socket_bind6_reuse(sock, ip, port, 0) == -1)
356 panic( "socket_bind6_reuse" ); 356 panic("socket_bind6_reuse");
357 357
358 if( ( proto == FLAG_TCP ) && ( socket_listen( sock, SOMAXCONN) == -1 ) ) 358 if ((proto == FLAG_TCP) && (socket_listen(sock, SOMAXCONN) == -1))
359 panic( "socket_listen" ); 359 panic("socket_listen");
360 360
361 if( !io_fd( sock ) ) 361 if (!io_fd(sock))
362 panic( "io_fd" ); 362 panic("io_fd");
363 363
364 io_setcookie( sock, (void*)proto ); 364 io_setcookie(sock, (void *)proto);
365 365
366 if( (proto == FLAG_UDP) && g_udp_workers ) { 366 if ((proto == FLAG_UDP) && g_udp_workers) {
367 io_block( sock ); 367 io_block(sock);
368 udp_init( sock, g_udp_workers ); 368 udp_init(sock, g_udp_workers);
369 } else 369 } else
370 io_wantread( sock ); 370 io_wantread(sock);
371 371
372#ifdef _DEBUG 372#ifdef _DEBUG
373 fputs( " success.\n", stderr); 373 fputs(" success.\n", stderr);
374#endif 374#endif
375 375
376 return sock; 376 return sock;
377} 377}
378 378
379char * set_config_option( char **option, char *value ) { 379char *set_config_option(char **option, char *value) {
380#ifdef _DEBUG 380#ifdef _DEBUG
381 fprintf( stderr, "Setting config option: %s\n", value ); 381 fprintf(stderr, "Setting config option: %s\n", value);
382#endif 382#endif
383 while( isspace(*value) ) ++value; 383 while (isspace(*value))
384 free( *option ); 384 ++value;
385 return *option = strdup( value ); 385 free(*option);
386 return *option = strdup(value);
386} 387}
387 388
388static int scan_ip6_port( const char *src, ot_ip6 ip, uint16 *port ) { 389static int scan_ip6_port(const char *src, ot_ip6 ip, uint16 *port) {
389 const char *s = src; 390 const char *s = src;
390 int off, bracket = 0; 391 int off, bracket = 0;
391 while( isspace(*s) ) ++s; 392 while (isspace(*s))
392 if( *s == '[' ) ++s, ++bracket; /* for v6 style notation */ 393 ++s;
393 if( !(off = scan_ip6( s, ip ) ) ) 394 if (*s == '[')
395 ++s, ++bracket; /* for v6 style notation */
396 if (!(off = scan_ip6(s, ip)))
394 return 0; 397 return 0;
395 s += off; 398 s += off;
396 if( bracket && *s == ']' ) ++s; 399 if (bracket && *s == ']')
397 if( *s == 0 || isspace(*s)) return s-src; 400 ++s;
398 if( !ip6_isv4mapped(ip)){ 401 if (*s == 0 || isspace(*s))
399 if( *s != ':' && *s != '.' ) return 0; 402 return s - src;
400 if( !bracket && *(s) == ':' ) return 0; 403 if (!ip6_isv4mapped(ip)) {
404 if (*s != ':' && *s != '.')
405 return 0;
406 if (!bracket && *(s) == ':')
407 return 0;
401 s++; 408 s++;
402 } else { 409 } else {
403 if( *(s++) != ':' ) return 0; 410 if (*(s++) != ':')
411 return 0;
412 }
413 if (!(off = scan_ushort(s, port)))
414 return 0;
415 return off + s - src;
416}
417
418static int scan_ip6_net(const char *src, ot_net *net) {
419 const char *s = src;
420 int off;
421 while (isspace(*s))
422 ++s;
423 if (!(off = scan_ip6(s, net->address)))
424 return 0;
425 s += off;
426 if (*s != '/')
427 net->bits = 128;
428 else {
429 s++;
430 if (!(off = scan_int(s, &net->bits)))
431 return 0;
432 if (ip6_isv4mapped(net->address))
433 net->bits += 96;
434 if (net->bits > 128)
435 return 0;
436 s += off;
404 } 437 }
405 if( !(off = scan_ushort (s, port ) ) ) 438 return off + s - src;
406 return 0;
407 return off+s-src;
408} 439}
409 440
410int parse_configfile( char * config_filename ) { 441int parse_configfile(char *config_filename) {
411 FILE * accesslist_filehandle; 442 FILE *accesslist_filehandle;
412 char inbuf[512]; 443 char inbuf[512];
413 ot_ip6 tmpip; 444 ot_ip6 tmpip;
414 int bound = 0; 445#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE)
446 ot_net tmpnet;
447#endif
448 int bound = 0;
415 449
416 accesslist_filehandle = fopen( config_filename, "r" ); 450 accesslist_filehandle = fopen(config_filename, "r");
417 451
418 if( accesslist_filehandle == NULL ) { 452 if (accesslist_filehandle == NULL) {
419 fprintf( stderr, "Warning: Can't open config file: %s.", config_filename ); 453 fprintf(stderr, "Warning: Can't open config file: %s.", config_filename);
420 return 0; 454 return 0;
421 } 455 }
422 456
423 while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) { 457 while (fgets(inbuf, sizeof(inbuf), accesslist_filehandle)) {
424 char *p = inbuf; 458 char *p = inbuf;
425 size_t strl; 459 size_t strl;
426 460
427 /* Skip white spaces */ 461 /* Skip white spaces */
428 while(isspace(*p)) ++p; 462 while (isspace(*p))
463 ++p;
429 464
430 /* Ignore comments and empty lines */ 465 /* Ignore comments and empty lines */
431 if((*p=='#')||(*p=='\n')||(*p==0)) continue; 466 if ((*p == '#') || (*p == '\n') || (*p == 0))
467 continue;
432 468
433 /* consume trailing new lines and spaces */ 469 /* consume trailing new lines and spaces */
434 strl = strlen(p); 470 strl = strlen(p);
435 while( strl && isspace(p[strl-1])) 471 while (strl && isspace(p[strl - 1]))
436 p[--strl] = 0; 472 p[--strl] = 0;
437 473
438 /* Scan for commands */ 474 /* Scan for commands */
439 if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) { 475 if (!byte_diff(p, 15, "tracker.rootdir") && isspace(p[15])) {
440 set_config_option( &g_serverdir, p+16 ); 476 set_config_option(&g_serverdir, p + 16);
441 } else if(!byte_diff(p,12,"tracker.user" ) && isspace(p[12])) { 477 } else if (!byte_diff(p, 12, "tracker.user") && isspace(p[12])) {
442 set_config_option( &g_serveruser, p+13 ); 478 set_config_option(&g_serveruser, p + 13);
443 } else if(!byte_diff(p,14,"listen.tcp_udp" ) && isspace(p[14])) { 479 } else if (!byte_diff(p, 14, "listen.tcp_udp") && isspace(p[14])) {
444 uint16_t tmpport = 6969; 480 uint16_t tmpport = 6969;
445 if( !scan_ip6_port( p+15, tmpip, &tmpport )) goto parse_error; 481 if (!scan_ip6_port(p + 15, tmpip, &tmpport))
446 ot_try_bind( tmpip, tmpport, FLAG_TCP ); ++bound; 482 goto parse_error;
447 ot_try_bind( tmpip, tmpport, FLAG_UDP ); ++bound; 483 ot_try_bind(tmpip, tmpport, FLAG_TCP);
448 } else if(!byte_diff(p,10,"listen.tcp" ) && isspace(p[10])) { 484 ++bound;
485 ot_try_bind(tmpip, tmpport, FLAG_UDP);
486 ++bound;
487 } else if (!byte_diff(p, 10, "listen.tcp") && isspace(p[10])) {
449 uint16_t tmpport = 6969; 488 uint16_t tmpport = 6969;
450 if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error; 489 if (!scan_ip6_port(p + 11, tmpip, &tmpport))
451 ot_try_bind( tmpip, tmpport, FLAG_TCP ); 490 goto parse_error;
491 ot_try_bind(tmpip, tmpport, FLAG_TCP);
452 ++bound; 492 ++bound;
453 } else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) { 493 } else if (!byte_diff(p, 10, "listen.udp") && isspace(p[10])) {
454 uint16_t tmpport = 6969; 494 uint16_t tmpport = 6969;
455 if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error; 495 if (!scan_ip6_port(p + 11, tmpip, &tmpport))
456 ot_try_bind( tmpip, tmpport, FLAG_UDP ); 496 goto parse_error;
497 ot_try_bind(tmpip, tmpport, FLAG_UDP);
457 ++bound; 498 ++bound;
458 } else if(!byte_diff(p,18,"listen.udp.workers" ) && isspace(p[18])) { 499 } else if (!byte_diff(p, 18, "listen.udp.workers") && isspace(p[18])) {
459 char *value = p + 18; 500 char *value = p + 18;
460 while( isspace(*value) ) ++value; 501 while (isspace(*value))
461 scan_uint( value, &g_udp_workers ); 502 ++value;
503 scan_uint(value, &g_udp_workers);
462#ifdef WANT_ACCESSLIST_WHITE 504#ifdef WANT_ACCESSLIST_WHITE
463 } else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) { 505 } else if (!byte_diff(p, 16, "access.whitelist") && isspace(p[16])) {
464 set_config_option( &g_accesslist_filename, p+17 ); 506 set_config_option(&g_accesslist_filename, p + 17);
465#elif defined( WANT_ACCESSLIST_BLACK ) 507#elif defined(WANT_ACCESSLIST_BLACK)
466 } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) { 508 } else if (!byte_diff(p, 16, "access.blacklist") && isspace(p[16])) {
467 set_config_option( &g_accesslist_filename, p+17 ); 509 set_config_option(&g_accesslist_filename, p + 17);
468#endif 510#endif
469#ifdef WANT_DYNAMIC_ACCESSLIST 511#ifdef WANT_DYNAMIC_ACCESSLIST
470 } else if(!byte_diff(p, 15, "access.fifo_add" ) && isspace(p[15])) { 512 } else if (!byte_diff(p, 15, "access.fifo_add") && isspace(p[15])) {
471 set_config_option( &g_accesslist_pipe_add, p+16 ); 513 set_config_option(&g_accesslist_pipe_add, p + 16);
472 } else if(!byte_diff(p, 18, "access.fifo_delete" ) && isspace(p[18])) { 514 } else if (!byte_diff(p, 18, "access.fifo_delete") && isspace(p[18])) {
473 set_config_option( &g_accesslist_pipe_delete, p+19 ); 515 set_config_option(&g_accesslist_pipe_delete, p + 19);
474#endif 516#endif
475#ifdef WANT_RESTRICT_STATS 517#ifdef WANT_RESTRICT_STATS
476 } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) { 518 } else if (!byte_diff(p, 12, "access.stats") && isspace(p[12])) {
477 if( !scan_ip6( p+13, tmpip )) goto parse_error; 519 if (!scan_ip6_net(p + 13, &tmpnet))
478 accesslist_blessip( tmpip, OT_PERMISSION_MAY_STAT ); 520 goto parse_error;
521 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT);
479#endif 522#endif
480 } else if(!byte_diff(p, 17, "access.stats_path" ) && isspace(p[17])) { 523 } else if (!byte_diff(p, 17, "access.stats_path") && isspace(p[17])) {
481 set_config_option( &g_stats_path, p+18 ); 524 set_config_option(&g_stats_path, p + 18);
482#ifdef WANT_IP_FROM_PROXY 525#ifdef WANT_IP_FROM_PROXY
483 } else if(!byte_diff(p, 12, "access.proxy" ) && isspace(p[12])) { 526 } else if (!byte_diff(p, 12, "access.proxy") && isspace(p[12])) {
484 if( !scan_ip6( p+13, tmpip )) goto parse_error; 527 if (!scan_ip6_net(p + 13, &tmpnet))
485 accesslist_blessip( tmpip, OT_PERMISSION_MAY_PROXY ); 528 goto parse_error;
529 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY);
486#endif 530#endif
487 } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) { 531 } else if (!byte_diff(p, 20, "tracker.redirect_url") && isspace(p[20])) {
488 set_config_option( &g_redirecturl, p+21 ); 532 set_config_option(&g_redirecturl, p + 21);
489#ifdef WANT_SYNC_LIVE 533#ifdef WANT_SYNC_LIVE
490 } else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) { 534 } else if (!byte_diff(p, 24, "livesync.cluster.node_ip") && isspace(p[24])) {
491 if( !scan_ip6( p+25, tmpip )) goto parse_error; 535 if (!scan_ip6_net(p + 25, &tmpnet))
492 accesslist_blessip( tmpip, OT_PERMISSION_MAY_LIVESYNC ); 536 goto parse_error;
493 } else if(!byte_diff(p, 23, "livesync.cluster.listen" ) && isspace(p[23])) { 537 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC);
538 } else if (!byte_diff(p, 23, "livesync.cluster.listen") && isspace(p[23])) {
494 uint16_t tmpport = LIVESYNC_PORT; 539 uint16_t tmpport = LIVESYNC_PORT;
495 if( !scan_ip6_port( p+24, tmpip, &tmpport )) goto parse_error; 540 if (!scan_ip6_port(p + 24, tmpip, &tmpport))
496 livesync_bind_mcast( tmpip, tmpport ); 541 goto parse_error;
542 livesync_bind_mcast(tmpip, tmpport);
497#endif 543#endif
498 } else 544 } else
499 fprintf( stderr, "Unhandled line in config file: %s\n", inbuf ); 545 fprintf(stderr, "Unhandled line in config file: %s\n", inbuf);
500 continue; 546 continue;
501 parse_error: 547 parse_error:
502 fprintf( stderr, "Parse error in config file: %s\n", inbuf); 548 fprintf(stderr, "Parse error in config file: %s\n", inbuf);
503 } 549 }
504 fclose( accesslist_filehandle ); 550 fclose(accesslist_filehandle);
505 return bound; 551 return bound;
506} 552}
507 553
508void load_state(const char * const state_filename ) { 554void load_state(const char *const state_filename) {
509 FILE * state_filehandle; 555 FILE *state_filehandle;
510 char inbuf[512]; 556 char inbuf[512];
511 ot_hash infohash; 557 ot_hash infohash;
512 unsigned long long base, downcount; 558 unsigned long long base, downcount;
513 int consumed; 559 int consumed;
514 560
515 state_filehandle = fopen( state_filename, "r" ); 561 state_filehandle = fopen(state_filename, "r");
516 562
517 if( state_filehandle == NULL ) { 563 if (state_filehandle == NULL) {
518 fprintf( stderr, "Warning: Can't open config file: %s.", state_filename ); 564 fprintf(stderr, "Warning: Can't open config file: %s.", state_filename);
519 return; 565 return;
520 } 566 }
521 567
522 /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */ 568 /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */
523 while( fgets( inbuf, sizeof(inbuf), state_filehandle ) ) { 569 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
524 int i; 570 size_t i;
525 for( i=0; i<(int)sizeof(ot_hash); ++i ) { 571 for (i = 0; i < sizeof(ot_hash); ++i) {
526 int eger = 16 * scan_fromhex( inbuf[ 2*i ] ) + scan_fromhex( inbuf[ 1 + 2*i ] ); 572 int eger = 16 * scan_fromhex(inbuf[2 * i]) + scan_fromhex(inbuf[1 + 2 * i]);
527 if( eger < 0 ) 573 if (eger < 0)
528 continue; 574 continue;
529 infohash[i] = eger; 575 infohash[i] = eger;
530 } 576 }
531 577
532 if( i != (int)sizeof(ot_hash) ) continue; 578 if (i != sizeof(ot_hash))
579 continue;
533 i *= 2; 580 i *= 2;
534 581
535 if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &base ) ) ) continue; 582 if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &base)))
583 continue;
536 i += consumed; 584 i += consumed;
537 if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue; 585 if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &downcount)))
538 add_torrent_from_saved_state( infohash, base, downcount ); 586 continue;
587 add_torrent_from_saved_state(infohash, base, downcount);
539 } 588 }
540 589
541 fclose( state_filehandle ); 590 fclose(state_filehandle);
542} 591}
543 592
544int drop_privileges ( const char * const serveruser, const char * const serverdir ) { 593int drop_privileges(const char *const serveruser, const char *const serverdir) {
545 struct passwd *pws = NULL; 594 struct passwd *pws = NULL;
546 595
547#ifdef _DEBUG 596#ifdef _DEBUG
548 if( !geteuid() ) 597 if (!geteuid())
549 fprintf( stderr, "Dropping to user %s.\n", serveruser ); 598 fprintf(stderr, "Dropping to user %s.\n", serveruser);
550 if( serverdir ) 599 if (serverdir)
551 fprintf( stderr, "ch%s'ing to directory %s.\n", geteuid() ? "dir" : "root", serverdir ); 600 fprintf(stderr, "ch%s'ing to directory %s.\n", geteuid() ? "dir" : "root", serverdir);
552#endif 601#endif
553 602
554 /* Grab pws entry before chrooting */ 603 /* Grab pws entry before chrooting */
555 pws = getpwnam( serveruser ); 604 pws = getpwnam(serveruser);
556 endpwent(); 605 endpwent();
557 606
558 if( geteuid() == 0 ) { 607 if (geteuid() == 0) {
559 /* Running as root: chroot and drop privileges */ 608 /* Running as root: chroot and drop privileges */
560 if( serverdir && chroot( serverdir ) ) { 609 if (serverdir && chroot(serverdir)) {
561 fprintf( stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno) ); 610 fprintf(stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno));
562 return -1; 611 return -1;
563 } 612 }
564 613
565 if(chdir("/")) 614 if (chdir("/"))
566 panic("chdir() failed after chrooting: "); 615 panic("chdir() failed after chrooting: ");
567 616
568 /* If we can't find server user, revert to nobody's default uid */ 617 /* If we can't find server user, revert to nobody's default uid */
569 if( !pws ) { 618 if (!pws) {
570 fprintf( stderr, "Warning: Could not get password entry for %s. Reverting to uid -2.\n", serveruser ); 619 fprintf(stderr, "Warning: Could not get password entry for %s. Reverting to uid -2.\n", serveruser);
571 if (setegid( (gid_t)-2 ) || setgid( (gid_t)-2 ) || setuid( (uid_t)-2 ) || seteuid( (uid_t)-2 )) 620 if (setegid((gid_t)-2) || setgid((gid_t)-2) || setuid((uid_t)-2) || seteuid((uid_t)-2))
572 panic("Could not set uid to value -2"); 621 panic("Could not set uid to value -2");
573 } 622 } else {
574 else { 623 if (setegid(pws->pw_gid) || setgid(pws->pw_gid) || setuid(pws->pw_uid) || seteuid(pws->pw_uid))
575 if (setegid( pws->pw_gid ) || setgid( pws->pw_gid ) || setuid( pws->pw_uid ) || seteuid( pws->pw_uid ))
576 panic("Could not set uid to specified value"); 624 panic("Could not set uid to specified value");
577 } 625 }
578 626
579 if( geteuid() == 0 || getegid() == 0 ) 627 if (geteuid() == 0 || getegid() == 0)
580 panic("Still running with root privileges?!"); 628 panic("Still running with root privileges?!");
581 } 629 } else {
582 else {
583 /* Normal user, just chdir() */ 630 /* Normal user, just chdir() */
584 if( serverdir && chdir( serverdir ) ) { 631 if (serverdir && chdir(serverdir)) {
585 fprintf( stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno) ); 632 fprintf(stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno));
586 return -1; 633 return -1;
587 } 634 }
588 } 635 }
@@ -590,118 +637,173 @@ int drop_privileges ( const char * const serveruser, const char * const serverdi
590 return 0; 637 return 0;
591} 638}
592 639
593int main( int argc, char **argv ) { 640/* Maintain our copy of the clock. time() on BSDs is very expensive. */
594 ot_ip6 serverip, tmpip; 641static void *time_caching_worker(void *args) {
595 int bound = 0, scanon = 1; 642 (void)args;
596 uint16_t tmpport; 643 while (1) {
597 char * statefile = 0; 644 g_now_seconds = time(NULL);
645 sleep(5);
646 }
647 return NULL;
648}
598 649
599 memset( serverip, 0, sizeof(ot_ip6) ); 650int main(int argc, char **argv) {
600#ifndef WANT_V6 651 ot_ip6 serverip;
601 serverip[10]=serverip[11]=-1; 652 ot_net tmpnet;
602 noipv6=1; 653 int bound = 0, scanon = 1;
654 uint16_t tmpport;
655 char *statefile = 0;
656 pthread_t thread_id; /* time cacher */
657
658 memset(serverip, 0, sizeof(ot_ip6));
659#ifdef WANT_V4_ONLY
660 serverip[10] = serverip[11] = -1;
603#endif 661#endif
604 662
605#ifdef WANT_DEV_RANDOM 663#ifdef WANT_DEV_RANDOM
606 srandomdev(); 664 srandomdev();
607#else 665#else
608 srandom( time(NULL) ); 666 srandom(time(NULL));
609#endif 667#endif
610 668
611 while( scanon ) { 669 while (scanon) {
612 switch( getopt( argc, argv, ":i:p:A:P:d:u:r:s:f:l:v" 670 switch (getopt(argc, argv,
671 ":i:p:A:P:d:u:r:s:f:l:v"
613#ifdef WANT_ACCESSLIST_BLACK 672#ifdef WANT_ACCESSLIST_BLACK
614"b:" 673 "b:"
615#elif defined( WANT_ACCESSLIST_WHITE ) 674#elif defined(WANT_ACCESSLIST_WHITE)
616"w:" 675 "w:"
617#endif 676#endif
618 "h" ) ) { 677 "h")) {
619 case -1 : scanon = 0; break; 678 case -1:
620 case 'i': 679 scanon = 0;
621 if( !scan_ip6( optarg, serverip )) { usage( argv[0] ); exit( 1 ); } 680 break;
622 break; 681 case 'i':
682 if (!scan_ip6(optarg, serverip)) {
683 usage(argv[0]);
684 exit(1);
685 }
686 break;
623#ifdef WANT_ACCESSLIST_BLACK 687#ifdef WANT_ACCESSLIST_BLACK
624 case 'b': set_config_option( &g_accesslist_filename, optarg); break; 688 case 'b':
625#elif defined( WANT_ACCESSLIST_WHITE ) 689 set_config_option(&g_accesslist_filename, optarg);
626 case 'w': set_config_option( &g_accesslist_filename, optarg); break; 690 break;
691#elif defined(WANT_ACCESSLIST_WHITE)
692 case 'w':
693 set_config_option(&g_accesslist_filename, optarg);
694 break;
627#endif 695#endif
628 case 'p': 696 case 'p':
629 if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); } 697 if (!scan_ushort(optarg, &tmpport)) {
630 ot_try_bind( serverip, tmpport, FLAG_TCP ); bound++; break; 698 usage(argv[0]);
631 case 'P': 699 exit(1);
632 if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); } 700 }
633 ot_try_bind( serverip, tmpport, FLAG_UDP ); bound++; break; 701 ot_try_bind(serverip, tmpport, FLAG_TCP);
702 bound++;
703 break;
704 case 'P':
705 if (!scan_ushort(optarg, &tmpport)) {
706 usage(argv[0]);
707 exit(1);
708 }
709 ot_try_bind(serverip, tmpport, FLAG_UDP);
710 bound++;
711 break;
634#ifdef WANT_SYNC_LIVE 712#ifdef WANT_SYNC_LIVE
635 case 's': 713 case 's':
636 if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); } 714 if (!scan_ushort(optarg, &tmpport)) {
637 livesync_bind_mcast( serverip, tmpport); break; 715 usage(argv[0]);
716 exit(1);
717 }
718 livesync_bind_mcast(serverip, tmpport);
719 break;
638#endif 720#endif
639 case 'd': set_config_option( &g_serverdir, optarg ); break; 721 case 'd':
640 case 'u': set_config_option( &g_serveruser, optarg ); break; 722 set_config_option(&g_serverdir, optarg);
641 case 'r': set_config_option( &g_redirecturl, optarg ); break; 723 break;
642 case 'l': statefile = optarg; break; 724 case 'u':
643 case 'A': 725 set_config_option(&g_serveruser, optarg);
644 if( !scan_ip6( optarg, tmpip )) { usage( argv[0] ); exit( 1 ); } 726 break;
645 accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */ 727 case 'r':
646 break; 728 set_config_option(&g_redirecturl, optarg);
647 case 'f': bound += parse_configfile( optarg ); break; 729 break;
648 case 'h': help( argv[0] ); exit( 0 ); 730 case 'l':
649 case 'v': { 731 statefile = optarg;
650 char buffer[8192]; 732 break;
651 stats_return_tracker_version( buffer ); 733 case 'A':
652 fputs( buffer, stderr ); 734 if (!scan_ip6_net(optarg, &tmpnet)) {
653 exit( 0 ); 735 usage(argv[0]);
736 exit(1);
654 } 737 }
655 default: 738 accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */
656 case '?': usage( argv[0] ); exit( 1 ); 739 break;
740 case 'f':
741 bound += parse_configfile(optarg);
742 break;
743 case 'h':
744 help(argv[0]);
745 exit(0);
746 case 'v': {
747 char buffer[8192];
748 stats_return_tracker_version(buffer);
749 fputs(buffer, stderr);
750 exit(0);
751 }
752 default:
753 case '?':
754 usage(argv[0]);
755 exit(1);
657 } 756 }
658 } 757 }
659 758
660 /* Bind to our default tcp/udp ports */ 759 /* Bind to our default tcp/udp ports */
661 if( !bound) { 760 if (!bound) {
662 ot_try_bind( serverip, 6969, FLAG_TCP ); 761 ot_try_bind(serverip, 6969, FLAG_TCP);
663 ot_try_bind( serverip, 6969, FLAG_UDP ); 762 ot_try_bind(serverip, 6969, FLAG_UDP);
664 } 763 }
665 764
765 defaul_signal_handlers();
766
666#ifdef WANT_SYSLOGS 767#ifdef WANT_SYSLOGS
667 openlog( "opentracker", 0, LOG_USER ); 768 openlog("opentracker", 0, LOG_USER);
668 setlogmask(LOG_UPTO(LOG_INFO)); 769 setlogmask(LOG_UPTO(LOG_INFO));
669#endif 770#endif
670 771
671 if( drop_privileges( g_serveruser ? g_serveruser : "nobody", g_serverdir ) == -1 ) 772 if (drop_privileges(g_serveruser ? g_serveruser : "nobody", g_serverdir) == -1)
672 panic( "drop_privileges failed, exiting. Last error"); 773 panic("drop_privileges failed, exiting. Last error");
673 774
674 g_now_seconds = time( NULL ); 775 g_now_seconds = time(NULL);
776 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
675 777
676 /* Create our self pipe which allows us to interrupt mainloops 778 /* Create our self pipe which allows us to interrupt mainloops
677 io_wait in case some data is available to send out */ 779 io_wait in case some data is available to send out */
678 if( pipe( g_self_pipe ) == -1 ) 780 if (pipe(g_self_pipe) == -1)
679 panic( "selfpipe failed: " ); 781 panic("selfpipe failed: ");
680 if( !io_fd( g_self_pipe[0] ) ) 782 if (!io_fd(g_self_pipe[0]))
681 panic( "selfpipe io_fd failed: " ); 783 panic("selfpipe io_fd failed: ");
682 if( !io_fd( g_self_pipe[1] ) ) 784 if (!io_fd(g_self_pipe[1]))
683 panic( "selfpipe io_fd failed: " ); 785 panic("selfpipe io_fd failed: ");
684 io_setcookie( g_self_pipe[0], (void*)FLAG_SELFPIPE ); 786 io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE);
685 io_wantread( g_self_pipe[0] ); 787 io_wantread(g_self_pipe[0]);
686 788
687 defaul_signal_handlers( );
688 /* Init all sub systems. This call may fail with an exit() */ 789 /* Init all sub systems. This call may fail with an exit() */
689 trackerlogic_init( ); 790 trackerlogic_init();
690 791
691 if( statefile ) 792#ifdef _DEBUG_RANDOMTORRENTS
692 load_state( statefile ); 793 fprintf(stderr, "DEBUG: Generating %d random peers on random torrents. This may take a while. (Setting RANDOMTORRENTS in trackerlogic.h)\n", RANDOMTORRENTS);
794 trackerlogic_add_random_torrents(RANDOMTORRENTS);
795 fprintf(stderr, "... done.\n");
796#endif
693 797
694 install_signal_handlers( ); 798 if (statefile)
799 load_state(statefile);
695 800
696 if( !g_udp_workers ) 801 install_signal_handlers();
697 udp_init( -1, 0 );
698 802
699 /* Kick off our initial clock setting alarm */ 803 if (!g_udp_workers)
700 alarm(5); 804 udp_init(-1, 0);
701 805
702 server_mainloop( 0 ); 806 server_mainloop(0);
703 807
704 return 0; 808 return 0;
705} 809}
706
707const char *g_version_opentracker_c = "$Source$: $Revision$\n";