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