An open and free bittorrent tracker https://erdgeist.org/gitweb/opentracker
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

670 lines
20 KiB

  1. /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
  2. It is considered beerware. Prost. Skol. Cheers or whatever.
  3. Some of the stuff below is stolen from Fefes example libowfat httpd.
  4. $Id$ */
  5. /* System */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <arpa/inet.h>
  9. #include <sys/socket.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. #include <signal.h>
  13. #include <stdio.h>
  14. #include <pwd.h>
  15. #include <ctype.h>
  16. #include <pthread.h>
  17. #ifdef WANT_SYSLOGS
  18. #include <syslog.h>
  19. #endif
  20. /* Libowfat */
  21. #include "socket.h"
  22. #include "io.h"
  23. #include "iob.h"
  24. #include "byte.h"
  25. #include "scan.h"
  26. #include "ip6.h"
  27. /* Opentracker */
  28. #include "trackerlogic.h"
  29. #include "ot_mutex.h"
  30. #include "ot_http.h"
  31. #include "ot_udp.h"
  32. #include "ot_accesslist.h"
  33. #include "ot_stats.h"
  34. #include "ot_livesync.h"
  35. /* Globals */
  36. time_t g_now_seconds;
  37. char * g_redirecturl;
  38. uint32_t g_tracker_id;
  39. volatile int g_opentracker_running = 1;
  40. int g_self_pipe[2];
  41. static char * g_serverdir;
  42. static char * g_serveruser;
  43. static unsigned int g_udp_workers;
  44. static void panic( const char *routing ) __attribute__ ((noreturn));
  45. static void panic( const char *routine ) {
  46. fprintf( stderr, "%s: %s\n", routine, strerror(errno) );
  47. exit( 111 );
  48. }
  49. static void signal_handler( int s ) {
  50. if( s == SIGINT ) {
  51. /* Any new interrupt signal quits the application */
  52. signal( SIGINT, SIG_DFL);
  53. /* Tell all other threads to not acquire any new lock on a bucket
  54. but cancel their operations and return */
  55. g_opentracker_running = 0;
  56. trackerlogic_deinit();
  57. #ifdef WANT_SYSLOGS
  58. closelog();
  59. #endif
  60. exit( 0 );
  61. } else if( s == SIGALRM ) {
  62. /* Maintain our copy of the clock. time() on BSDs is very expensive. */
  63. g_now_seconds = time(NULL);
  64. alarm(5);
  65. }
  66. }
  67. static void defaul_signal_handlers( void ) {
  68. sigset_t signal_mask;
  69. sigemptyset(&signal_mask);
  70. sigaddset (&signal_mask, SIGPIPE);
  71. sigaddset (&signal_mask, SIGHUP);
  72. sigaddset (&signal_mask, SIGINT);
  73. sigaddset (&signal_mask, SIGALRM);
  74. pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
  75. }
  76. static void install_signal_handlers( void ) {
  77. struct sigaction sa;
  78. sigset_t signal_mask;
  79. sigemptyset(&signal_mask);
  80. sa.sa_handler = signal_handler;
  81. sigemptyset(&sa.sa_mask);
  82. sa.sa_flags = SA_RESTART;
  83. if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1) )
  84. panic( "install_signal_handlers" );
  85. sigaddset (&signal_mask, SIGINT);
  86. sigaddset (&signal_mask, SIGALRM);
  87. pthread_sigmask (SIG_UNBLOCK, &signal_mask, NULL);
  88. }
  89. static void usage( char *name ) {
  90. fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip] [-f config] [-s livesyncport]"
  91. #ifdef WANT_ACCESSLIST_BLACK
  92. " [-b blacklistfile]"
  93. #elif defined ( WANT_ACCESSLIST_WHITE )
  94. " [-w whitelistfile]"
  95. #endif
  96. "\n", name );
  97. }
  98. #define HELPLINE(opt,desc) fprintf(stderr, "\t%-10s%s\n",opt,desc)
  99. static void help( char *name ) {
  100. usage( name );
  101. HELPLINE("-f config","include and execute the config file");
  102. HELPLINE("-i ip","specify ip to bind to (default: *, you may specify more than one)");
  103. HELPLINE("-p port","specify tcp port to bind to (default: 6969, you may specify more than one)");
  104. HELPLINE("-P port","specify udp port to bind to (default: 6969, you may specify more than one)");
  105. HELPLINE("-r redirecturl","specify url where / should be redirected to (default none)");
  106. HELPLINE("-d dir","specify directory to try to chroot to (default: \".\")");
  107. HELPLINE("-u user","specify user under whose priviliges opentracker should run (default: \"nobody\")");
  108. HELPLINE("-A ip","bless an ip address as admin address (e.g. to allow syncs from this address)");
  109. #ifdef WANT_ACCESSLIST_BLACK
  110. HELPLINE("-b file","specify blacklist file.");
  111. #elif defined( WANT_ACCESSLIST_WHITE )
  112. HELPLINE("-w file","specify whitelist file.");
  113. #endif
  114. 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" );
  115. }
  116. #undef HELPLINE
  117. static size_t header_complete( char * request, ssize_t byte_count ) {
  118. int i = 0, state = 0;
  119. for( i=1; i < byte_count; i+=2 )
  120. if( request[i] <= 13 ) {
  121. i--;
  122. for( state = 0 ; i < byte_count; ++i ) {
  123. char c = request[i];
  124. if( c == '\r' || c == '\n' )
  125. state = ( state >> 2 ) | ( ( c << 6 ) & 0xc0 );
  126. else
  127. break;
  128. if( state >= 0xa0 || state == 0x99 ) return i + 1;
  129. }
  130. }
  131. return 0;
  132. }
  133. static void handle_dead( const int64 sock ) {
  134. struct http_data* cookie=io_getcookie( sock );
  135. if( cookie ) {
  136. iob_reset( &cookie->batch );
  137. array_reset( &cookie->request );
  138. if( cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK )
  139. mutex_workqueue_canceltask( sock );
  140. free( cookie );
  141. }
  142. io_close( sock );
  143. }
  144. static void handle_read( const int64 sock, struct ot_workstruct *ws ) {
  145. struct http_data* cookie = io_getcookie( sock );
  146. ssize_t byte_count;
  147. if( ( byte_count = io_tryread( sock, ws->inbuf, G_INBUF_SIZE ) ) <= 0 ) {
  148. handle_dead( sock );
  149. return;
  150. }
  151. /* If we get the whole request in one packet, handle it without copying */
  152. if( !array_start( &cookie->request ) ) {
  153. if( ( ws->header_size = header_complete( ws->inbuf, byte_count ) ) ) {
  154. ws->request = ws->inbuf;
  155. ws->request_size = byte_count;
  156. http_handle_request( sock, ws );
  157. } else
  158. array_catb( &cookie->request, ws->inbuf, byte_count );
  159. return;
  160. }
  161. array_catb( &cookie->request, ws->inbuf, byte_count );
  162. if( array_failed( &cookie->request ) || array_bytes( &cookie->request ) > 8192 ) {
  163. http_issue_error( sock, ws, CODE_HTTPERROR_500 );
  164. return;
  165. }
  166. while( ( ws->header_size = header_complete( array_start( &cookie->request ), array_bytes( &cookie->request ) ) ) ) {
  167. ws->request = array_start( &cookie->request );
  168. ws->request_size = array_bytes( &cookie->request );
  169. http_handle_request( sock, ws );
  170. #ifdef WANT_KEEPALIVE
  171. if( !ws->keep_alive )
  172. #endif
  173. return;
  174. }
  175. }
  176. static void handle_write( const int64 sock ) {
  177. struct http_data* cookie=io_getcookie( sock );
  178. if( !cookie || ( iob_send( sock, &cookie->batch ) <= 0 ) )
  179. handle_dead( sock );
  180. }
  181. static void handle_accept( const int64 serversocket ) {
  182. struct http_data *cookie;
  183. int64 sock;
  184. ot_ip6 ip;
  185. uint16 port;
  186. tai6464 t;
  187. while( ( sock = socket_accept6( serversocket, ip, &port, NULL ) ) != -1 ) {
  188. /* Put fd into a non-blocking mode */
  189. io_nonblock( sock );
  190. if( !io_fd( sock ) ||
  191. !( cookie = (struct http_data*)malloc( sizeof(struct http_data) ) ) ) {
  192. io_close( sock );
  193. continue;
  194. }
  195. memset(cookie, 0, sizeof( struct http_data ) );
  196. memcpy(cookie->ip,ip,sizeof(ot_ip6));
  197. io_setcookie( sock, cookie );
  198. io_wantread( sock );
  199. stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
  200. /* That breaks taia encapsulation. But there is no way to take system
  201. time this often in FreeBSD and libowfat does not allow to set unix time */
  202. taia_uint( &t, 0 ); /* Clear t */
  203. tai_unix( &(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT) );
  204. io_timeout( sock, t );
  205. }
  206. io_eagain(serversocket);
  207. }
  208. static void * server_mainloop( void * args ) {
  209. struct ot_workstruct ws;
  210. time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
  211. struct iovec *iovector;
  212. int iovec_entries;
  213. (void)args;
  214. /* Initialize our "thread local storage" */
  215. ws.inbuf = malloc( G_INBUF_SIZE );
  216. ws.outbuf = malloc( G_OUTBUF_SIZE );
  217. #ifdef _DEBUG_HTTPERROR
  218. ws.debugbuf= malloc( G_DEBUGBUF_SIZE );
  219. #endif
  220. if( !ws.inbuf || !ws.outbuf )
  221. panic( "Initializing worker failed" );
  222. for( ; ; ) {
  223. int64 sock;
  224. io_wait();
  225. while( ( sock = io_canread( ) ) != -1 ) {
  226. const void *cookie = io_getcookie( sock );
  227. if( (intptr_t)cookie == FLAG_TCP )
  228. handle_accept( sock );
  229. else if( (intptr_t)cookie == FLAG_UDP )
  230. handle_udp6( sock, &ws );
  231. else if( (intptr_t)cookie == FLAG_SELFPIPE )
  232. io_tryread( sock, ws.inbuf, G_INBUF_SIZE );
  233. else
  234. handle_read( sock, &ws );
  235. }
  236. while( ( sock = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 )
  237. http_sendiovecdata( sock, &ws, iovec_entries, iovector );
  238. while( ( sock = io_canwrite( ) ) != -1 )
  239. handle_write( sock );
  240. if( g_now_seconds > next_timeout_check ) {
  241. while( ( sock = io_timeouted() ) != -1 )
  242. handle_dead( sock );
  243. next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
  244. }
  245. livesync_ticker();
  246. /* Enforce setting the clock */
  247. signal_handler( SIGALRM );
  248. }
  249. return 0;
  250. }
  251. static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) {
  252. int64 sock = proto == FLAG_TCP ? socket_tcp6( ) : socket_udp6( );
  253. #ifndef WANT_V6
  254. if( !ip6_isv4mapped(ip) ) {
  255. exerr( "V4 Tracker is V4 only!" );
  256. }
  257. #else
  258. if( ip6_isv4mapped(ip) ) {
  259. exerr( "V6 Tracker is V6 only!" );
  260. }
  261. #endif
  262. #ifdef _DEBUG
  263. {
  264. char *protos[] = {"TCP","UDP","UDP mcast"};
  265. char _debug[512];
  266. int off = snprintf( _debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto] );
  267. off += fmt_ip6c( _debug+off, ip);
  268. snprintf( _debug + off, sizeof(_debug)-off, "]:%d...", port);
  269. fputs( _debug, stderr );
  270. }
  271. #endif
  272. if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 )
  273. panic( "socket_bind6_reuse" );
  274. if( ( proto == FLAG_TCP ) && ( socket_listen( sock, SOMAXCONN) == -1 ) )
  275. panic( "socket_listen" );
  276. if( !io_fd( sock ) )
  277. panic( "io_fd" );
  278. io_setcookie( sock, (void*)proto );
  279. if( (proto == FLAG_UDP) && g_udp_workers ) {
  280. io_block( sock );
  281. udp_init( sock, g_udp_workers );
  282. } else
  283. io_wantread( sock );
  284. #ifdef _DEBUG
  285. fputs( " success.\n", stderr);
  286. #endif
  287. return sock;
  288. }
  289. char * set_config_option( char **option, char *value ) {
  290. #ifdef _DEBUG
  291. fprintf( stderr, "Setting config option: %s\n", value );
  292. #endif
  293. while( isspace(*value) ) ++value;
  294. free( *option );
  295. return *option = strdup( value );
  296. }
  297. static int scan_ip6_port( const char *src, ot_ip6 ip, uint16 *port ) {
  298. const char *s = src;
  299. int off, bracket = 0;
  300. while( isspace(*s) ) ++s;
  301. if( *s == '[' ) ++s, ++bracket; /* for v6 style notation */
  302. if( !(off = scan_ip6( s, ip ) ) )
  303. return 0;
  304. s += off;
  305. if( bracket && *s == ']' ) ++s;
  306. if( *s == 0 || isspace(*s)) return s-src;
  307. if( !ip6_isv4mapped(ip)){
  308. if( *s != ':' && *s != '.' ) return 0;
  309. if( !bracket && *(s) == ':' ) return 0;
  310. s++;
  311. } else {
  312. if( *(s++) != ':' ) return 0;
  313. }
  314. if( !(off = scan_ushort (s, port ) ) )
  315. return 0;
  316. return off+s-src;
  317. }
  318. int parse_configfile( char * config_filename ) {
  319. FILE * accesslist_filehandle;
  320. char inbuf[512];
  321. ot_ip6 tmpip;
  322. int bound = 0;
  323. accesslist_filehandle = fopen( config_filename, "r" );
  324. if( accesslist_filehandle == NULL ) {
  325. fprintf( stderr, "Warning: Can't open config file: %s.", config_filename );
  326. return 0;
  327. }
  328. while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) {
  329. char *p = inbuf;
  330. size_t strl;
  331. /* Skip white spaces */
  332. while(isspace(*p)) ++p;
  333. /* Ignore comments and empty lines */
  334. if((*p=='#')||(*p=='\n')||(*p==0)) continue;
  335. /* consume trailing new lines and spaces */
  336. strl = strlen(p);
  337. while( strl && isspace(p[strl-1]))
  338. p[--strl] = 0;
  339. /* Scan for commands */
  340. if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) {
  341. set_config_option( &g_serverdir, p+16 );
  342. } else if(!byte_diff(p,12,"tracker.user" ) && isspace(p[12])) {
  343. set_config_option( &g_serveruser, p+13 );
  344. } else if(!byte_diff(p,14,"listen.tcp_udp" ) && isspace(p[14])) {
  345. uint16_t tmpport = 6969;
  346. if( !scan_ip6_port( p+15, tmpip, &tmpport )) goto parse_error;
  347. ot_try_bind( tmpip, tmpport, FLAG_TCP ); ++bound;
  348. ot_try_bind( tmpip, tmpport, FLAG_UDP ); ++bound;
  349. } else if(!byte_diff(p,10,"listen.tcp" ) && isspace(p[10])) {
  350. uint16_t tmpport = 6969;
  351. if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error;
  352. ot_try_bind( tmpip, tmpport, FLAG_TCP );
  353. ++bound;
  354. } else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) {
  355. uint16_t tmpport = 6969;
  356. if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error;
  357. ot_try_bind( tmpip, tmpport, FLAG_UDP );
  358. ++bound;
  359. } else if(!byte_diff(p,18,"listen.udp.workers" ) && isspace(p[18])) {
  360. char *value = p + 18;
  361. while( isspace(*value) ) ++value;
  362. scan_uint( value, &g_udp_workers );
  363. #ifdef WANT_ACCESSLIST_WHITE
  364. } else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) {
  365. set_config_option( &g_accesslist_filename, p+17 );
  366. #elif defined( WANT_ACCESSLIST_BLACK )
  367. } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) {
  368. set_config_option( &g_accesslist_filename, p+17 );
  369. #endif
  370. #ifdef WANT_RESTRICT_STATS
  371. } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) {
  372. if( !scan_ip6( p+13, tmpip )) goto parse_error;
  373. accesslist_blessip( tmpip, OT_PERMISSION_MAY_STAT );
  374. #endif
  375. } else if(!byte_diff(p, 17, "access.stats_path" ) && isspace(p[17])) {
  376. set_config_option( &g_stats_path, p+18 );
  377. #ifdef WANT_IP_FROM_PROXY
  378. } else if(!byte_diff(p, 12, "access.proxy" ) && isspace(p[12])) {
  379. if( !scan_ip6( p+13, tmpip )) goto parse_error;
  380. accesslist_blessip( tmpip, OT_PERMISSION_MAY_PROXY );
  381. #endif
  382. } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
  383. set_config_option( &g_redirecturl, p+21 );
  384. #ifdef WANT_SYNC_LIVE
  385. } else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) {
  386. if( !scan_ip6( p+25, tmpip )) goto parse_error;
  387. accesslist_blessip( tmpip, OT_PERMISSION_MAY_LIVESYNC );
  388. } else if(!byte_diff(p, 23, "livesync.cluster.listen" ) && isspace(p[23])) {
  389. uint16_t tmpport = LIVESYNC_PORT;
  390. if( !scan_ip6_port( p+24, tmpip, &tmpport )) goto parse_error;
  391. livesync_bind_mcast( tmpip, tmpport );
  392. #endif
  393. } else
  394. fprintf( stderr, "Unhandled line in config file: %s\n", inbuf );
  395. continue;
  396. parse_error:
  397. fprintf( stderr, "Parse error in config file: %s\n", inbuf);
  398. }
  399. fclose( accesslist_filehandle );
  400. return bound;
  401. }
  402. void load_state(const char * const state_filename ) {
  403. FILE * state_filehandle;
  404. char inbuf[512];
  405. ot_hash infohash;
  406. unsigned long long base, downcount;
  407. int consumed;
  408. state_filehandle = fopen( state_filename, "r" );
  409. if( state_filehandle == NULL ) {
  410. fprintf( stderr, "Warning: Can't open config file: %s.", state_filename );
  411. return;
  412. }
  413. /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */
  414. while( fgets( inbuf, sizeof(inbuf), state_filehandle ) ) {
  415. int i;
  416. for( i=0; i<(int)sizeof(ot_hash); ++i ) {
  417. int eger = 16 * scan_fromhex( inbuf[ 2*i ] ) + scan_fromhex( inbuf[ 1 + 2*i ] );
  418. if( eger < 0 )
  419. continue;
  420. infohash[i] = eger;
  421. }
  422. if( i != (int)sizeof(ot_hash) ) continue;
  423. i *= 2;
  424. if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &base ) ) ) continue;
  425. i += consumed;
  426. if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue;
  427. add_torrent_from_saved_state( infohash, base, downcount );
  428. }
  429. fclose( state_filehandle );
  430. }
  431. int drop_privileges ( const char * const serveruser, const char * const serverdir ) {
  432. struct passwd *pws = NULL;
  433. #ifdef _DEBUG
  434. if( !geteuid() )
  435. fprintf( stderr, "Dropping to user %s.\n", serveruser );
  436. if( serverdir )
  437. fprintf( stderr, "ch%s'ing to directory %s.\n", geteuid() ? "dir" : "root", serverdir );
  438. #endif
  439. /* Grab pws entry before chrooting */
  440. pws = getpwnam( serveruser );
  441. endpwent();
  442. if( geteuid() == 0 ) {
  443. /* Running as root: chroot and drop privileges */
  444. if( serverdir && chroot( serverdir ) ) {
  445. fprintf( stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno) );
  446. return -1;
  447. }
  448. if(chdir("/"))
  449. panic("chdir() failed after chrooting: ");
  450. /* If we can't find server user, revert to nobody's default uid */
  451. if( !pws ) {
  452. fprintf( stderr, "Warning: Could not get password entry for %s. Reverting to uid -2.\n", serveruser );
  453. setegid( (gid_t)-2 ); setgid( (gid_t)-2 );
  454. setuid( (uid_t)-2 ); seteuid( (uid_t)-2 );
  455. }
  456. else {
  457. setegid( pws->pw_gid ); setgid( pws->pw_gid );
  458. setuid( pws->pw_uid ); seteuid( pws->pw_uid );
  459. }
  460. if( geteuid() == 0 || getegid() == 0 )
  461. panic("Still running with root privileges?!");
  462. }
  463. else {
  464. /* Normal user, just chdir() */
  465. if( serverdir && chdir( serverdir ) ) {
  466. fprintf( stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno) );
  467. return -1;
  468. }
  469. }
  470. return 0;
  471. }
  472. int main( int argc, char **argv ) {
  473. ot_ip6 serverip, tmpip;
  474. int bound = 0, scanon = 1;
  475. uint16_t tmpport;
  476. char * statefile = 0;
  477. memset( serverip, 0, sizeof(ot_ip6) );
  478. #ifndef WANT_V6
  479. serverip[10]=serverip[11]=-1;
  480. noipv6=1;
  481. #endif
  482. #ifdef WANT_DEV_RANDOM
  483. srandomdev();
  484. #else
  485. srandom( time(NULL) );
  486. #endif
  487. while( scanon ) {
  488. switch( getopt( argc, argv, ":i:p:A:P:d:u:r:s:f:l:v"
  489. #ifdef WANT_ACCESSLIST_BLACK
  490. "b:"
  491. #elif defined( WANT_ACCESSLIST_WHITE )
  492. "w:"
  493. #endif
  494. "h" ) ) {
  495. case -1 : scanon = 0; break;
  496. case 'i':
  497. if( !scan_ip6( optarg, serverip )) { usage( argv[0] ); exit( 1 ); }
  498. break;
  499. #ifdef WANT_ACCESSLIST_BLACK
  500. case 'b': set_config_option( &g_accesslist_filename, optarg); break;
  501. #elif defined( WANT_ACCESSLIST_WHITE )
  502. case 'w': set_config_option( &g_accesslist_filename, optarg); break;
  503. #endif
  504. case 'p':
  505. if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
  506. ot_try_bind( serverip, tmpport, FLAG_TCP ); bound++; break;
  507. case 'P':
  508. if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
  509. ot_try_bind( serverip, tmpport, FLAG_UDP ); bound++; break;
  510. #ifdef WANT_SYNC_LIVE
  511. case 's':
  512. if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
  513. livesync_bind_mcast( serverip, tmpport); break;
  514. #endif
  515. case 'd': set_config_option( &g_serverdir, optarg ); break;
  516. case 'u': set_config_option( &g_serveruser, optarg ); break;
  517. case 'r': set_config_option( &g_redirecturl, optarg ); break;
  518. case 'l': statefile = optarg; break;
  519. case 'A':
  520. if( !scan_ip6( optarg, tmpip )) { usage( argv[0] ); exit( 1 ); }
  521. accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */
  522. break;
  523. case 'f': bound += parse_configfile( optarg ); break;
  524. case 'h': help( argv[0] ); exit( 0 );
  525. case 'v': {
  526. char buffer[8192];
  527. stats_return_tracker_version( buffer );
  528. fputs( buffer, stderr );
  529. exit( 0 );
  530. }
  531. default:
  532. case '?': usage( argv[0] ); exit( 1 );
  533. }
  534. }
  535. /* Bind to our default tcp/udp ports */
  536. if( !bound) {
  537. ot_try_bind( serverip, 6969, FLAG_TCP );
  538. ot_try_bind( serverip, 6969, FLAG_UDP );
  539. }
  540. #ifdef WANT_SYSLOGS
  541. openlog( "opentracker", 0, LOG_USER );
  542. setlogmask(LOG_UPTO(LOG_INFO));
  543. #endif
  544. if( drop_privileges( g_serveruser ? g_serveruser : "nobody", g_serverdir ) == -1 )
  545. panic( "drop_privileges failed, exiting. Last error");
  546. g_now_seconds = time( NULL );
  547. /* Create our self pipe which allows us to interrupt mainloops
  548. io_wait in case some data is available to send out */
  549. if( pipe( g_self_pipe ) == -1 )
  550. panic( "selfpipe failed: " );
  551. if( !io_fd( g_self_pipe[0] ) )
  552. panic( "selfpipe io_fd failed: " );
  553. if( !io_fd( g_self_pipe[1] ) )
  554. panic( "selfpipe io_fd failed: " );
  555. io_setcookie( g_self_pipe[0], (void*)FLAG_SELFPIPE );
  556. io_wantread( g_self_pipe[0] );
  557. defaul_signal_handlers( );
  558. /* Init all sub systems. This call may fail with an exit() */
  559. trackerlogic_init( );
  560. if( statefile )
  561. load_state( statefile );
  562. install_signal_handlers( );
  563. if( !g_udp_workers )
  564. udp_init( -1, 0 );
  565. /* Kick off our initial clock setting alarm */
  566. alarm(5);
  567. server_mainloop( 0 );
  568. return 0;
  569. }
  570. const char *g_version_opentracker_c = "$Source$: $Revision$\n";