diff options
Diffstat (limited to 'opentracker.c')
-rw-r--r-- | opentracker.c | 829 |
1 files changed, 447 insertions, 382 deletions
diff --git a/opentracker.c b/opentracker.c index a896762..392f6df 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 *routine ) __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,61 +69,63 @@ static void signal_handler( int s ) { | |||
69 | closelog(); | 69 | closelog(); |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | exit( 0 ); | 72 | exit(0); |
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | static void defaul_signal_handlers( void ) { | 76 | static void defaul_signal_handlers(void) { |
77 | sigset_t signal_mask; | 77 | sigset_t signal_mask; |
78 | sigemptyset(&signal_mask); | 78 | sigemptyset(&signal_mask); |
79 | sigaddset (&signal_mask, SIGPIPE); | 79 | sigaddset(&signal_mask, SIGPIPE); |
80 | sigaddset (&signal_mask, SIGHUP); | 80 | sigaddset(&signal_mask, SIGHUP); |
81 | sigaddset (&signal_mask, SIGINT); | 81 | sigaddset(&signal_mask, SIGINT); |
82 | sigaddset (&signal_mask, SIGALRM); | 82 | sigaddset(&signal_mask, SIGALRM); |
83 | pthread_sigmask (SIG_BLOCK, &signal_mask, NULL); | 83 | pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); |
84 | } | 84 | } |
85 | 85 | ||
86 | static void install_signal_handlers( void ) { | 86 | static void install_signal_handlers(void) { |
87 | struct sigaction sa; | 87 | struct sigaction sa; |
88 | sigset_t signal_mask; | 88 | sigset_t signal_mask; |
89 | sigemptyset(&signal_mask); | 89 | sigemptyset(&signal_mask); |
90 | 90 | ||
91 | sa.sa_handler = signal_handler; | 91 | sa.sa_handler = signal_handler; |
92 | sigemptyset(&sa.sa_mask); | 92 | sigemptyset(&sa.sa_mask); |
93 | sa.sa_flags = SA_RESTART; | 93 | sa.sa_flags = SA_RESTART; |
94 | if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1) ) | 94 | if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1)) |
95 | panic( "install_signal_handlers" ); | 95 | panic("install_signal_handlers"); |
96 | 96 | ||
97 | sigaddset (&signal_mask, SIGINT); | 97 | sigaddset(&signal_mask, SIGINT); |
98 | pthread_sigmask (SIG_UNBLOCK, &signal_mask, NULL); | 98 | pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL); |
99 | } | 99 | } |
100 | 100 | ||
101 | static void usage( char *name ) { | 101 | static void usage(char *name) { |
102 | fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-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]" | ||
103 | #ifdef WANT_ACCESSLIST_BLACK | 104 | #ifdef WANT_ACCESSLIST_BLACK |
104 | " [-b blacklistfile]" | 105 | " [-b blacklistfile]" |
105 | #elif defined ( WANT_ACCESSLIST_WHITE ) | 106 | #elif defined(WANT_ACCESSLIST_WHITE) |
106 | " [-w whitelistfile]" | 107 | " [-w whitelistfile]" |
107 | #endif | 108 | #endif |
108 | "\n", name ); | 109 | "\n", |
110 | name); | ||
109 | } | 111 | } |
110 | 112 | ||
111 | #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) |
112 | static void help( char *name ) { | 114 | static void help(char *name) { |
113 | usage( name ); | 115 | usage(name); |
114 | 116 | ||
115 | HELPLINE("-f config","include and execute the config file"); | 117 | HELPLINE("-f config", "include and execute the config file"); |
116 | HELPLINE("-i ip","specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)"); | 118 | HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)"); |
117 | HELPLINE("-p port","do bind to tcp port (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)"); |
118 | HELPLINE("-P port","do bind to udp port (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)"); |
119 | 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)"); |
120 | HELPLINE("-d dir","specify directory to try to chroot to (default: \".\")"); | 122 | HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")"); |
121 | 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\")"); |
122 | HELPLINE("-A ip[/bits]","bless an ip address or net 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)"); |
123 | #ifdef WANT_ACCESSLIST_BLACK | 125 | #ifdef WANT_ACCESSLIST_BLACK |
124 | HELPLINE("-b file","specify blacklist file."); | 126 | HELPLINE("-b file", "specify blacklist file."); |
125 | #elif defined( WANT_ACCESSLIST_WHITE ) | 127 | #elif defined(WANT_ACCESSLIST_WHITE) |
126 | HELPLINE("-w file","specify whitelist file."); | 128 | HELPLINE("-w file", "specify whitelist file."); |
127 | #endif | 129 | #endif |
128 | 130 | ||
129 | 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"); |
@@ -133,165 +135,165 @@ static void help( char *name ) { | |||
133 | } | 135 | } |
134 | #undef HELPLINE | 136 | #undef HELPLINE |
135 | 137 | ||
136 | static ssize_t header_complete( char * request, ssize_t byte_count ) { | 138 | static ssize_t header_complete(char *request, ssize_t byte_count) { |
137 | ssize_t i = 0, state = 0; | 139 | ssize_t i = 0, state = 0; |
138 | 140 | ||
139 | for( i=1; i < byte_count; i+=2 ) | 141 | for (i = 1; i < byte_count; i += 2) |
140 | if( request[i] <= 13 ) { | 142 | if (request[i] <= 13) { |
141 | i--; | 143 | i--; |
142 | for( state = 0 ; i < byte_count; ++i ) { | 144 | for (state = 0; i < byte_count; ++i) { |
143 | char c = request[i]; | 145 | char c = request[i]; |
144 | if( c == '\r' || c == '\n' ) | 146 | if (c == '\r' || c == '\n') |
145 | state = ( state >> 2 ) | ( ( c << 6 ) & 0xc0 ); | 147 | state = (state >> 2) | ((c << 6) & 0xc0); |
146 | else | 148 | else |
147 | break; | 149 | break; |
148 | if( state >= 0xa0 || state == 0x99 ) return i + 1; | 150 | if (state >= 0xa0 || state == 0x99) |
151 | return i + 1; | ||
149 | } | 152 | } |
150 | } | 153 | } |
151 | return 0; | 154 | return 0; |
152 | } | 155 | } |
153 | 156 | ||
154 | static void handle_dead( const int64 sock ) { | 157 | static void handle_dead(const int64 sock) { |
155 | struct http_data* cookie=io_getcookie( sock ); | 158 | struct http_data *cookie = io_getcookie(sock); |
156 | if( cookie ) { | 159 | if (cookie) { |
157 | size_t i; | 160 | size_t i; |
158 | for ( i = 0; i < cookie->batches; ++i) | 161 | for (i = 0; i < cookie->batches; ++i) |
159 | iob_reset( cookie->batch + i ); | 162 | iob_reset(cookie->batch + i); |
160 | free( cookie->batch ); | 163 | free(cookie->batch); |
161 | array_reset( &cookie->request ); | 164 | array_reset(&cookie->request); |
162 | if( cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) ) | 165 | if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) |
163 | mutex_workqueue_canceltask( sock ); | 166 | mutex_workqueue_canceltask(sock); |
164 | free( cookie ); | 167 | free(cookie); |
165 | } | 168 | } |
166 | io_close( sock ); | 169 | io_close(sock); |
167 | } | 170 | } |
168 | 171 | ||
169 | static void handle_read( const int64 sock, struct ot_workstruct *ws ) { | 172 | static void handle_read(const int64 sock, struct ot_workstruct *ws) { |
170 | struct http_data* cookie = io_getcookie( sock ); | 173 | struct http_data *cookie = io_getcookie(sock); |
171 | 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); |
172 | 175 | ||
173 | if( byte_count == 0 || byte_count == -3 ) { | 176 | if (byte_count == 0 || byte_count == -3) { |
174 | handle_dead( sock ); | 177 | handle_dead(sock); |
175 | return; | 178 | return; |
176 | } | 179 | } |
177 | 180 | ||
178 | if( byte_count == -1) | 181 | if (byte_count == -1) |
179 | return; | 182 | return; |
180 | 183 | ||
181 | /* 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 */ |
182 | if( !array_start( &cookie->request ) ) { | 185 | if (!array_start(&cookie->request)) { |
183 | if( ( ws->header_size = header_complete( ws->inbuf, byte_count ) ) ) { | 186 | if ((ws->header_size = header_complete(ws->inbuf, byte_count))) { |
184 | ws->request = ws->inbuf; | 187 | ws->request = ws->inbuf; |
185 | ws->request_size = byte_count; | 188 | ws->request_size = byte_count; |
186 | http_handle_request( sock, ws ); | 189 | http_handle_request(sock, ws); |
187 | } else | 190 | } else |
188 | array_catb( &cookie->request, ws->inbuf, (size_t)byte_count ); | 191 | array_catb(&cookie->request, ws->inbuf, (size_t)byte_count); |
189 | return; | 192 | return; |
190 | } | 193 | } |
191 | 194 | ||
192 | array_catb( &cookie->request, ws->inbuf, byte_count ); | 195 | array_catb(&cookie->request, ws->inbuf, byte_count); |
193 | if( array_failed( &cookie->request ) || array_bytes( &cookie->request ) > 8192 ) { | 196 | if (array_failed(&cookie->request) || array_bytes(&cookie->request) > 8192) { |
194 | http_issue_error( sock, ws, CODE_HTTPERROR_500 ); | 197 | http_issue_error(sock, ws, CODE_HTTPERROR_500); |
195 | return; | 198 | return; |
196 | } | 199 | } |
197 | 200 | ||
198 | 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)))) { |
199 | ws->request = array_start( &cookie->request ); | 202 | ws->request = array_start(&cookie->request); |
200 | ws->request_size = array_bytes( &cookie->request ); | 203 | ws->request_size = array_bytes(&cookie->request); |
201 | http_handle_request( sock, ws ); | 204 | http_handle_request(sock, ws); |
202 | #ifdef WANT_KEEPALIVE | 205 | #ifdef WANT_KEEPALIVE |
203 | if( !ws->keep_alive ) | 206 | if (!ws->keep_alive) |
204 | #endif | 207 | #endif |
205 | return; | 208 | return; |
206 | } | 209 | } |
207 | } | 210 | } |
208 | 211 | ||
209 | static void handle_write( const int64 sock ) { | 212 | static void handle_write(const int64 sock) { |
210 | struct http_data* cookie=io_getcookie( sock ); | 213 | struct http_data *cookie = io_getcookie(sock); |
211 | size_t i; | 214 | size_t i; |
212 | int chunked = 0; | 215 | int chunked = 0; |
213 | 216 | ||
214 | /* Look for the first io_batch still containing bytes to write */ | 217 | /* Look for the first io_batch still containing bytes to write */ |
215 | if( cookie ) { | 218 | if (cookie) { |
216 | if( cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER ) | 219 | if (cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER) |
217 | chunked = 1; | 220 | chunked = 1; |
218 | 221 | ||
219 | for( i = 0; i < cookie->batches; ++i ) { | 222 | for (i = 0; i < cookie->batches; ++i) { |
220 | if( cookie->batch[i].bytesleft ) { | 223 | if (cookie->batch[i].bytesleft) { |
221 | int64 res = iob_send( sock, cookie->batch + i ); | 224 | int64 res = iob_send(sock, cookie->batch + i); |
222 | 225 | ||
223 | if( res == -3 ) { | 226 | if (res == -3) { |
224 | handle_dead( sock ); | 227 | handle_dead(sock); |
225 | return; | 228 | return; |
226 | } | 229 | } |
227 | 230 | ||
228 | if( !cookie->batch[i].bytesleft ) | 231 | if (!cookie->batch[i].bytesleft) |
229 | continue; | 232 | continue; |
230 | 233 | ||
231 | if( res == -1 || res > 0 || i < cookie->batches - 1 ) | 234 | if (res == -1 || res > 0 || i < cookie->batches - 1) |
232 | return; | 235 | return; |
233 | } | 236 | } |
234 | } | 237 | } |
235 | } | 238 | } |
236 | 239 | ||
237 | /* In a chunked transfer after all batches accumulated have been sent, wait for the next one */ | 240 | /* In a chunked transfer after all batches accumulated have been sent, wait for the next one */ |
238 | if( chunked ) | 241 | if (chunked) |
239 | io_dontwantwrite( sock ); | 242 | io_dontwantwrite(sock); |
240 | else | 243 | else |
241 | handle_dead( sock ); | 244 | handle_dead(sock); |
242 | } | 245 | } |
243 | 246 | ||
244 | static void handle_accept( const int64 serversocket ) { | 247 | static void handle_accept(const int64 serversocket) { |
245 | struct http_data *cookie; | 248 | struct http_data *cookie; |
246 | int64 sock; | 249 | int64 sock; |
247 | ot_ip6 ip; | 250 | ot_ip6 ip; |
248 | uint16 port; | 251 | uint16 port; |
249 | tai6464 t; | 252 | tai6464 t; |
250 | 253 | ||
251 | while( ( sock = socket_accept6( serversocket, ip, &port, NULL ) ) != -1 ) { | 254 | while ((sock = socket_accept6(serversocket, ip, &port, NULL)) != -1) { |
252 | 255 | ||
253 | /* Put fd into a non-blocking mode */ | 256 | /* Put fd into a non-blocking mode */ |
254 | io_nonblock( sock ); | 257 | io_nonblock(sock); |
255 | 258 | ||
256 | if( !io_fd( sock ) || | 259 | if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) { |
257 | !( cookie = (struct http_data*)malloc( sizeof(struct http_data) ) ) ) { | 260 | io_close(sock); |
258 | io_close( sock ); | ||
259 | continue; | 261 | continue; |
260 | } | 262 | } |
261 | memset(cookie, 0, sizeof( struct http_data ) ); | 263 | memset(cookie, 0, sizeof(struct http_data)); |
262 | memcpy(cookie->ip,ip,sizeof(ot_ip6)); | 264 | memcpy(cookie->ip, ip, sizeof(ot_ip6)); |
263 | 265 | ||
264 | io_setcookie( sock, cookie ); | 266 | io_setcookie(sock, cookie); |
265 | io_wantread( sock ); | 267 | io_wantread(sock); |
266 | 268 | ||
267 | stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); | 269 | stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); |
268 | 270 | ||
269 | /* 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 |
270 | 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 */ |
271 | taia_uint( &t, 0 ); /* Clear t */ | 273 | taia_uint(&t, 0); /* Clear t */ |
272 | tai_unix( &(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT) ); | 274 | tai_unix(&(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT)); |
273 | io_timeout( sock, t ); | 275 | io_timeout(sock, t); |
274 | } | 276 | } |
275 | io_eagain(serversocket); | 277 | io_eagain(serversocket); |
276 | } | 278 | } |
277 | 279 | ||
278 | static void * server_mainloop( void * args ) { | 280 | static void *server_mainloop(void *args) { |
279 | struct ot_workstruct ws; | 281 | struct ot_workstruct ws; |
280 | 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; |
281 | struct iovec *iovector; | 283 | struct iovec *iovector; |
282 | int iovec_entries, is_partial; | 284 | int iovec_entries, is_partial; |
283 | 285 | ||
284 | (void)args; | 286 | (void)args; |
285 | 287 | ||
286 | /* Initialize our "thread local storage" */ | 288 | /* Initialize our "thread local storage" */ |
287 | ws.inbuf = malloc( G_INBUF_SIZE ); | 289 | ws.inbuf = malloc(G_INBUF_SIZE); |
288 | ws.outbuf = malloc( G_OUTBUF_SIZE ); | 290 | ws.outbuf = malloc(G_OUTBUF_SIZE); |
289 | #ifdef _DEBUG_HTTPERROR | 291 | #ifdef _DEBUG_HTTPERROR |
290 | ws.debugbuf= malloc( G_DEBUGBUF_SIZE ); | 292 | ws.debugbuf = malloc(G_DEBUGBUF_SIZE); |
291 | #endif | 293 | #endif |
292 | 294 | ||
293 | if( !ws.inbuf || !ws.outbuf ) | 295 | if (!ws.inbuf || !ws.outbuf) |
294 | panic( "Initializing worker failed" ); | 296 | panic("Initializing worker failed"); |
295 | 297 | ||
296 | #ifdef WANT_ARC4RANDOM | 298 | #ifdef WANT_ARC4RANDOM |
297 | arc4random_buf(&ws.rand48_state[0], 3 * sizeof(uint16_t)); | 299 | arc4random_buf(&ws.rand48_state[0], 3 * sizeof(uint16_t)); |
@@ -301,32 +303,32 @@ static void * server_mainloop( void * args ) { | |||
301 | ws.rand48_state[2] = (uint16_t)random(); | 303 | ws.rand48_state[2] = (uint16_t)random(); |
302 | #endif | 304 | #endif |
303 | 305 | ||
304 | for( ; ; ) { | 306 | for (;;) { |
305 | int64 sock; | 307 | int64 sock; |
306 | 308 | ||
307 | io_wait(); | 309 | io_wait(); |
308 | 310 | ||
309 | while( ( sock = io_canread( ) ) != -1 ) { | 311 | while ((sock = io_canread()) != -1) { |
310 | const void *cookie = io_getcookie( sock ); | 312 | const void *cookie = io_getcookie(sock); |
311 | if( (intptr_t)cookie == FLAG_TCP ) | 313 | if ((intptr_t)cookie == FLAG_TCP) |
312 | handle_accept( sock ); | 314 | handle_accept(sock); |
313 | else if( (intptr_t)cookie == FLAG_UDP ) | 315 | else if ((intptr_t)cookie == FLAG_UDP) |
314 | handle_udp6( sock, &ws ); | 316 | handle_udp6(sock, &ws); |
315 | else if( (intptr_t)cookie == FLAG_SELFPIPE ) | 317 | else if ((intptr_t)cookie == FLAG_SELFPIPE) |
316 | io_tryread( sock, ws.inbuf, G_INBUF_SIZE ); | 318 | io_tryread(sock, ws.inbuf, G_INBUF_SIZE); |
317 | else | 319 | else |
318 | handle_read( sock, &ws ); | 320 | handle_read(sock, &ws); |
319 | } | 321 | } |
320 | 322 | ||
321 | while( ( sock = mutex_workqueue_popresult( &iovec_entries, &iovector, &is_partial ) ) != -1 ) | 323 | while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) |
322 | http_sendiovecdata( sock, &ws, iovec_entries, iovector, is_partial ); | 324 | http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); |
323 | 325 | ||
324 | while( ( sock = io_canwrite( ) ) != -1 ) | 326 | while ((sock = io_canwrite()) != -1) |
325 | handle_write( sock ); | 327 | handle_write(sock); |
326 | 328 | ||
327 | if( g_now_seconds > next_timeout_check ) { | 329 | if (g_now_seconds > next_timeout_check) { |
328 | while( ( sock = io_timeouted() ) != -1 ) | 330 | while ((sock = io_timeouted()) != -1) |
329 | handle_dead( sock ); | 331 | handle_dead(sock); |
330 | next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; | 332 | next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; |
331 | } | 333 | } |
332 | 334 | ||
@@ -335,276 +337,298 @@ static void * server_mainloop( void * args ) { | |||
335 | return 0; | 337 | return 0; |
336 | } | 338 | } |
337 | 339 | ||
338 | 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) { |
339 | int64 sock = proto == FLAG_TCP ? socket_tcp6( ) : socket_udp6( ); | 341 | int64 sock = proto == FLAG_TCP ? socket_tcp6() : socket_udp6(); |
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; | ||
401 | } | 411 | } |
402 | if( !(off = scan_ushort (s, port ) ) ) | 412 | if (!(off = scan_ushort(s, port))) |
403 | return 0; | 413 | return 0; |
404 | return off+s-src; | 414 | return off + s - src; |
405 | } | 415 | } |
406 | 416 | ||
407 | static int scan_ip6_net( const char *src, ot_net *net) { | 417 | static int scan_ip6_net(const char *src, ot_net *net) { |
408 | const char *s = src; | 418 | const char *s = src; |
409 | int off; | 419 | int off; |
410 | while( isspace(*s) ) ++s; | 420 | while (isspace(*s)) |
411 | if( !(off = scan_ip6( s, net->address ) ) ) | 421 | ++s; |
422 | if (!(off = scan_ip6(s, net->address))) | ||
412 | return 0; | 423 | return 0; |
413 | s += off; | 424 | s += off; |
414 | if(*s!='/') | 425 | if (*s != '/') |
415 | net->bits = 128; | 426 | net->bits = 128; |
416 | else { | 427 | else { |
417 | s++; | 428 | s++; |
418 | if( !(off = scan_int (s, &net->bits ) ) ) | 429 | if (!(off = scan_int(s, &net->bits))) |
419 | return 0; | 430 | return 0; |
420 | if( ip6_isv4mapped(net->address)) | 431 | if (ip6_isv4mapped(net->address)) |
421 | net->bits += 96; | 432 | net->bits += 96; |
422 | if(net->bits > 128) | 433 | if (net->bits > 128) |
423 | return 0; | 434 | return 0; |
424 | s += off; | 435 | s += off; |
425 | } | 436 | } |
426 | return off+s-src; | 437 | return off + s - src; |
427 | } | 438 | } |
428 | 439 | ||
429 | int parse_configfile( char * config_filename ) { | 440 | int parse_configfile(char *config_filename) { |
430 | FILE * accesslist_filehandle; | 441 | FILE *accesslist_filehandle; |
431 | char inbuf[512]; | 442 | char inbuf[512]; |
432 | ot_ip6 tmpip; | 443 | ot_ip6 tmpip; |
433 | #if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE) | 444 | #if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE) |
434 | ot_net tmpnet; | 445 | ot_net tmpnet; |
435 | #endif | 446 | #endif |
436 | int bound = 0; | 447 | int bound = 0; |
437 | 448 | ||
438 | accesslist_filehandle = fopen( config_filename, "r" ); | 449 | accesslist_filehandle = fopen(config_filename, "r"); |
439 | 450 | ||
440 | if( accesslist_filehandle == NULL ) { | 451 | if (accesslist_filehandle == NULL) { |
441 | fprintf( stderr, "Warning: Can't open config file: %s.", config_filename ); | 452 | fprintf(stderr, "Warning: Can't open config file: %s.", config_filename); |
442 | return 0; | 453 | return 0; |
443 | } | 454 | } |
444 | 455 | ||
445 | while( fgets( inbuf, sizeof(inbuf), accesslist_filehandle ) ) { | 456 | while (fgets(inbuf, sizeof(inbuf), accesslist_filehandle)) { |
446 | char *p = inbuf; | 457 | char *p = inbuf; |
447 | size_t strl; | 458 | size_t strl; |
448 | 459 | ||
449 | /* Skip white spaces */ | 460 | /* Skip white spaces */ |
450 | while(isspace(*p)) ++p; | 461 | while (isspace(*p)) |
462 | ++p; | ||
451 | 463 | ||
452 | /* Ignore comments and empty lines */ | 464 | /* Ignore comments and empty lines */ |
453 | if((*p=='#')||(*p=='\n')||(*p==0)) continue; | 465 | if ((*p == '#') || (*p == '\n') || (*p == 0)) |
466 | continue; | ||
454 | 467 | ||
455 | /* consume trailing new lines and spaces */ | 468 | /* consume trailing new lines and spaces */ |
456 | strl = strlen(p); | 469 | strl = strlen(p); |
457 | while( strl && isspace(p[strl-1])) | 470 | while (strl && isspace(p[strl - 1])) |
458 | p[--strl] = 0; | 471 | p[--strl] = 0; |
459 | 472 | ||
460 | /* Scan for commands */ | 473 | /* Scan for commands */ |
461 | if(!byte_diff(p,15,"tracker.rootdir" ) && isspace(p[15])) { | 474 | if (!byte_diff(p, 15, "tracker.rootdir") && isspace(p[15])) { |
462 | set_config_option( &g_serverdir, p+16 ); | 475 | set_config_option(&g_serverdir, p + 16); |
463 | } else if(!byte_diff(p,12,"tracker.user" ) && isspace(p[12])) { | 476 | } else if (!byte_diff(p, 12, "tracker.user") && isspace(p[12])) { |
464 | set_config_option( &g_serveruser, p+13 ); | 477 | set_config_option(&g_serveruser, p + 13); |
465 | } 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])) { |
466 | uint16_t tmpport = 6969; | 479 | uint16_t tmpport = 6969; |
467 | if( !scan_ip6_port( p+15, tmpip, &tmpport )) goto parse_error; | 480 | if (!scan_ip6_port(p + 15, tmpip, &tmpport)) |
468 | ot_try_bind( tmpip, tmpport, FLAG_TCP ); ++bound; | 481 | goto parse_error; |
469 | ot_try_bind( tmpip, tmpport, FLAG_UDP ); ++bound; | 482 | ot_try_bind(tmpip, tmpport, FLAG_TCP); |
470 | } 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])) { | ||
471 | uint16_t tmpport = 6969; | 487 | uint16_t tmpport = 6969; |
472 | if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error; | 488 | if (!scan_ip6_port(p + 11, tmpip, &tmpport)) |
473 | ot_try_bind( tmpip, tmpport, FLAG_TCP ); | 489 | goto parse_error; |
490 | ot_try_bind(tmpip, tmpport, FLAG_TCP); | ||
474 | ++bound; | 491 | ++bound; |
475 | } else if(!byte_diff(p, 10, "listen.udp" ) && isspace(p[10])) { | 492 | } else if (!byte_diff(p, 10, "listen.udp") && isspace(p[10])) { |
476 | uint16_t tmpport = 6969; | 493 | uint16_t tmpport = 6969; |
477 | if( !scan_ip6_port( p+11, tmpip, &tmpport )) goto parse_error; | 494 | if (!scan_ip6_port(p + 11, tmpip, &tmpport)) |
478 | ot_try_bind( tmpip, tmpport, FLAG_UDP ); | 495 | goto parse_error; |
496 | ot_try_bind(tmpip, tmpport, FLAG_UDP); | ||
479 | ++bound; | 497 | ++bound; |
480 | } 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])) { |
481 | char *value = p + 18; | 499 | char *value = p + 18; |
482 | while( isspace(*value) ) ++value; | 500 | while (isspace(*value)) |
483 | scan_uint( value, &g_udp_workers ); | 501 | ++value; |
502 | scan_uint(value, &g_udp_workers); | ||
484 | #ifdef WANT_ACCESSLIST_WHITE | 503 | #ifdef WANT_ACCESSLIST_WHITE |
485 | } else if(!byte_diff(p, 16, "access.whitelist" ) && isspace(p[16])) { | 504 | } else if (!byte_diff(p, 16, "access.whitelist") && isspace(p[16])) { |
486 | set_config_option( &g_accesslist_filename, p+17 ); | 505 | set_config_option(&g_accesslist_filename, p + 17); |
487 | #elif defined( WANT_ACCESSLIST_BLACK ) | 506 | #elif defined(WANT_ACCESSLIST_BLACK) |
488 | } else if(!byte_diff(p, 16, "access.blacklist" ) && isspace(p[16])) { | 507 | } else if (!byte_diff(p, 16, "access.blacklist") && isspace(p[16])) { |
489 | set_config_option( &g_accesslist_filename, p+17 ); | 508 | set_config_option(&g_accesslist_filename, p + 17); |
490 | #endif | 509 | #endif |
491 | #ifdef WANT_DYNAMIC_ACCESSLIST | 510 | #ifdef WANT_DYNAMIC_ACCESSLIST |
492 | } 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])) { |
493 | set_config_option( &g_accesslist_pipe_add, p+16 ); | 512 | set_config_option(&g_accesslist_pipe_add, p + 16); |
494 | } 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])) { |
495 | set_config_option( &g_accesslist_pipe_delete, p+19 ); | 514 | set_config_option(&g_accesslist_pipe_delete, p + 19); |
496 | #endif | 515 | #endif |
497 | #ifdef WANT_RESTRICT_STATS | 516 | #ifdef WANT_RESTRICT_STATS |
498 | } else if(!byte_diff(p, 12, "access.stats" ) && isspace(p[12])) { | 517 | } else if (!byte_diff(p, 12, "access.stats") && isspace(p[12])) { |
499 | if( !scan_ip6_net( p+13, &tmpnet )) goto parse_error; | 518 | if (!scan_ip6_net(p + 13, &tmpnet)) |
500 | accesslist_bless_net( &tmpnet, OT_PERMISSION_MAY_STAT ); | 519 | goto parse_error; |
520 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT); | ||
501 | #endif | 521 | #endif |
502 | } 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])) { |
503 | set_config_option( &g_stats_path, p+18 ); | 523 | set_config_option(&g_stats_path, p + 18); |
504 | #ifdef WANT_IP_FROM_PROXY | 524 | #ifdef WANT_IP_FROM_PROXY |
505 | } else if(!byte_diff(p, 12, "access.proxy" ) && isspace(p[12])) { | 525 | } else if (!byte_diff(p, 12, "access.proxy") && isspace(p[12])) { |
506 | if( !scan_ip6_net( p+13, &tmpnet )) goto parse_error; | 526 | if (!scan_ip6_net(p + 13, &tmpnet)) |
507 | accesslist_bless_net( &tmpnet, OT_PERMISSION_MAY_PROXY ); | 527 | goto parse_error; |
528 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY); | ||
508 | #endif | 529 | #endif |
509 | } 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])) { |
510 | set_config_option( &g_redirecturl, p+21 ); | 531 | set_config_option(&g_redirecturl, p + 21); |
511 | #ifdef WANT_SYNC_LIVE | 532 | #ifdef WANT_SYNC_LIVE |
512 | } 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])) { |
513 | if( !scan_ip6_net( p+25, &tmpnet )) goto parse_error; | 534 | if (!scan_ip6_net(p + 25, &tmpnet)) |
514 | accesslist_bless_net( &tmpnet, OT_PERMISSION_MAY_LIVESYNC ); | 535 | goto parse_error; |
515 | } 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])) { | ||
516 | uint16_t tmpport = LIVESYNC_PORT; | 538 | uint16_t tmpport = LIVESYNC_PORT; |
517 | if( !scan_ip6_port( p+24, tmpip, &tmpport )) goto parse_error; | 539 | if (!scan_ip6_port(p + 24, tmpip, &tmpport)) |
518 | livesync_bind_mcast( tmpip, tmpport ); | 540 | goto parse_error; |
541 | livesync_bind_mcast(tmpip, tmpport); | ||
519 | #endif | 542 | #endif |
520 | } else | 543 | } else |
521 | fprintf( stderr, "Unhandled line in config file: %s\n", inbuf ); | 544 | fprintf(stderr, "Unhandled line in config file: %s\n", inbuf); |
522 | continue; | 545 | continue; |
523 | parse_error: | 546 | parse_error: |
524 | fprintf( stderr, "Parse error in config file: %s\n", inbuf); | 547 | fprintf(stderr, "Parse error in config file: %s\n", inbuf); |
525 | } | 548 | } |
526 | fclose( accesslist_filehandle ); | 549 | fclose(accesslist_filehandle); |
527 | return bound; | 550 | return bound; |
528 | } | 551 | } |
529 | 552 | ||
530 | void load_state(const char * const state_filename ) { | 553 | void load_state(const char *const state_filename) { |
531 | FILE * state_filehandle; | 554 | FILE *state_filehandle; |
532 | char inbuf[512]; | 555 | char inbuf[512]; |
533 | ot_hash infohash; | 556 | ot_hash infohash; |
534 | unsigned long long base, downcount; | 557 | unsigned long long base, downcount; |
535 | int consumed; | 558 | int consumed; |
536 | 559 | ||
537 | state_filehandle = fopen( state_filename, "r" ); | 560 | state_filehandle = fopen(state_filename, "r"); |
538 | 561 | ||
539 | if( state_filehandle == NULL ) { | 562 | if (state_filehandle == NULL) { |
540 | fprintf( stderr, "Warning: Can't open config file: %s.", state_filename ); | 563 | fprintf(stderr, "Warning: Can't open config file: %s.", state_filename); |
541 | return; | 564 | return; |
542 | } | 565 | } |
543 | 566 | ||
544 | /* 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+" */ |
545 | while( fgets( inbuf, sizeof(inbuf), state_filehandle ) ) { | 568 | while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { |
546 | int i; | 569 | int i; |
547 | for( i=0; i<(int)sizeof(ot_hash); ++i ) { | 570 | for (i = 0; i < (int)sizeof(ot_hash); ++i) { |
548 | 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]); |
549 | if( eger < 0 ) | 572 | if (eger < 0) |
550 | continue; | 573 | continue; |
551 | infohash[i] = eger; | 574 | infohash[i] = eger; |
552 | } | 575 | } |
553 | 576 | ||
554 | if( i != (int)sizeof(ot_hash) ) continue; | 577 | if (i != (int)sizeof(ot_hash)) |
578 | continue; | ||
555 | i *= 2; | 579 | i *= 2; |
556 | 580 | ||
557 | if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &base ) ) ) continue; | 581 | if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &base))) |
582 | continue; | ||
558 | i += consumed; | 583 | i += consumed; |
559 | if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue; | 584 | if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &downcount))) |
560 | add_torrent_from_saved_state( infohash, base, downcount ); | 585 | continue; |
586 | add_torrent_from_saved_state(infohash, base, downcount); | ||
561 | } | 587 | } |
562 | 588 | ||
563 | fclose( state_filehandle ); | 589 | fclose(state_filehandle); |
564 | } | 590 | } |
565 | 591 | ||
566 | int drop_privileges ( const char * const serveruser, const char * const serverdir ) { | 592 | int drop_privileges(const char *const serveruser, const char *const serverdir) { |
567 | struct passwd *pws = NULL; | 593 | struct passwd *pws = NULL; |
568 | 594 | ||
569 | #ifdef _DEBUG | 595 | #ifdef _DEBUG |
570 | if( !geteuid() ) | 596 | if (!geteuid()) |
571 | fprintf( stderr, "Dropping to user %s.\n", serveruser ); | 597 | fprintf(stderr, "Dropping to user %s.\n", serveruser); |
572 | if( serverdir ) | 598 | if (serverdir) |
573 | 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); |
574 | #endif | 600 | #endif |
575 | 601 | ||
576 | /* Grab pws entry before chrooting */ | 602 | /* Grab pws entry before chrooting */ |
577 | pws = getpwnam( serveruser ); | 603 | pws = getpwnam(serveruser); |
578 | endpwent(); | 604 | endpwent(); |
579 | 605 | ||
580 | if( geteuid() == 0 ) { | 606 | if (geteuid() == 0) { |
581 | /* Running as root: chroot and drop privileges */ | 607 | /* Running as root: chroot and drop privileges */ |
582 | if( serverdir && chroot( serverdir ) ) { | 608 | if (serverdir && chroot(serverdir)) { |
583 | 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)); |
584 | return -1; | 610 | return -1; |
585 | } | 611 | } |
586 | 612 | ||
587 | if(chdir("/")) | 613 | if (chdir("/")) |
588 | panic("chdir() failed after chrooting: "); | 614 | panic("chdir() failed after chrooting: "); |
589 | 615 | ||
590 | /* 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 */ |
591 | if( !pws ) { | 617 | if (!pws) { |
592 | 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); |
593 | 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)) |
594 | panic("Could not set uid to value -2"); | 620 | panic("Could not set uid to value -2"); |
595 | } | 621 | } else { |
596 | else { | 622 | if (setegid(pws->pw_gid) || setgid(pws->pw_gid) || setuid(pws->pw_uid) || seteuid(pws->pw_uid)) |
597 | if (setegid( pws->pw_gid ) || setgid( pws->pw_gid ) || setuid( pws->pw_uid ) || seteuid( pws->pw_uid )) | ||
598 | panic("Could not set uid to specified value"); | 623 | panic("Could not set uid to specified value"); |
599 | } | 624 | } |
600 | 625 | ||
601 | if( geteuid() == 0 || getegid() == 0 ) | 626 | if (geteuid() == 0 || getegid() == 0) |
602 | panic("Still running with root privileges?!"); | 627 | panic("Still running with root privileges?!"); |
603 | } | 628 | } else { |
604 | else { | ||
605 | /* Normal user, just chdir() */ | 629 | /* Normal user, just chdir() */ |
606 | if( serverdir && chdir( serverdir ) ) { | 630 | if (serverdir && chdir(serverdir)) { |
607 | 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)); |
608 | return -1; | 632 | return -1; |
609 | } | 633 | } |
610 | } | 634 | } |
@@ -613,7 +637,7 @@ int drop_privileges ( const char * const serveruser, const char * const serverdi | |||
613 | } | 637 | } |
614 | 638 | ||
615 | /* Maintain our copy of the clock. time() on BSDs is very expensive. */ | 639 | /* Maintain our copy of the clock. time() on BSDs is very expensive. */ |
616 | static void *time_caching_worker(void*args) { | 640 | static void *time_caching_worker(void *args) { |
617 | (void)args; | 641 | (void)args; |
618 | while (1) { | 642 | while (1) { |
619 | g_now_seconds = time(NULL); | 643 | g_now_seconds = time(NULL); |
@@ -621,105 +645,146 @@ static void *time_caching_worker(void*args) { | |||
621 | } | 645 | } |
622 | } | 646 | } |
623 | 647 | ||
624 | int main( int argc, char **argv ) { | 648 | int main(int argc, char **argv) { |
625 | ot_ip6 serverip; | 649 | ot_ip6 serverip; |
626 | ot_net tmpnet; | 650 | ot_net tmpnet; |
627 | int bound = 0, scanon = 1; | 651 | int bound = 0, scanon = 1; |
628 | uint16_t tmpport; | 652 | uint16_t tmpport; |
629 | char * statefile = 0; | 653 | char *statefile = 0; |
630 | pthread_t thread_id; /* time cacher */ | 654 | pthread_t thread_id; /* time cacher */ |
631 | 655 | ||
632 | memset( serverip, 0, sizeof(ot_ip6) ); | 656 | memset(serverip, 0, sizeof(ot_ip6)); |
633 | #ifdef WANT_V4_ONLY | 657 | #ifdef WANT_V4_ONLY |
634 | serverip[10]=serverip[11]=-1; | 658 | serverip[10] = serverip[11] = -1; |
635 | #endif | 659 | #endif |
636 | 660 | ||
637 | #ifdef WANT_DEV_RANDOM | 661 | #ifdef WANT_DEV_RANDOM |
638 | srandomdev(); | 662 | srandomdev(); |
639 | #else | 663 | #else |
640 | srandom( time(NULL) ); | 664 | srandom(time(NULL)); |
641 | #endif | 665 | #endif |
642 | 666 | ||
643 | while( scanon ) { | 667 | while (scanon) { |
644 | switch( getopt( argc, argv, ":i:p:A:P:d:u:r:s:f:l:v" | 668 | switch (getopt(argc, argv, |
669 | ":i:p:A:P:d:u:r:s:f:l:v" | ||
645 | #ifdef WANT_ACCESSLIST_BLACK | 670 | #ifdef WANT_ACCESSLIST_BLACK |
646 | "b:" | 671 | "b:" |
647 | #elif defined( WANT_ACCESSLIST_WHITE ) | 672 | #elif defined(WANT_ACCESSLIST_WHITE) |
648 | "w:" | 673 | "w:" |
649 | #endif | 674 | #endif |
650 | "h" ) ) { | 675 | "h")) { |
651 | case -1 : scanon = 0; break; | 676 | case -1: |
652 | case 'i': | 677 | scanon = 0; |
653 | if( !scan_ip6( optarg, serverip )) { usage( argv[0] ); exit( 1 ); } | 678 | break; |
654 | break; | 679 | case 'i': |
680 | if (!scan_ip6(optarg, serverip)) { | ||
681 | usage(argv[0]); | ||
682 | exit(1); | ||
683 | } | ||
684 | break; | ||
655 | #ifdef WANT_ACCESSLIST_BLACK | 685 | #ifdef WANT_ACCESSLIST_BLACK |
656 | case 'b': set_config_option( &g_accesslist_filename, optarg); break; | 686 | case 'b': |
657 | #elif defined( WANT_ACCESSLIST_WHITE ) | 687 | set_config_option(&g_accesslist_filename, optarg); |
658 | case 'w': set_config_option( &g_accesslist_filename, optarg); break; | 688 | break; |
689 | #elif defined(WANT_ACCESSLIST_WHITE) | ||
690 | case 'w': | ||
691 | set_config_option(&g_accesslist_filename, optarg); | ||
692 | break; | ||
659 | #endif | 693 | #endif |
660 | case 'p': | 694 | case 'p': |
661 | if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); } | 695 | if (!scan_ushort(optarg, &tmpport)) { |
662 | ot_try_bind( serverip, tmpport, FLAG_TCP ); bound++; break; | 696 | usage(argv[0]); |
663 | case 'P': | 697 | exit(1); |
664 | if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); } | 698 | } |
665 | ot_try_bind( serverip, tmpport, FLAG_UDP ); bound++; break; | 699 | ot_try_bind(serverip, tmpport, FLAG_TCP); |
700 | bound++; | ||
701 | break; | ||
702 | case 'P': | ||
703 | if (!scan_ushort(optarg, &tmpport)) { | ||
704 | usage(argv[0]); | ||
705 | exit(1); | ||
706 | } | ||
707 | ot_try_bind(serverip, tmpport, FLAG_UDP); | ||
708 | bound++; | ||
709 | break; | ||
666 | #ifdef WANT_SYNC_LIVE | 710 | #ifdef WANT_SYNC_LIVE |
667 | case 's': | 711 | case 's': |
668 | if( !scan_ushort( optarg, &tmpport)) { usage( argv[0] ); exit( 1 ); } | 712 | if (!scan_ushort(optarg, &tmpport)) { |
669 | livesync_bind_mcast( serverip, tmpport); break; | 713 | usage(argv[0]); |
714 | exit(1); | ||
715 | } | ||
716 | livesync_bind_mcast(serverip, tmpport); | ||
717 | break; | ||
670 | #endif | 718 | #endif |
671 | case 'd': set_config_option( &g_serverdir, optarg ); break; | 719 | case 'd': |
672 | case 'u': set_config_option( &g_serveruser, optarg ); break; | 720 | set_config_option(&g_serverdir, optarg); |
673 | case 'r': set_config_option( &g_redirecturl, optarg ); break; | 721 | break; |
674 | case 'l': statefile = optarg; break; | 722 | case 'u': |
675 | case 'A': | 723 | set_config_option(&g_serveruser, optarg); |
676 | if( !scan_ip6_net( optarg, &tmpnet )) { usage( argv[0] ); exit( 1 ); } | 724 | break; |
677 | accesslist_bless_net( &tmpnet, 0xffff ); /* Allow everything for now */ | 725 | case 'r': |
678 | break; | 726 | set_config_option(&g_redirecturl, optarg); |
679 | case 'f': bound += parse_configfile( optarg ); break; | 727 | break; |
680 | case 'h': help( argv[0] ); exit( 0 ); | 728 | case 'l': |
681 | case 'v': { | 729 | statefile = optarg; |
682 | char buffer[8192]; | 730 | break; |
683 | stats_return_tracker_version( buffer ); | 731 | case 'A': |
684 | fputs( buffer, stderr ); | 732 | if (!scan_ip6_net(optarg, &tmpnet)) { |
685 | exit( 0 ); | 733 | usage(argv[0]); |
734 | exit(1); | ||
686 | } | 735 | } |
687 | default: | 736 | accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */ |
688 | case '?': usage( argv[0] ); exit( 1 ); | 737 | break; |
738 | case 'f': | ||
739 | bound += parse_configfile(optarg); | ||
740 | break; | ||
741 | case 'h': | ||
742 | help(argv[0]); | ||
743 | exit(0); | ||
744 | case 'v': { | ||
745 | char buffer[8192]; | ||
746 | stats_return_tracker_version(buffer); | ||
747 | fputs(buffer, stderr); | ||
748 | exit(0); | ||
749 | } | ||
750 | default: | ||
751 | case '?': | ||
752 | usage(argv[0]); | ||
753 | exit(1); | ||
689 | } | 754 | } |
690 | } | 755 | } |
691 | 756 | ||
692 | /* Bind to our default tcp/udp ports */ | 757 | /* Bind to our default tcp/udp ports */ |
693 | if( !bound) { | 758 | if (!bound) { |
694 | ot_try_bind( serverip, 6969, FLAG_TCP ); | 759 | ot_try_bind(serverip, 6969, FLAG_TCP); |
695 | ot_try_bind( serverip, 6969, FLAG_UDP ); | 760 | ot_try_bind(serverip, 6969, FLAG_UDP); |
696 | } | 761 | } |
697 | 762 | ||
698 | #ifdef WANT_SYSLOGS | 763 | #ifdef WANT_SYSLOGS |
699 | openlog( "opentracker", 0, LOG_USER ); | 764 | openlog("opentracker", 0, LOG_USER); |
700 | setlogmask(LOG_UPTO(LOG_INFO)); | 765 | setlogmask(LOG_UPTO(LOG_INFO)); |
701 | #endif | 766 | #endif |
702 | 767 | ||
703 | if( drop_privileges( g_serveruser ? g_serveruser : "nobody", g_serverdir ) == -1 ) | 768 | if (drop_privileges(g_serveruser ? g_serveruser : "nobody", g_serverdir) == -1) |
704 | panic( "drop_privileges failed, exiting. Last error"); | 769 | panic("drop_privileges failed, exiting. Last error"); |
705 | 770 | ||
706 | g_now_seconds = time( NULL ); | 771 | g_now_seconds = time(NULL); |
707 | pthread_create( &thread_id, NULL, time_caching_worker, NULL); | 772 | pthread_create(&thread_id, NULL, time_caching_worker, NULL); |
708 | 773 | ||
709 | /* Create our self pipe which allows us to interrupt mainloops | 774 | /* Create our self pipe which allows us to interrupt mainloops |
710 | io_wait in case some data is available to send out */ | 775 | io_wait in case some data is available to send out */ |
711 | if( pipe( g_self_pipe ) == -1 ) | 776 | if (pipe(g_self_pipe) == -1) |
712 | panic( "selfpipe failed: " ); | 777 | panic("selfpipe failed: "); |
713 | if( !io_fd( g_self_pipe[0] ) ) | 778 | if (!io_fd(g_self_pipe[0])) |
714 | panic( "selfpipe io_fd failed: " ); | 779 | panic("selfpipe io_fd failed: "); |
715 | if( !io_fd( g_self_pipe[1] ) ) | 780 | if (!io_fd(g_self_pipe[1])) |
716 | panic( "selfpipe io_fd failed: " ); | 781 | panic("selfpipe io_fd failed: "); |
717 | io_setcookie( g_self_pipe[0], (void*)FLAG_SELFPIPE ); | 782 | io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE); |
718 | io_wantread( g_self_pipe[0] ); | 783 | io_wantread(g_self_pipe[0]); |
719 | 784 | ||
720 | defaul_signal_handlers( ); | 785 | defaul_signal_handlers(); |
721 | /* Init all sub systems. This call may fail with an exit() */ | 786 | /* Init all sub systems. This call may fail with an exit() */ |
722 | trackerlogic_init( ); | 787 | trackerlogic_init(); |
723 | 788 | ||
724 | #ifdef _DEBUG_RANDOMTORRENTS | 789 | #ifdef _DEBUG_RANDOMTORRENTS |
725 | fprintf(stderr, "DEBUG: Generating %d random peers on random torrents. This may take a while. (Setting RANDOMTORRENTS in trackerlogic.h)\n", RANDOMTORRENTS); | 790 | fprintf(stderr, "DEBUG: Generating %d random peers on random torrents. This may take a while. (Setting RANDOMTORRENTS in trackerlogic.h)\n", RANDOMTORRENTS); |
@@ -727,15 +792,15 @@ int main( int argc, char **argv ) { | |||
727 | fprintf(stderr, "... done.\n"); | 792 | fprintf(stderr, "... done.\n"); |
728 | #endif | 793 | #endif |
729 | 794 | ||
730 | if( statefile ) | 795 | if (statefile) |
731 | load_state( statefile ); | 796 | load_state(statefile); |
732 | 797 | ||
733 | install_signal_handlers( ); | 798 | install_signal_handlers(); |
734 | 799 | ||
735 | if( !g_udp_workers ) | 800 | if (!g_udp_workers) |
736 | udp_init( -1, 0 ); | 801 | udp_init(-1, 0); |
737 | 802 | ||
738 | server_mainloop( 0 ); | 803 | server_mainloop(0); |
739 | 804 | ||
740 | return 0; | 805 | return 0; |
741 | } | 806 | } |