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.

656 lines
20 KiB

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