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