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.
 
 
 
 

669 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: opentracker.c,v 1.240 2018/01/29 17:43:33 erdgeist Exp $ */
  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. }
  207. static void * server_mainloop( void * args ) {
  208. struct ot_workstruct ws;
  209. time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
  210. struct iovec *iovector;
  211. int iovec_entries;
  212. (void)args;
  213. /* Initialize our "thread local storage" */
  214. ws.inbuf = malloc( G_INBUF_SIZE );
  215. ws.outbuf = malloc( G_OUTBUF_SIZE );
  216. #ifdef _DEBUG_HTTPERROR
  217. ws.debugbuf= malloc( G_DEBUGBUF_SIZE );
  218. #endif
  219. if( !ws.inbuf || !ws.outbuf )
  220. panic( "Initializing worker failed" );
  221. for( ; ; ) {
  222. int64 sock;
  223. io_wait();
  224. while( ( sock = io_canread( ) ) != -1 ) {
  225. const void *cookie = io_getcookie( sock );
  226. if( (intptr_t)cookie == FLAG_TCP )
  227. handle_accept( sock );
  228. else if( (intptr_t)cookie == FLAG_UDP )
  229. handle_udp6( sock, &ws );
  230. else if( (intptr_t)cookie == FLAG_SELFPIPE )
  231. io_tryread( sock, ws.inbuf, G_INBUF_SIZE );
  232. else
  233. handle_read( sock, &ws );
  234. }
  235. while( ( sock = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 )
  236. http_sendiovecdata( sock, &ws, iovec_entries, iovector );
  237. while( ( sock = io_canwrite( ) ) != -1 )
  238. handle_write( sock );
  239. if( g_now_seconds > next_timeout_check ) {
  240. while( ( sock = io_timeouted() ) != -1 )
  241. handle_dead( sock );
  242. next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
  243. }
  244. livesync_ticker();
  245. /* Enforce setting the clock */
  246. signal_handler( SIGALRM );
  247. }
  248. return 0;
  249. }
  250. static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) {
  251. int64 sock = proto == FLAG_TCP ? socket_tcp6( ) : socket_udp6( );
  252. #ifndef WANT_V6
  253. if( !ip6_isv4mapped(ip) ) {
  254. exerr( "V4 Tracker is V4 only!" );
  255. }
  256. #else
  257. if( ip6_isv4mapped(ip) ) {
  258. exerr( "V6 Tracker is V6 only!" );
  259. }
  260. #endif
  261. #ifdef _DEBUG
  262. {
  263. char *protos[] = {"TCP","UDP","UDP mcast"};
  264. char _debug[512];
  265. int off = snprintf( _debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto] );
  266. off += fmt_ip6c( _debug+off, ip);
  267. snprintf( _debug + off, sizeof(_debug)-off, "]:%d...", port);
  268. fputs( _debug, stderr );
  269. }
  270. #endif
  271. if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 )
  272. panic( "socket_bind6_reuse" );
  273. if( ( proto == FLAG_TCP ) && ( socket_listen( sock, SOMAXCONN) == -1 ) )
  274. panic( "socket_listen" );
  275. if( !io_fd( sock ) )
  276. panic( "io_fd" );
  277. io_setcookie( sock, (void*)proto );
  278. if( (proto == FLAG_UDP) && g_udp_workers ) {
  279. io_block( sock );
  280. udp_init( sock, g_udp_workers );
  281. } else
  282. io_wantread( sock );
  283. #ifdef _DEBUG
  284. fputs( " success.\n", stderr);
  285. #endif
  286. return sock;
  287. }
  288. char * set_config_option( char **option, char *value ) {
  289. #ifdef _DEBUG
  290. fprintf( stderr, "Setting config option: %s\n", value );
  291. #endif
  292. while( isspace(*value) ) ++value;
  293. free( *option );
  294. return *option = strdup( value );
  295. }
  296. static int scan_ip6_port( const char *src, ot_ip6 ip, uint16 *port ) {
  297. const char *s = src;
  298. int off, bracket = 0;
  299. while( isspace(*s) ) ++s;
  300. if( *s == '[' ) ++s, ++bracket; /* for v6 style notation */
  301. if( !(off = scan_ip6( s, ip ) ) )
  302. return 0;
  303. s += off;
  304. if( bracket && *s == ']' ) ++s;
  305. if( *s == 0 || isspace(*s)) return s-src;
  306. if( !ip6_isv4mapped(ip)){
  307. if( *s != ':' && *s != '.' ) return 0;
  308. if( !bracket && *(s) == ':' ) return 0;
  309. s++;
  310. } else {
  311. if( *(s++) != ':' ) return 0;
  312. }
  313. if( !(off = scan_ushort (s, port ) ) )
  314. return 0;
  315. return off+s-src;
  316. }
  317. int parse_configfile( char * config_filename ) {
  318. FILE * accesslist_filehandle;
  319. char inbuf[512];
  320. ot_ip6 tmpip;
  321. int bound = 0;
  322. accesslist_filehandle = fopen( config_filename, "r" );
  323. if( accesslist_filehandle == NULL ) {
  324. fprintf( stderr, "Warning: Can't open config file: %s.", config_filename );
  325. return 0;
  326. }
  327. while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) {
  328. char *p = inbuf;
  329. size_t strl;
  330. /* Skip white spaces */
  331. while(isspace(*p)) ++p;
  332. /* Ignore comments and empty lines */
  333. if((*p=='#')||(*p=='\n')||(*p==0)) continue;
  334. /* consume trailing new lines and spaces */
  335. strl = strlen(p);
  336. while( strl && isspace(p[strl-1]))
  337. p[--strl] = 0;
  338. /* Scan for commands */
  339. if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) {
  340. set_config_option( &g_serverdir, p+16 );
  341. } else if(!byte_diff(p,12,"tracker.user" ) && isspace(p[12])) {
  342. set_config_option( &g_serveruser, p+13 );
  343. } else if(!byte_diff(p,14,"listen.tcp_udp" ) && isspace(p[14])) {
  344. uint16_t tmpport = 6969;
  345. if( !scan_ip6_port( p+15, tmpip, &tmpport )) goto parse_error;
  346. ot_try_bind( tmpip, tmpport, FLAG_TCP ); ++bound;
  347. ot_try_bind( tmpip, tmpport, FLAG_UDP ); ++bound;
  348. } else if(!byte_diff(p,10,"listen.tcp" ) && isspace(p[10])) {
  349. uint16_t tmpport = 6969;
  350. if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error;
  351. ot_try_bind( tmpip, tmpport, FLAG_TCP );
  352. ++bound;
  353. } else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) {
  354. uint16_t tmpport = 6969;
  355. if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error;
  356. ot_try_bind( tmpip, tmpport, FLAG_UDP );
  357. ++bound;
  358. } else if(!byte_diff(p,18,"listen.udp.workers" ) && isspace(p[18])) {
  359. char *value = p + 18;
  360. while( isspace(*value) ) ++value;
  361. scan_uint( value, &g_udp_workers );
  362. #ifdef WANT_ACCESSLIST_WHITE
  363. } else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) {
  364. set_config_option( &g_accesslist_filename, p+17 );
  365. #elif defined( WANT_ACCESSLIST_BLACK )
  366. } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) {
  367. set_config_option( &g_accesslist_filename, p+17 );
  368. #endif
  369. #ifdef WANT_RESTRICT_STATS
  370. } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) {
  371. if( !scan_ip6( p+13, tmpip )) goto parse_error;
  372. accesslist_blessip( tmpip, OT_PERMISSION_MAY_STAT );
  373. #endif
  374. } else if(!byte_diff(p, 17, "access.stats_path" ) && isspace(p[17])) {
  375. set_config_option( &g_stats_path, p+18 );
  376. #ifdef WANT_IP_FROM_PROXY
  377. } else if(!byte_diff(p, 12, "access.proxy" ) && isspace(p[12])) {
  378. if( !scan_ip6( p+13, tmpip )) goto parse_error;
  379. accesslist_blessip( tmpip, OT_PERMISSION_MAY_PROXY );
  380. #endif
  381. } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
  382. set_config_option( &g_redirecturl, p+21 );
  383. #ifdef WANT_SYNC_LIVE
  384. } else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) {
  385. if( !scan_ip6( p+25, tmpip )) goto parse_error;
  386. accesslist_blessip( tmpip, OT_PERMISSION_MAY_LIVESYNC );
  387. } else if(!byte_diff(p, 23, "livesync.cluster.listen" ) && isspace(p[23])) {
  388. uint16_t tmpport = LIVESYNC_PORT;
  389. if( !scan_ip6_port( p+24, tmpip, &tmpport )) goto parse_error;
  390. livesync_bind_mcast( tmpip, tmpport );
  391. #endif
  392. } else
  393. fprintf( stderr, "Unhandled line in config file: %s\n", inbuf );
  394. continue;
  395. parse_error:
  396. fprintf( stderr, "Parse error in config file: %s\n", inbuf);
  397. }
  398. fclose( accesslist_filehandle );
  399. return bound;
  400. }
  401. void load_state(const char * const state_filename ) {
  402. FILE * state_filehandle;
  403. char inbuf[512];
  404. ot_hash infohash;
  405. unsigned long long base, downcount;
  406. int consumed;
  407. state_filehandle = fopen( state_filename, "r" );
  408. if( state_filehandle == NULL ) {
  409. fprintf( stderr, "Warning: Can't open config file: %s.", state_filename );
  410. return;
  411. }
  412. /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */
  413. while( fgets( inbuf, sizeof(inbuf), state_filehandle ) ) {
  414. int i;
  415. for( i=0; i<(int)sizeof(ot_hash); ++i ) {
  416. int eger = 16 * scan_fromhex( inbuf[ 2*i ] ) + scan_fromhex( inbuf[ 1 + 2*i ] );
  417. if( eger < 0 )
  418. continue;
  419. infohash[i] = eger;
  420. }
  421. if( i != (int)sizeof(ot_hash) ) continue;
  422. i *= 2;
  423. if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &base ) ) ) continue;
  424. i += consumed;
  425. if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue;
  426. add_torrent_from_saved_state( infohash, base, downcount );
  427. }
  428. fclose( state_filehandle );
  429. }
  430. int drop_privileges ( const char * const serveruser, const char * const serverdir ) {
  431. struct passwd *pws = NULL;
  432. #ifdef _DEBUG
  433. if( !geteuid() )
  434. fprintf( stderr, "Dropping to user %s.\n", serveruser );
  435. if( serverdir )
  436. fprintf( stderr, "ch%s'ing to directory %s.\n", geteuid() ? "dir" : "root", serverdir );
  437. #endif
  438. /* Grab pws entry before chrooting */
  439. pws = getpwnam( serveruser );
  440. endpwent();
  441. if( geteuid() == 0 ) {
  442. /* Running as root: chroot and drop privileges */
  443. if( serverdir && chroot( serverdir ) ) {
  444. fprintf( stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno) );
  445. return -1;
  446. }
  447. if(chdir("/"))
  448. panic("chdir() failed after chrooting: ");
  449. /* If we can't find server user, revert to nobody's default uid */
  450. if( !pws ) {
  451. fprintf( stderr, "Warning: Could not get password entry for %s. Reverting to uid -2.\n", serveruser );
  452. setegid( (gid_t)-2 ); setgid( (gid_t)-2 );
  453. setuid( (uid_t)-2 ); seteuid( (uid_t)-2 );
  454. }
  455. else {
  456. setegid( pws->pw_gid ); setgid( pws->pw_gid );
  457. setuid( pws->pw_uid ); seteuid( pws->pw_uid );
  458. }
  459. if( geteuid() == 0 || getegid() == 0 )
  460. panic("Still running with root privileges?!");
  461. }
  462. else {
  463. /* Normal user, just chdir() */
  464. if( serverdir && chdir( serverdir ) ) {
  465. fprintf( stderr, "Could not chroot to %s, because: %s\n", serverdir, strerror(errno) );
  466. return -1;
  467. }
  468. }
  469. return 0;
  470. }
  471. int main( int argc, char **argv ) {
  472. ot_ip6 serverip, tmpip;
  473. int bound = 0, scanon = 1;
  474. uint16_t tmpport;
  475. char * statefile = 0;
  476. memset( serverip, 0, sizeof(ot_ip6) );
  477. #ifndef WANT_V6
  478. serverip[10]=serverip[11]=-1;
  479. noipv6=1;
  480. #endif
  481. #ifdef WANT_DEV_RANDOM
  482. srandomdev();
  483. #else
  484. srandom( time(NULL) );
  485. #endif
  486. while( scanon ) {
  487. switch( getopt( argc, argv, ":i:p:A:P:d:u:r:s:f:l:v"
  488. #ifdef WANT_ACCESSLIST_BLACK
  489. "b:"
  490. #elif defined( WANT_ACCESSLIST_WHITE )
  491. "w:"
  492. #endif
  493. "h" ) ) {
  494. case -1 : scanon = 0; break;
  495. case 'i':
  496. if( !scan_ip6( optarg, serverip )) { usage( argv[0] ); exit( 1 ); }
  497. break;
  498. #ifdef WANT_ACCESSLIST_BLACK
  499. case 'b': set_config_option( &g_accesslist_filename, optarg); break;
  500. #elif defined( WANT_ACCESSLIST_WHITE )
  501. case 'w': set_config_option( &g_accesslist_filename, optarg); break;
  502. #endif
  503. case 'p':
  504. if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
  505. ot_try_bind( serverip, tmpport, FLAG_TCP ); bound++; break;
  506. case 'P':
  507. if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
  508. ot_try_bind( serverip, tmpport, FLAG_UDP ); bound++; break;
  509. #ifdef WANT_SYNC_LIVE
  510. case 's':
  511. if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); }
  512. livesync_bind_mcast( serverip, tmpport); break;
  513. #endif
  514. case 'd': set_config_option( &g_serverdir, optarg ); break;
  515. case 'u': set_config_option( &g_serveruser, optarg ); break;
  516. case 'r': set_config_option( &g_redirecturl, optarg ); break;
  517. case 'l': statefile = optarg; break;
  518. case 'A':
  519. if( !scan_ip6( optarg, tmpip )) { usage( argv[0] ); exit( 1 ); }
  520. accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */
  521. break;
  522. case 'f': bound += parse_configfile( optarg ); break;
  523. case 'h': help( argv[0] ); exit( 0 );
  524. case 'v': {
  525. char buffer[8192];
  526. stats_return_tracker_version( buffer );
  527. fputs( buffer, stderr );
  528. exit( 0 );
  529. }
  530. default:
  531. case '?': usage( argv[0] ); exit( 1 );
  532. }
  533. }
  534. /* Bind to our default tcp/udp ports */
  535. if( !bound) {
  536. ot_try_bind( serverip, 6969, FLAG_TCP );
  537. ot_try_bind( serverip, 6969, FLAG_UDP );
  538. }
  539. #ifdef WANT_SYSLOGS
  540. openlog( "opentracker", 0, LOG_USER );
  541. setlogmask(LOG_UPTO(LOG_INFO));
  542. #endif
  543. if( drop_privileges( g_serveruser ? g_serveruser : "nobody", g_serverdir ) == -1 )
  544. panic( "drop_privileges failed, exiting. Last error");
  545. g_now_seconds = time( NULL );
  546. /* Create our self pipe which allows us to interrupt mainloops
  547. io_wait in case some data is available to send out */
  548. if( pipe( g_self_pipe ) == -1 )
  549. panic( "selfpipe failed: " );
  550. if( !io_fd( g_self_pipe[0] ) )
  551. panic( "selfpipe io_fd failed: " );
  552. if( !io_fd( g_self_pipe[1] ) )
  553. panic( "selfpipe io_fd failed: " );
  554. io_setcookie( g_self_pipe[0], (void*)FLAG_SELFPIPE );
  555. io_wantread( g_self_pipe[0] );
  556. defaul_signal_handlers( );
  557. /* Init all sub systems. This call may fail with an exit() */
  558. trackerlogic_init( );
  559. if( statefile )
  560. load_state( statefile );
  561. install_signal_handlers( );
  562. if( !g_udp_workers )
  563. udp_init( -1, 0 );
  564. /* Kick off our initial clock setting alarm */
  565. alarm(5);
  566. server_mainloop( 0 );
  567. return 0;
  568. }
  569. const char *g_version_opentracker_c = "$Source: /home/cvsroot/opentracker/opentracker.c,v $: $Revision: 1.240 $\n";