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