diff options
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | opentracker.c | 54 | ||||
| -rw-r--r-- | ot_accesslist.c | 30 | ||||
| -rw-r--r-- | ot_accesslist.h | 2 | ||||
| -rw-r--r-- | ot_buf.c | 41 | ||||
| -rw-r--r-- | ot_buf.h | 27 | ||||
| -rw-r--r-- | ot_fullscrape.c | 2 | ||||
| -rw-r--r-- | ot_fullscrape.h | 2 | ||||
| -rw-r--r-- | ot_hex.c | 20 | ||||
| -rw-r--r-- | ot_hex.h | 4 | ||||
| -rw-r--r-- | ot_http.c | 81 | ||||
| -rw-r--r-- | ot_http.h | 10 | ||||
| -rw-r--r-- | ot_ip.c | 201 | ||||
| -rw-r--r-- | ot_ip.h | 33 | ||||
| -rw-r--r-- | ot_livesync.c | 14 | ||||
| -rw-r--r-- | ot_livesync.h | 2 | ||||
| -rw-r--r-- | ot_mutex.c | 13 | ||||
| -rw-r--r-- | ot_mutex.h | 14 | ||||
| -rw-r--r-- | ot_stats.c | 15 | ||||
| -rw-r--r-- | ot_stats.h | 2 | ||||
| -rw-r--r-- | ot_sync.c | 2 | ||||
| -rw-r--r-- | ot_sync.h | 4 | ||||
| -rw-r--r-- | ot_udp.c | 10 | ||||
| -rw-r--r-- | ot_udp.h | 6 | ||||
| -rw-r--r-- | ot_vector.c | 2 | ||||
| -rw-r--r-- | proxy.c | 36 | ||||
| -rw-r--r-- | tests/runner.c | 2 | ||||
| -rw-r--r-- | tests/t_buf.c | 205 | ||||
| -rw-r--r-- | tests/t_ip.c | 217 | ||||
| -rw-r--r-- | tests/test.h | 2 | ||||
| -rw-r--r-- | trackerlogic.c | 12 |
31 files changed, 922 insertions, 153 deletions
| @@ -68,9 +68,9 @@ CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread | |||
| 68 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread | 68 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread |
| 69 | 69 | ||
| 70 | BINARY =opentracker | 70 | BINARY =opentracker |
| 71 | HEADERS=trackerlogic.h scan_urlencoded_query.h ot_hex.h ot_scan.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h | 71 | HEADERS=trackerlogic.h scan_urlencoded_query.h ot_buf.h ot_hex.h ot_ip.h ot_scan.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h |
| 72 | SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_hex.c ot_scan.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c | 72 | SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_buf.c ot_hex.c ot_ip.c ot_scan.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c |
| 73 | SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c | 73 | SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c ot_ip.c |
| 74 | 74 | ||
| 75 | OBJECTS = $(SOURCES:%.c=%.o) | 75 | OBJECTS = $(SOURCES:%.c=%.o) |
| 76 | OBJECTS_debug = $(SOURCES:%.c=%.debug.o) | 76 | OBJECTS_debug = $(SOURCES:%.c=%.debug.o) |
| @@ -105,8 +105,8 @@ proxy.debug: $(OBJECTS_proxy_debug) $(HEADERS) | |||
| 105 | # has to. tests/stubs.c supplies the few symbols those modules reference but | 105 | # has to. tests/stubs.c supplies the few symbols those modules reference but |
| 106 | # the tests never reach. | 106 | # the tests never reach. |
| 107 | TESTBIN=tests/runner | 107 | TESTBIN=tests/runner |
| 108 | TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_scan_urlencoded_query.c tests/t_iovec.c tests/t_vector.c tests/t_random.c tests/t_hex.c tests/t_accesslist.c tests/t_scan.c | 108 | TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_scan_urlencoded_query.c tests/t_iovec.c tests/t_vector.c tests/t_random.c tests/t_hex.c tests/t_accesslist.c tests/t_scan.c tests/t_buf.c tests/t_ip.c |
| 109 | TEST_UNITS=scan_urlencoded_query.c ot_iovec.c ot_vector.c ot_random.c ot_hex.c ot_scan.c ot_accesslist.c | 109 | TEST_UNITS=scan_urlencoded_query.c ot_buf.c ot_ip.c ot_iovec.c ot_vector.c ot_random.c ot_hex.c ot_scan.c ot_accesslist.c |
| 110 | TEST_HEADERS=tests/test.h $(HEADERS) | 110 | TEST_HEADERS=tests/test.h $(HEADERS) |
| 111 | # Tests reach code that sits behind feature flags, so the units under test are | 111 | # Tests reach code that sits behind feature flags, so the units under test are |
| 112 | # built with those features enabled. A test binary is not a production binary. | 112 | # built with those features enabled. A test binary is not a production binary. |
diff --git a/opentracker.c b/opentracker.c index bcc075c..af336aa 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -24,17 +24,17 @@ | |||
| 24 | /* Libowfat */ | 24 | /* Libowfat */ |
| 25 | #include "io.h" | 25 | #include "io.h" |
| 26 | #include "iob.h" | 26 | #include "iob.h" |
| 27 | #include "ip6.h" | ||
| 28 | #include "socket.h" | 27 | #include "socket.h" |
| 29 | 28 | ||
| 30 | /* Opentracker */ | 29 | /* Opentracker */ |
| 31 | #include "ot_accesslist.h" | 30 | #include "ot_accesslist.h" |
| 32 | #include "ot_hex.h" | 31 | #include "ot_hex.h" |
| 33 | #include "ot_http.h" | 32 | #include "ot_http.h" |
| 33 | #include "ot_ip.h" | ||
| 34 | #include "ot_livesync.h" | 34 | #include "ot_livesync.h" |
| 35 | #include "ot_mutex.h" | 35 | #include "ot_mutex.h" |
| 36 | #include "ot_scan.h" | ||
| 37 | #include "ot_random.h" | 36 | #include "ot_random.h" |
| 37 | #include "ot_scan.h" | ||
| 38 | #include "ot_stats.h" | 38 | #include "ot_stats.h" |
| 39 | #include "ot_udp.h" | 39 | #include "ot_udp.h" |
| 40 | #include "trackerlogic.h" | 40 | #include "trackerlogic.h" |
| @@ -156,14 +156,14 @@ static ssize_t header_complete(char *request, ssize_t byte_count) { | |||
| 156 | return 0; | 156 | return 0; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | static void handle_dead(const int64 sock) { | 159 | static void handle_dead(const int64_t sock) { |
| 160 | struct http_data *cookie = io_getcookie(sock); | 160 | struct http_data *cookie = io_getcookie(sock); |
| 161 | if (cookie) { | 161 | if (cookie) { |
| 162 | size_t i; | 162 | size_t i; |
| 163 | for (i = 0; i < cookie->batches; ++i) | 163 | for (i = 0; i < cookie->batches; ++i) |
| 164 | iob_reset(cookie->batch + i); | 164 | iob_reset(cookie->batch + i); |
| 165 | free(cookie->batch); | 165 | free(cookie->batch); |
| 166 | array_reset(&cookie->request); | 166 | buf_reset(&cookie->request); |
| 167 | if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) | 167 | if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) |
| 168 | mutex_workqueue_canceltask(sock); | 168 | mutex_workqueue_canceltask(sock); |
| 169 | free(cookie); | 169 | free(cookie); |
| @@ -171,7 +171,7 @@ static void handle_dead(const int64 sock) { | |||
| 171 | io_close(sock); | 171 | io_close(sock); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static void handle_read(const int64 sock, struct ot_workstruct *ws) { | 174 | static void handle_read(const int64_t sock, struct ot_workstruct *ws) { |
| 175 | struct http_data *cookie = io_getcookie(sock); | 175 | struct http_data *cookie = io_getcookie(sock); |
| 176 | ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); | 176 | ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); |
| 177 | 177 | ||
| @@ -183,26 +183,30 @@ static void handle_read(const int64 sock, struct ot_workstruct *ws) { | |||
| 183 | if (byte_count == -1) | 183 | if (byte_count == -1) |
| 184 | return; | 184 | return; |
| 185 | 185 | ||
| 186 | ws->request = NULL; | ||
| 187 | ws->request_size = 0; | ||
| 188 | ws->header_size = 0; | ||
| 189 | ws->keep_alive = 0; | ||
| 190 | |||
| 186 | /* If we get the whole request in one packet, handle it without copying */ | 191 | /* If we get the whole request in one packet, handle it without copying */ |
| 187 | if (!array_start(&cookie->request)) { | 192 | if (!cookie->request.data) { |
| 188 | if ((ws->header_size = header_complete(ws->inbuf, byte_count))) { | 193 | if ((ws->header_size = header_complete(ws->inbuf, byte_count))) { |
| 189 | ws->request = ws->inbuf; | 194 | ws->request = ws->inbuf; |
| 190 | ws->request_size = byte_count; | 195 | ws->request_size = byte_count; |
| 191 | http_handle_request(sock, ws); | 196 | http_handle_request(sock, ws); |
| 192 | } else | 197 | } else if (buf_cat(&cookie->request, ws->inbuf, (size_t)byte_count)) |
| 193 | array_catb(&cookie->request, ws->inbuf, (size_t)byte_count); | 198 | handle_dead(sock); |
| 194 | return; | 199 | return; |
| 195 | } | 200 | } |
| 196 | 201 | ||
| 197 | array_catb(&cookie->request, ws->inbuf, byte_count); | 202 | if (buf_cat(&cookie->request, ws->inbuf, (size_t)byte_count) || cookie->request.size > G_INBUF_SIZE) { |
| 198 | if (array_failed(&cookie->request) || array_bytes(&cookie->request) > 8192) { | ||
| 199 | http_issue_error(sock, ws, CODE_HTTPERROR_500); | 203 | http_issue_error(sock, ws, CODE_HTTPERROR_500); |
| 200 | return; | 204 | return; |
| 201 | } | 205 | } |
| 202 | 206 | ||
| 203 | while ((ws->header_size = header_complete(array_start(&cookie->request), array_bytes(&cookie->request)))) { | 207 | while ((ws->header_size = header_complete(cookie->request.data, (ssize_t)cookie->request.size))) { |
| 204 | ws->request = array_start(&cookie->request); | 208 | ws->request = cookie->request.data; |
| 205 | ws->request_size = array_bytes(&cookie->request); | 209 | ws->request_size = (ssize_t)cookie->request.size; |
| 206 | http_handle_request(sock, ws); | 210 | http_handle_request(sock, ws); |
| 207 | #ifdef WANT_KEEPALIVE | 211 | #ifdef WANT_KEEPALIVE |
| 208 | if (!ws->keep_alive) | 212 | if (!ws->keep_alive) |
| @@ -211,7 +215,7 @@ static void handle_read(const int64 sock, struct ot_workstruct *ws) { | |||
| 211 | } | 215 | } |
| 212 | } | 216 | } |
| 213 | 217 | ||
| 214 | static void handle_write(const int64 sock) { | 218 | static void handle_write(const int64_t sock) { |
| 215 | struct http_data *cookie = io_getcookie(sock); | 219 | struct http_data *cookie = io_getcookie(sock); |
| 216 | size_t i; | 220 | size_t i; |
| 217 | int chunked = 0; | 221 | int chunked = 0; |
| @@ -223,7 +227,7 @@ static void handle_write(const int64 sock) { | |||
| 223 | 227 | ||
| 224 | for (i = 0; i < cookie->batches; ++i) { | 228 | for (i = 0; i < cookie->batches; ++i) { |
| 225 | if (cookie->batch[i].bytesleft) { | 229 | if (cookie->batch[i].bytesleft) { |
| 226 | int64 res = iob_send(sock, cookie->batch + i); | 230 | int64_t res = iob_send(sock, cookie->batch + i); |
| 227 | 231 | ||
| 228 | if (res == -3) { | 232 | if (res == -3) { |
| 229 | handle_dead(sock); | 233 | handle_dead(sock); |
| @@ -246,9 +250,9 @@ static void handle_write(const int64 sock) { | |||
| 246 | handle_dead(sock); | 250 | handle_dead(sock); |
| 247 | } | 251 | } |
| 248 | 252 | ||
| 249 | static void handle_accept(const int64 serversocket) { | 253 | static void handle_accept(const int64_t serversocket) { |
| 250 | struct http_data *cookie; | 254 | struct http_data *cookie; |
| 251 | int64 sock; | 255 | int64_t sock; |
| 252 | ot_ip6 ip; | 256 | ot_ip6 ip; |
| 253 | uint16 port; | 257 | uint16 port; |
| 254 | tai6464 t; | 258 | tai6464 t; |
| @@ -301,7 +305,7 @@ static void *server_mainloop(void *args) { | |||
| 301 | random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); | 305 | random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); |
| 302 | 306 | ||
| 303 | for (;;) { | 307 | for (;;) { |
| 304 | int64 sock; | 308 | int64_t sock; |
| 305 | 309 | ||
| 306 | io_wait(); | 310 | io_wait(); |
| 307 | 311 | ||
| @@ -335,14 +339,14 @@ static void *server_mainloop(void *args) { | |||
| 335 | } | 339 | } |
| 336 | 340 | ||
| 337 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) { | 341 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) { |
| 338 | int64 sock = proto == FLAG_TCP ? socket_tcp6() : socket_udp6(); | 342 | int64_t sock = proto == FLAG_TCP ? socket_tcp6() : socket_udp6(); |
| 339 | 343 | ||
| 340 | #ifdef _DEBUG | 344 | #ifdef _DEBUG |
| 341 | { | 345 | { |
| 342 | char *protos[] = {"TCP", "UDP", "UDP mcast"}; | 346 | char *protos[] = {"TCP", "UDP", "UDP mcast"}; |
| 343 | char _debug[512]; | 347 | char _debug[512]; |
| 344 | int off = snprintf(_debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto]); | 348 | int off = snprintf(_debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto]); |
| 345 | off += fmt_ip6c(_debug + off, ip); | 349 | off += ip_format(_debug + off, ip); |
| 346 | snprintf(_debug + off, sizeof(_debug) - off, "]:%d...", port); | 350 | snprintf(_debug + off, sizeof(_debug) - off, "]:%d...", port); |
| 347 | fputs(_debug, stderr); | 351 | fputs(_debug, stderr); |
| 348 | } | 352 | } |
| @@ -390,14 +394,14 @@ static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { | |||
| 390 | ++s; | 394 | ++s; |
| 391 | if (*s == '[') | 395 | if (*s == '[') |
| 392 | ++s, ++bracket; /* for v6 style notation */ | 396 | ++s, ++bracket; /* for v6 style notation */ |
| 393 | if (!(off = scan_ip6(s, ip))) | 397 | if (!(off = ip_scan(s, ip))) |
| 394 | return 0; | 398 | return 0; |
| 395 | s += off; | 399 | s += off; |
| 396 | if (bracket && *s == ']') | 400 | if (bracket && *s == ']') |
| 397 | ++s; | 401 | ++s; |
| 398 | if (*s == 0 || isspace(*s)) | 402 | if (*s == 0 || isspace(*s)) |
| 399 | return s - src; | 403 | return s - src; |
| 400 | if (!ip6_isv4mapped(ip)) { | 404 | if (!ip_is_v4mapped(ip)) { |
| 401 | if (*s != ':' && *s != '.') | 405 | if (*s != ':' && *s != '.') |
| 402 | return 0; | 406 | return 0; |
| 403 | if (!bracket && *(s) == ':') | 407 | if (!bracket && *(s) == ':') |
| @@ -419,7 +423,7 @@ static int scan_ip6_net(const char *src, ot_net *net) { | |||
| 419 | int off; | 423 | int off; |
| 420 | while (isspace(*s)) | 424 | while (isspace(*s)) |
| 421 | ++s; | 425 | ++s; |
| 422 | if (!(off = scan_ip6(s, net->address))) | 426 | if (!(off = ip_scan(s, net->address))) |
| 423 | return 0; | 427 | return 0; |
| 424 | s += off; | 428 | s += off; |
| 425 | if (*s != '/') | 429 | if (*s != '/') |
| @@ -429,7 +433,7 @@ static int scan_ip6_net(const char *src, ot_net *net) { | |||
| 429 | if (!(off = scan_udec(s, &value, 128))) | 433 | if (!(off = scan_udec(s, &value, 128))) |
| 430 | return 0; | 434 | return 0; |
| 431 | net->bits = (int)value; | 435 | net->bits = (int)value; |
| 432 | if (ip6_isv4mapped(net->address)) | 436 | if (ip_is_v4mapped(net->address)) |
| 433 | net->bits += 96; | 437 | net->bits += 96; |
| 434 | if (net->bits > 128) | 438 | if (net->bits > 128) |
| 435 | return 0; | 439 | return 0; |
| @@ -757,7 +761,7 @@ int main(int argc, char **argv) { | |||
| 757 | scanon = 0; | 761 | scanon = 0; |
| 758 | break; | 762 | break; |
| 759 | case 'i': | 763 | case 'i': |
| 760 | if (!scan_ip6(optarg, serverip)) { | 764 | if (!ip_scan(optarg, serverip)) { |
| 761 | usage(argv[0]); | 765 | usage(argv[0]); |
| 762 | exit(1); | 766 | exit(1); |
| 763 | } | 767 | } |
diff --git a/ot_accesslist.c b/ot_accesslist.c index a199fa4..2465ada 100644 --- a/ot_accesslist.c +++ b/ot_accesslist.c | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | /* Libowfat */ | 24 | /* Libowfat */ |
| 25 | #include "ip6.h" | ||
| 26 | 25 | ||
| 27 | /* Opentracker */ | 26 | /* Opentracker */ |
| 28 | #include "ot_accesslist.h" | 27 | #include "ot_accesslist.h" |
| 29 | #include "ot_hex.h" | 28 | #include "ot_hex.h" |
| 29 | #include "ot_ip.h" | ||
| 30 | #include "ot_vector.h" | 30 | #include "ot_vector.h" |
| 31 | #include "trackerlogic.h" | 31 | #include "trackerlogic.h" |
| 32 | 32 | ||
| @@ -81,7 +81,7 @@ static ot_accesslist *accesslist_make(ot_accesslist *next, size_t size) { | |||
| 81 | if (accesslist_new) { | 81 | if (accesslist_new) { |
| 82 | accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL; | 82 | accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL; |
| 83 | accesslist_new->size = size; | 83 | accesslist_new->size = size; |
| 84 | accesslist_new->base = g_now_minutes; | 84 | accesslist_new->base = 0; |
| 85 | accesslist_new->next = next; | 85 | accesslist_new->next = next; |
| 86 | if (size && !accesslist_new->list) { | 86 | if (size && !accesslist_new->list) { |
| 87 | free(accesslist_new); | 87 | free(accesslist_new); |
| @@ -192,16 +192,24 @@ static void accesslist_readfile(void) { | |||
| 192 | 192 | ||
| 193 | /* Now exchange the accesslist vector in the least race condition prone way */ | 193 | /* Now exchange the accesslist vector in the least race condition prone way */ |
| 194 | pthread_mutex_lock(&g_accesslist_mutex); | 194 | pthread_mutex_lock(&g_accesslist_mutex); |
| 195 | |||
| 196 | /* Mark old accesslist as "needs to live another five minutes" */ | ||
| 197 | if (g_accesslist) | ||
| 198 | g_accesslist->base = g_now_minutes; | ||
| 195 | accesslist_new->next = g_accesslist; | 199 | accesslist_new->next = g_accesslist; |
| 196 | g_accesslist = accesslist_new; /* Only now set a new list */ | 200 | g_accesslist = accesslist_new; /* Only now set a new list */ |
| 197 | 201 | ||
| 198 | #ifdef WANT_DYNAMIC_ACCESSLIST | 202 | #ifdef WANT_DYNAMIC_ACCESSLIST |
| 199 | /* If we have dynamic accesslists, reloading a new one will always void the add/delete lists. | 203 | /* If we have dynamic accesslists, reloading a new one will always void the add/delete lists. |
| 200 | Insert empty ones at the list head */ | 204 | Insert empty ones at the list head */ |
| 201 | if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL) | 205 | if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL) { |
| 206 | g_accesslist_add->base = g_now_minutes; | ||
| 202 | g_accesslist_add = accesslist_new; | 207 | g_accesslist_add = accesslist_new; |
| 203 | if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL) | 208 | } |
| 209 | if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL) { | ||
| 210 | g_accesslist_delete->base = g_now_minutes; | ||
| 204 | g_accesslist_delete = accesslist_new; | 211 | g_accesslist_delete = accesslist_new; |
| 212 | } | ||
| 205 | #endif | 213 | #endif |
| 206 | 214 | ||
| 207 | accesslist_clean(g_accesslist); | 215 | accesslist_clean(g_accesslist); |
| @@ -209,7 +217,7 @@ static void accesslist_readfile(void) { | |||
| 209 | pthread_mutex_unlock(&g_accesslist_mutex); | 217 | pthread_mutex_unlock(&g_accesslist_mutex); |
| 210 | } | 218 | } |
| 211 | 219 | ||
| 212 | int accesslist_hashisvalid(ot_hash hash) { | 220 | int accesslist_hashisvalid(const ot_hash hash) { |
| 213 | /* Get working copy of current access list */ | 221 | /* Get working copy of current access list */ |
| 214 | ot_accesslist *accesslist = g_accesslist; | 222 | ot_accesslist *accesslist = g_accesslist; |
| 215 | #ifdef WANT_DYNAMIC_ACCESSLIST | 223 | #ifdef WANT_DYNAMIC_ACCESSLIST |
| @@ -315,7 +323,8 @@ static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic | |||
| 315 | ot_accesslist *accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1); | 323 | ot_accesslist *accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1); |
| 316 | if (accesslist_new) { | 324 | if (accesslist_new) { |
| 317 | memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off); | 325 | memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off); |
| 318 | memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1); | 326 | memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, sizeof(ot_hash) * ((*removing_from)->size - off - 1)); |
| 327 | (*removing_from)->base = g_now_minutes; | ||
| 319 | *removing_from = accesslist_new; | 328 | *removing_from = accesslist_new; |
| 320 | } | 329 | } |
| 321 | } | 330 | } |
| @@ -330,7 +339,7 @@ static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic | |||
| 330 | } | 339 | } |
| 331 | } else { | 340 | } else { |
| 332 | int exactmatch = 0; | 341 | int exactmatch = 0; |
| 333 | ot_hash *insert_point = binary_search(info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch); | 342 | ot_hash *insert_point = binary_search(info_hash, (*adding_to)->list, (*adding_to)->size, sizeof(ot_hash), OT_HASH_COMPARE_SIZE, &exactmatch); |
| 334 | 343 | ||
| 335 | /* Only if the info hash is not in the adding_to list, create a new head with that entry */ | 344 | /* Only if the info hash is not in the adding_to list, create a new head with that entry */ |
| 336 | if (!exactmatch) { | 345 | if (!exactmatch) { |
| @@ -339,7 +348,8 @@ static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic | |||
| 339 | if (accesslist_new) { | 348 | if (accesslist_new) { |
| 340 | memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off); | 349 | memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off); |
| 341 | memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash)); | 350 | memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash)); |
| 342 | memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, (*adding_to)->size - off); | 351 | memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, sizeof(ot_hash) * ((*adding_to)->size - off)); |
| 352 | (*adding_to)->base = g_now_minutes; | ||
| 343 | *adding_to = accesslist_new; | 353 | *adding_to = accesslist_new; |
| 344 | } | 354 | } |
| 345 | } | 355 | } |
| @@ -546,10 +556,10 @@ int accesslist_bless_net(ot_net *net, ot_permissions permissions) { | |||
| 546 | { | 556 | { |
| 547 | char _debug[512]; | 557 | char _debug[512]; |
| 548 | int off = snprintf(_debug, sizeof(_debug), "Blessing ip net "); | 558 | int off = snprintf(_debug, sizeof(_debug), "Blessing ip net "); |
| 549 | off += fmt_ip6c(_debug + off, net->address); | 559 | off += ip_format(_debug + off, net->address); |
| 550 | if (net->bits < 128) { | 560 | if (net->bits < 128) { |
| 551 | _debug[off++] = '/'; | 561 | _debug[off++] = '/'; |
| 552 | if (ip6_isv4mapped(net->address)) | 562 | if (ip_is_v4mapped(net->address)) |
| 553 | off += snprintf(_debug + off, sizeof(_debug) - off, "%d", net->bits - 96); | 563 | off += snprintf(_debug + off, sizeof(_debug) - off, "%d", net->bits - 96); |
| 554 | else | 564 | else |
| 555 | off += snprintf(_debug + off, sizeof(_debug) - off, "%d", net->bits); | 565 | off += snprintf(_debug + off, sizeof(_debug) - off, "%d", net->bits); |
diff --git a/ot_accesslist.h b/ot_accesslist.h index b3e979d..30aaebd 100644 --- a/ot_accesslist.h +++ b/ot_accesslist.h | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #define WANT_ACCESSLIST | 16 | #define WANT_ACCESSLIST |
| 17 | void accesslist_init(void); | 17 | void accesslist_init(void); |
| 18 | void accesslist_deinit(void); | 18 | void accesslist_deinit(void); |
| 19 | int accesslist_hashisvalid(ot_hash hash); | 19 | int accesslist_hashisvalid(const ot_hash hash); |
| 20 | void accesslist_cleanup(void); | 20 | void accesslist_cleanup(void); |
| 21 | 21 | ||
| 22 | /* Scan buf for up to capacity info_hashes in hexadecimal notation, one per | 22 | /* Scan buf for up to capacity info_hashes in hexadecimal notation, one per |
diff --git a/ot_buf.c b/ot_buf.c new file mode 100644 index 0000000..eb00edf --- /dev/null +++ b/ot_buf.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | /* System */ | ||
| 7 | #include <stdlib.h> | ||
| 8 | #include <string.h> | ||
| 9 | |||
| 10 | /* Opentracker */ | ||
| 11 | #include "ot_buf.h" | ||
| 12 | |||
| 13 | int buf_cat(ot_buf *buf, const void *src, size_t len) { | ||
| 14 | char *data; | ||
| 15 | |||
| 16 | if (!len) | ||
| 17 | return 0; | ||
| 18 | |||
| 19 | if (buf->size + len < buf->size) | ||
| 20 | return -1; | ||
| 21 | |||
| 22 | if (!(data = realloc(buf->data, buf->size + len))) | ||
| 23 | return -1; | ||
| 24 | |||
| 25 | buf->data = data; | ||
| 26 | memcpy(data + buf->size, src, len); | ||
| 27 | buf->size += len; | ||
| 28 | |||
| 29 | return 0; | ||
| 30 | } | ||
| 31 | |||
| 32 | void buf_truncate(ot_buf *buf, size_t len) { | ||
| 33 | if (len < buf->size) | ||
| 34 | buf->size = len; | ||
| 35 | } | ||
| 36 | |||
| 37 | void buf_reset(ot_buf *buf) { | ||
| 38 | free(buf->data); | ||
| 39 | buf->data = NULL; | ||
| 40 | buf->size = 0; | ||
| 41 | } | ||
diff --git a/ot_buf.h b/ot_buf.h new file mode 100644 index 0000000..219a069 --- /dev/null +++ b/ot_buf.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | #ifndef OT_BUF_H__ | ||
| 7 | #define OT_BUF_H__ | ||
| 8 | |||
| 9 | #include <stddef.h> | ||
| 10 | |||
| 11 | /* A growable byte buffer, holding an HTTP request that did not arrive in a | ||
| 12 | single packet. Requests that arrive whole are served straight from the | ||
| 13 | worker's input buffer and never come near this. */ | ||
| 14 | typedef struct { | ||
| 15 | char *data; | ||
| 16 | size_t size; | ||
| 17 | } ot_buf; | ||
| 18 | |||
| 19 | /* Append len bytes from src. Returns 0, or -1 if the memory could not be | ||
| 20 | had, in which case the buffer keeps whatever it already held. */ | ||
| 21 | int buf_cat(ot_buf *buf, const void *src, size_t len); | ||
| 22 | |||
| 23 | void buf_truncate(ot_buf *buf, size_t len); | ||
| 24 | |||
| 25 | void buf_reset(ot_buf *buf); | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/ot_fullscrape.c b/ot_fullscrape.c index 3d0e2f1..9dcbe68 100644 --- a/ot_fullscrape.c +++ b/ot_fullscrape.c | |||
| @@ -82,7 +82,7 @@ void fullscrape_deinit(void) { | |||
| 82 | pthread_cancel( thread_id ); | 82 | pthread_cancel( thread_id ); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void fullscrape_deliver( int64 sock, ot_tasktype tasktype ) { | 85 | void fullscrape_deliver( int64_t sock, ot_tasktype tasktype ) { |
| 86 | mutex_workqueue_pushtask( sock, tasktype ); | 86 | mutex_workqueue_pushtask( sock, tasktype ); |
| 87 | } | 87 | } |
| 88 | 88 | ||
diff --git a/ot_fullscrape.h b/ot_fullscrape.h index 843e039..0e7690c 100644 --- a/ot_fullscrape.h +++ b/ot_fullscrape.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | void fullscrape_init(void); | 13 | void fullscrape_init(void); |
| 14 | void fullscrape_deinit(void); | 14 | void fullscrape_deinit(void); |
| 15 | void fullscrape_deliver(int64 sock, ot_tasktype tasktype); | 15 | void fullscrape_deliver(int64_t sock, ot_tasktype tasktype); |
| 16 | 16 | ||
| 17 | #else | 17 | #else |
| 18 | 18 | ||
| @@ -10,16 +10,18 @@ | |||
| 10 | /* Opentracker */ | 10 | /* Opentracker */ |
| 11 | #include "ot_hex.h" | 11 | #include "ot_hex.h" |
| 12 | 12 | ||
| 13 | static int fromhex(unsigned char c) { | 13 | int hex_value(int c) { |
| 14 | if (c >= '0' && c <= '9') | 14 | unsigned char u = (unsigned char)c; |
| 15 | return c - '0'; | 15 | |
| 16 | c |= 0x20; /* fold upper case onto lower, digits are already handled */ | 16 | if (u >= '0' && u <= '9') |
| 17 | if (c >= 'a' && c <= 'f') | 17 | return u - '0'; |
| 18 | return c - 'a' + 10; | 18 | u |= 0x20; /* fold upper case onto lower, digits are already handled */ |
| 19 | if (u >= 'a' && u <= 'f') | ||
| 20 | return u - 'a' + 10; | ||
| 19 | return -1; | 21 | return -1; |
| 20 | } | 22 | } |
| 21 | 23 | ||
| 22 | int hex_isdigit(int c) { return fromhex((unsigned char)c) >= 0; } | 24 | int hex_isdigit(int c) { return hex_value(c) >= 0; } |
| 23 | 25 | ||
| 24 | char *hex_fromhash(char *dest, const uint8_t *hash) { | 26 | char *hex_fromhash(char *dest, const uint8_t *hash) { |
| 25 | static const char digits[] = "0123456789ABCDEF"; | 27 | static const char digits[] = "0123456789ABCDEF"; |
| @@ -43,9 +45,9 @@ int hex_tohash(ot_hash hash, const char *src) { | |||
| 43 | 45 | ||
| 44 | /* Tested one character at a time so that a string ending early stops us | 46 | /* Tested one character at a time so that a string ending early stops us |
| 45 | at its terminator rather than one byte past it */ | 47 | at its terminator rather than one byte past it */ |
| 46 | if ((high = fromhex((unsigned char)src[2 * i])) < 0) | 48 | if ((high = hex_value((unsigned char)src[2 * i])) < 0) |
| 47 | return 0; | 49 | return 0; |
| 48 | if ((low = fromhex((unsigned char)src[2 * i + 1])) < 0) | 50 | if ((low = hex_value((unsigned char)src[2 * i + 1])) < 0) |
| 49 | return 0; | 51 | return 0; |
| 50 | 52 | ||
| 51 | decoded[i] = (uint8_t)((high << 4) | low); | 53 | decoded[i] = (uint8_t)((high << 4) | low); |
| @@ -22,4 +22,8 @@ int hex_tohash(ot_hash hash, const char *src); | |||
| 22 | /* Non-zero if c is a hexadecimal digit, in either case. */ | 22 | /* Non-zero if c is a hexadecimal digit, in either case. */ |
| 23 | int hex_isdigit(int c); | 23 | int hex_isdigit(int c); |
| 24 | 24 | ||
| 25 | /* The value of a hexadecimal digit, or -1 if c is not one. Shared with the | ||
| 26 | address scanner so that both agree on what a digit is. */ | ||
| 27 | int hex_value(int c); | ||
| 28 | |||
| 25 | #endif | 29 | #endif |
| @@ -15,15 +15,14 @@ | |||
| 15 | #include <unistd.h> | 15 | #include <unistd.h> |
| 16 | 16 | ||
| 17 | /* Libowfat */ | 17 | /* Libowfat */ |
| 18 | #include "array.h" | ||
| 19 | #include "iob.h" | 18 | #include "iob.h" |
| 20 | #include "ip6.h" | ||
| 21 | 19 | ||
| 22 | /* Opentracker */ | 20 | /* Opentracker */ |
| 23 | #include "ot_accesslist.h" | 21 | #include "ot_accesslist.h" |
| 24 | #include "ot_fullscrape.h" | 22 | #include "ot_fullscrape.h" |
| 25 | #include "ot_http.h" | 23 | #include "ot_http.h" |
| 26 | #include "ot_iovec.h" | 24 | #include "ot_iovec.h" |
| 25 | #include "ot_ip.h" | ||
| 27 | #include "ot_mutex.h" | 26 | #include "ot_mutex.h" |
| 28 | #include "ot_scan.h" | 27 | #include "ot_scan.h" |
| 29 | #include "ot_stats.h" | 28 | #include "ot_stats.h" |
| @@ -45,7 +44,7 @@ ssize_t g_stats_path_len; | |||
| 45 | 44 | ||
| 46 | enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; | 45 | enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; |
| 47 | 46 | ||
| 48 | static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | 47 | static void http_senddata(const int64_t sock, struct ot_workstruct *ws) { |
| 49 | struct http_data *cookie = io_getcookie(sock); | 48 | struct http_data *cookie = io_getcookie(sock); |
| 50 | ssize_t written_size; | 49 | ssize_t written_size; |
| 51 | 50 | ||
| @@ -54,20 +53,25 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | |||
| 54 | return; | 53 | return; |
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | /* whoever sends data is not interested in its input-array */ | 56 | /* whoever sends data is not interested in its input buffer */ |
| 58 | if (ws->keep_alive && ws->header_size != ws->request_size) { | 57 | if (ws->keep_alive && ws->header_size != ws->request_size) { |
| 59 | size_t rest = ws->request_size - ws->header_size; | 58 | size_t rest = ws->request_size - ws->header_size; |
| 60 | if (array_start(&cookie->request)) { | 59 | if (cookie->request.data) { |
| 61 | memmove(array_start(&cookie->request), ws->request + ws->header_size, rest); | 60 | memmove(cookie->request.data, ws->request + ws->header_size, rest); |
| 62 | array_truncate(&cookie->request, 1, rest); | 61 | buf_truncate(&cookie->request, rest); |
| 63 | } else | 62 | } else if (buf_cat(&cookie->request, ws->request + ws->header_size, rest)) { |
| 64 | array_catb(&cookie->request, ws->request + ws->header_size, rest); | 63 | /* Without room for what the client pipelined behind this request, answer |
| 64 | this one and let the connection close, rather than keeping it open | ||
| 65 | around a request we have silently dropped */ | ||
| 66 | buf_reset(&cookie->request); | ||
| 67 | ws->keep_alive = 0; | ||
| 68 | } | ||
| 65 | } else | 69 | } else |
| 66 | array_reset(&cookie->request); | 70 | buf_reset(&cookie->request); |
| 67 | 71 | ||
| 68 | written_size = write(sock, ws->reply, ws->reply_size); | 72 | written_size = write(sock, ws->reply, ws->reply_size); |
| 69 | if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) { | 73 | if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) { |
| 70 | array_reset(&cookie->request); | 74 | buf_reset(&cookie->request); |
| 71 | free(cookie); | 75 | free(cookie); |
| 72 | io_close(sock); | 76 | io_close(sock); |
| 73 | return; | 77 | return; |
| @@ -78,7 +82,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | |||
| 78 | tai6464 t; | 82 | tai6464 t; |
| 79 | 83 | ||
| 80 | if (!(outbuf = malloc(ws->reply_size - written_size))) { | 84 | if (!(outbuf = malloc(ws->reply_size - written_size))) { |
| 81 | array_reset(&cookie->request); | 85 | buf_reset(&cookie->request); |
| 82 | free(cookie); | 86 | free(cookie); |
| 83 | io_close(sock); | 87 | io_close(sock); |
| 84 | return; | 88 | return; |
| @@ -90,7 +94,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | |||
| 90 | if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) { | 94 | if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) { |
| 91 | free(cookie->batch); | 95 | free(cookie->batch); |
| 92 | free(outbuf); | 96 | free(outbuf); |
| 93 | array_reset(&cookie->request); | 97 | buf_reset(&cookie->request); |
| 94 | free(cookie); | 98 | free(cookie); |
| 95 | io_close(sock); | 99 | io_close(sock); |
| 96 | return; | 100 | return; |
| @@ -120,7 +124,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | |||
| 120 | #define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) | 124 | #define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) |
| 121 | #define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) | 125 | #define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) |
| 122 | #define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) | 126 | #define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) |
| 123 | ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) { | 127 | ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) { |
| 124 | char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", | 128 | char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", |
| 125 | "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; | 129 | "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; |
| 126 | char *title = error_code[code]; | 130 | char *title = error_code[code]; |
| @@ -140,7 +144,7 @@ ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) { | |||
| 140 | return ws->reply_size = -2; | 144 | return ws->reply_size = -2; |
| 141 | } | 145 | } |
| 142 | 146 | ||
| 143 | ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) { | 147 | ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) { |
| 144 | struct http_data *cookie = io_getcookie(sock); | 148 | struct http_data *cookie = io_getcookie(sock); |
| 145 | io_batch *current; | 149 | io_batch *current; |
| 146 | char *header; | 150 | char *header; |
| @@ -154,8 +158,15 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t io | |||
| 154 | HTTPERROR_500; | 158 | HTTPERROR_500; |
| 155 | } | 159 | } |
| 156 | 160 | ||
| 161 | /* Descriptor numbers get recycled, so a result can only belong to this | ||
| 162 | connection if this connection is in fact waiting for one. */ | ||
| 163 | if (!(cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER))) { | ||
| 164 | iovec_free(&iovec_entries, &iovector); | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 157 | /* If this socket collected request in a buffer, free it now */ | 168 | /* If this socket collected request in a buffer, free it now */ |
| 158 | array_reset(&cookie->request); | 169 | buf_reset(&cookie->request); |
| 159 | 170 | ||
| 160 | /* If we came here, wait for the answer is over */ | 171 | /* If we came here, wait for the answer is over */ |
| 161 | if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { | 172 | if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { |
| @@ -232,7 +243,7 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t io | |||
| 232 | return 0; | 243 | return 0; |
| 233 | } | 244 | } |
| 234 | 245 | ||
| 235 | static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { | 246 | static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 236 | static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}}; | 247 | static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}}; |
| 237 | static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS}, | 248 | static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS}, |
| 238 | {"conn", TASK_STATS_CONNS}, | 249 | {"conn", TASK_STATS_CONNS}, |
| @@ -263,12 +274,16 @@ static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, cha | |||
| 263 | {"url", TASK_FULLSCRAPE_TPB_URLENCODED}, {"txt", TASK_FULLSCRAPE_TPB_ASCII}, | 274 | {"url", TASK_FULLSCRAPE_TPB_URLENCODED}, {"txt", TASK_FULLSCRAPE_TPB_ASCII}, |
| 264 | {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}}; | 275 | {"txtp", TASK_FULLSCRAPE_TPB_ASCII_PLUS}, {NULL, -3}}; |
| 265 | 276 | ||
| 266 | int mode = TASK_STATS_PEERS, scanon = 1, format = 0; | ||
| 267 | |||
| 268 | #ifdef WANT_RESTRICT_STATS | ||
| 269 | struct http_data *cookie = io_getcookie(sock); | 277 | struct http_data *cookie = io_getcookie(sock); |
| 278 | int mode = TASK_STATS_PEERS, scanon = 1, format = 0; | ||
| 279 | |||
| 280 | /* A socket without one is a dead socket, which is what http_sendiovecdata | ||
| 281 | already answers 500 to. */ | ||
| 282 | if (!cookie) | ||
| 283 | HTTPERROR_500; | ||
| 270 | 284 | ||
| 271 | if (!cookie || !accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_STAT)) | 285 | #ifdef WANT_RESTRICT_STATS |
| 286 | if (!accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_STAT)) | ||
| 272 | HTTPERROR_403_IP; | 287 | HTTPERROR_403_IP; |
| 273 | #endif | 288 | #endif |
| 274 | 289 | ||
| @@ -302,10 +317,9 @@ static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, cha | |||
| 302 | } | 317 | } |
| 303 | 318 | ||
| 304 | if (mode == TASK_STATS_TPB) { | 319 | if (mode == TASK_STATS_TPB) { |
| 305 | struct http_data *cookie = io_getcookie(sock); | 320 | tai6464 t; |
| 306 | tai6464 t; | ||
| 307 | #ifdef WANT_COMPRESSION_GZIP | 321 | #ifdef WANT_COMPRESSION_GZIP |
| 308 | ws->request[ws->request_size] = 0; | 322 | ws->request[ws->request_size - 1] = 0; |
| 309 | #ifndef WANT_COMPRESSION_GZIP_ALWAYS | 323 | #ifndef WANT_COMPRESSION_GZIP_ALWAYS |
| 310 | if (strstr(read_ptr - 1, "gzip")) { | 324 | if (strstr(read_ptr - 1, "gzip")) { |
| 311 | #endif | 325 | #endif |
| @@ -330,6 +344,9 @@ static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, cha | |||
| 330 | /* default format for now */ | 344 | /* default format for now */ |
| 331 | if ((mode & TASK_CLASS_MASK) == TASK_STATS) { | 345 | if ((mode & TASK_CLASS_MASK) == TASK_STATS) { |
| 332 | tai6464 t; | 346 | tai6464 t; |
| 347 | |||
| 348 | cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; | ||
| 349 | |||
| 333 | /* Complex stats also include expensive memory debugging tools */ | 350 | /* Complex stats also include expensive memory debugging tools */ |
| 334 | taia_uint(&t, 0); | 351 | taia_uint(&t, 0); |
| 335 | io_timeout(sock, t); | 352 | io_timeout(sock, t); |
| @@ -351,7 +368,7 @@ typedef struct { | |||
| 351 | #endif | 368 | #endif |
| 352 | 369 | ||
| 353 | #ifdef WANT_FULLSCRAPE | 370 | #ifdef WANT_FULLSCRAPE |
| 354 | static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws) { | 371 | static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *ws) { |
| 355 | struct http_data *cookie = io_getcookie(sock); | 372 | struct http_data *cookie = io_getcookie(sock); |
| 356 | int format = 0; | 373 | int format = 0; |
| 357 | tai6464 t; | 374 | tai6464 t; |
| @@ -421,7 +438,7 @@ static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws | |||
| 421 | } | 438 | } |
| 422 | #endif | 439 | #endif |
| 423 | 440 | ||
| 424 | static ssize_t http_handle_scrape(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { | 441 | static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 425 | static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; | 442 | static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; |
| 426 | 443 | ||
| 427 | ot_hash *multiscrape_buf = (ot_hash *)ws->request; | 444 | ot_hash *multiscrape_buf = (ot_hash *)ws->request; |
| @@ -500,7 +517,7 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event", | |||
| 500 | #endif | 517 | #endif |
| 501 | {"peer_id", 9}, {NULL, -3}}; | 518 | {"peer_id", 9}, {NULL, -3}}; |
| 502 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; | 519 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; |
| 503 | static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { | 520 | static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 504 | size_t numwant; | 521 | size_t numwant; |
| 505 | int tmp, scanon; | 522 | int tmp, scanon; |
| 506 | unsigned short port = 0; | 523 | unsigned short port = 0; |
| @@ -521,7 +538,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct * | |||
| 521 | if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) { | 538 | if (accesslist_is_blessed(cookie->ip, OT_PERMISSION_MAY_PROXY)) { |
| 522 | ot_ip6 proxied_ip; | 539 | ot_ip6 proxied_ip; |
| 523 | char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for"); | 540 | char *fwd = http_header(ws->request, ws->header_size, "x-forwarded-for"); |
| 524 | if (fwd && scan_ip6(fwd, proxied_ip)) { | 541 | if (fwd && ip_scan(fwd, proxied_ip)) { |
| 525 | OT_SETIP(ws->peer, proxied_ip); | 542 | OT_SETIP(ws->peer, proxied_ip); |
| 526 | } else | 543 | } else |
| 527 | OT_SETIP(ws->peer, cookie->ip); | 544 | OT_SETIP(ws->peer, cookie->ip); |
| @@ -607,7 +624,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct * | |||
| 607 | char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; | 624 | char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply + 16; |
| 608 | len = scan_urlencoded_query(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); | 625 | len = scan_urlencoded_query(&read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE); |
| 609 | tmp_buf2[len] = 0; | 626 | tmp_buf2[len] = 0; |
| 610 | if ((len <= 0) || !scan_ip6(tmp_buf2, tmp_buf1)) | 627 | if ((len <= 0) || !ip_scan(tmp_buf2, tmp_buf1)) |
| 611 | HTTPERROR_400_PARAM; | 628 | HTTPERROR_400_PARAM; |
| 612 | OT_SETIP(&ws->peer, tmp_buf1); | 629 | OT_SETIP(&ws->peer, tmp_buf1); |
| 613 | } break; | 630 | } break; |
| @@ -629,7 +646,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct * | |||
| 629 | loglist_reset(); | 646 | loglist_reset(); |
| 630 | return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n"); | 647 | return ws->reply_size = sprintf(ws->reply, "Successfully removed.\n"); |
| 631 | } | 648 | } |
| 632 | parsed = scan_ip6(tmp_buf, net.address); | 649 | parsed = ip_scan(tmp_buf, net.address); |
| 633 | if (!parsed) | 650 | if (!parsed) |
| 634 | HTTPERROR_400_PARAM; | 651 | HTTPERROR_400_PARAM; |
| 635 | if (tmp_buf[parsed++] != '/') | 652 | if (tmp_buf[parsed++] != '/') |
| @@ -639,7 +656,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct * | |||
| 639 | if (!parsed) | 656 | if (!parsed) |
| 640 | HTTPERROR_400_PARAM; | 657 | HTTPERROR_400_PARAM; |
| 641 | bits = (signed short)value; | 658 | bits = (signed short)value; |
| 642 | if (ip6_isv4mapped(net.address)) | 659 | if (ip_is_v4mapped(net.address)) |
| 643 | bits += 96; | 660 | bits += 96; |
| 644 | } | 661 | } |
| 645 | net.bits = bits; | 662 | net.bits = bits; |
| @@ -678,7 +695,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct * | |||
| 678 | return ws->reply_size; | 695 | return ws->reply_size; |
| 679 | } | 696 | } |
| 680 | 697 | ||
| 681 | ssize_t http_handle_request(const int64 sock, struct ot_workstruct *ws) { | 698 | ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) { |
| 682 | ssize_t reply_off, len; | 699 | ssize_t reply_off, len; |
| 683 | char *read_ptr = ws->request, *write_ptr; | 700 | char *read_ptr = ws->request, *write_ptr; |
| 684 | 701 | ||
| @@ -6,6 +6,8 @@ | |||
| 6 | #ifndef OT_HTTP_H__ | 6 | #ifndef OT_HTTP_H__ |
| 7 | #define OT_HTTP_H__ | 7 | #define OT_HTTP_H__ |
| 8 | 8 | ||
| 9 | #include "ot_buf.h" | ||
| 10 | |||
| 9 | typedef enum { | 11 | typedef enum { |
| 10 | STRUCT_HTTP_FLAG_WAITINGFORTASK = 1, | 12 | STRUCT_HTTP_FLAG_WAITINGFORTASK = 1, |
| 11 | STRUCT_HTTP_FLAG_GZIP = 2, | 13 | STRUCT_HTTP_FLAG_GZIP = 2, |
| @@ -16,16 +18,16 @@ typedef enum { | |||
| 16 | } STRUCT_HTTP_FLAG; | 18 | } STRUCT_HTTP_FLAG; |
| 17 | 19 | ||
| 18 | struct http_data { | 20 | struct http_data { |
| 19 | array request; | 21 | ot_buf request; |
| 20 | io_batch *batch; | 22 | io_batch *batch; |
| 21 | size_t batches; | 23 | size_t batches; |
| 22 | ot_ip6 ip; | 24 | ot_ip6 ip; |
| 23 | STRUCT_HTTP_FLAG flag; | 25 | STRUCT_HTTP_FLAG flag; |
| 24 | }; | 26 | }; |
| 25 | 27 | ||
| 26 | ssize_t http_handle_request(const int64 s, struct ot_workstruct *ws); | 28 | ssize_t http_handle_request(const int64_t s, struct ot_workstruct *ws); |
| 27 | ssize_t http_sendiovecdata(const int64 s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial); | 29 | ssize_t http_sendiovecdata(const int64_t s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial); |
| 28 | ssize_t http_issue_error(const int64 s, struct ot_workstruct *ws, int code); | 30 | ssize_t http_issue_error(const int64_t s, struct ot_workstruct *ws, int code); |
| 29 | 31 | ||
| 30 | extern char *g_stats_path; | 32 | extern char *g_stats_path; |
| 31 | extern ssize_t g_stats_path_len; | 33 | extern ssize_t g_stats_path_len; |
| @@ -0,0 +1,201 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | /* System */ | ||
| 7 | #include <stdint.h> | ||
| 8 | #include <string.h> | ||
| 9 | |||
| 10 | /* Opentracker */ | ||
| 11 | #include "ot_hex.h" | ||
| 12 | #include "ot_ip.h" | ||
| 13 | |||
| 14 | const char ip_v4mapped_prefix[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; | ||
| 15 | |||
| 16 | /* The dotted quad is only ever reached through the v4 mapped form, so both | ||
| 17 | halves of it stay in here */ | ||
| 18 | |||
| 19 | static size_t ip4_format(char *dest, const uint8_t *ip) { | ||
| 20 | char *d = dest; | ||
| 21 | int i; | ||
| 22 | |||
| 23 | for (i = 0; i < 4; ++i) { | ||
| 24 | unsigned int octet = ip[i]; | ||
| 25 | |||
| 26 | if (i) | ||
| 27 | *d++ = '.'; | ||
| 28 | if (octet >= 100) | ||
| 29 | *d++ = (char)('0' + octet / 100); | ||
| 30 | if (octet >= 10) | ||
| 31 | *d++ = (char)('0' + (octet / 10) % 10); | ||
| 32 | *d++ = (char)('0' + octet % 10); | ||
| 33 | } | ||
| 34 | |||
| 35 | return (size_t)(d - dest); | ||
| 36 | } | ||
| 37 | |||
| 38 | static size_t ip4_scan(const char *src, uint8_t ip[4]) { | ||
| 39 | uint8_t octets[4]; | ||
| 40 | const char *s = src; | ||
| 41 | int i; | ||
| 42 | |||
| 43 | for (i = 0; i < 4; ++i) { | ||
| 44 | unsigned int value = 0; | ||
| 45 | int digits = 0; | ||
| 46 | |||
| 47 | if (i && *s++ != '.') | ||
| 48 | return 0; | ||
| 49 | |||
| 50 | /* Leading zeros are tolerated, a value beyond one octet is not */ | ||
| 51 | while (*s >= '0' && *s <= '9' && digits < 4) { | ||
| 52 | value = value * 10 + (unsigned int)(*s++ - '0'); | ||
| 53 | ++digits; | ||
| 54 | } | ||
| 55 | if (!digits || value > 255) | ||
| 56 | return 0; | ||
| 57 | |||
| 58 | octets[i] = (uint8_t)value; | ||
| 59 | } | ||
| 60 | |||
| 61 | memcpy(ip, octets, sizeof(octets)); | ||
| 62 | return (size_t)(s - src); | ||
| 63 | } | ||
| 64 | |||
| 65 | static unsigned int group_at(const char *ip, int n) { return ((unsigned int)(uint8_t)ip[2 * n] << 8) | (uint8_t)ip[2 * n + 1]; } | ||
| 66 | |||
| 67 | size_t ip_format(char *dest, const ot_ip6 ip) { | ||
| 68 | static const char hexdigit[] = "0123456789abcdef"; | ||
| 69 | char *d = dest; | ||
| 70 | int best_start = 0, best_len = 0, i = 0; | ||
| 71 | |||
| 72 | if (ip_is_v4mapped(ip)) | ||
| 73 | return ip4_format(dest, (const uint8_t *)ip + sizeof(ip_v4mapped_prefix)); | ||
| 74 | |||
| 75 | /* RFC 5952 4.2: the longest run of zero groups becomes "::", never a run | ||
| 76 | of one, and the first of two equal runs wins */ | ||
| 77 | while (i < 8) { | ||
| 78 | int j = i; | ||
| 79 | |||
| 80 | if (group_at(ip, i)) { | ||
| 81 | ++i; | ||
| 82 | continue; | ||
| 83 | } | ||
| 84 | while (j < 8 && !group_at(ip, j)) | ||
| 85 | ++j; | ||
| 86 | if (j - i > best_len) { | ||
| 87 | best_len = j - i; | ||
| 88 | best_start = i; | ||
| 89 | } | ||
| 90 | i = j; | ||
| 91 | } | ||
| 92 | if (best_len < 2) | ||
| 93 | best_len = 0; | ||
| 94 | |||
| 95 | for (i = 0; i < 8; ++i) { | ||
| 96 | unsigned int group; | ||
| 97 | int shift = 12; | ||
| 98 | |||
| 99 | if (best_len && i == best_start) { | ||
| 100 | *d++ = ':'; | ||
| 101 | if (i + best_len == 8) | ||
| 102 | *d++ = ':'; /* nothing follows, so close the run */ | ||
| 103 | i += best_len - 1; | ||
| 104 | continue; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (i) | ||
| 108 | *d++ = ':'; | ||
| 109 | |||
| 110 | group = group_at(ip, i); | ||
| 111 | while (shift && !(group >> shift)) | ||
| 112 | shift -= 4; /* RFC 5952 4.1: no leading zeros */ | ||
| 113 | for (;; shift -= 4) { | ||
| 114 | *d++ = hexdigit[(group >> shift) & 15]; | ||
| 115 | if (!shift) | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | return (size_t)(d - dest); | ||
| 121 | } | ||
| 122 | |||
| 123 | size_t ip_scan(const char *src, ot_ip6 ip) { | ||
| 124 | uint8_t prefix[16], suffix[16]; | ||
| 125 | size_t prefixlen = 0, suffixlen = 0; | ||
| 126 | const char *s = src; | ||
| 127 | int have_gap = 0; | ||
| 128 | int need_colon = 0; | ||
| 129 | |||
| 130 | /* A plain IPv4 address is an address too, stored v4 mapped */ | ||
| 131 | { | ||
| 132 | size_t consumed = ip4_scan(src, prefix); | ||
| 133 | if (consumed) { | ||
| 134 | memcpy(ip, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); | ||
| 135 | memcpy(ip + sizeof(ip_v4mapped_prefix), prefix, 4); | ||
| 136 | return consumed; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | for (;;) { | ||
| 141 | unsigned int value = 0; | ||
| 142 | int digits = 0, nibble; | ||
| 143 | uint8_t *into = have_gap ? suffix : prefix; | ||
| 144 | size_t *fill = have_gap ? &suffixlen : &prefixlen; | ||
| 145 | |||
| 146 | /* RFC 4291 2.2: one run of zero groups may be written "::" */ | ||
| 147 | if (s[0] == ':' && s[1] == ':') { | ||
| 148 | if (have_gap) | ||
| 149 | return 0; | ||
| 150 | have_gap = 1; | ||
| 151 | need_colon = 0; | ||
| 152 | s += 2; | ||
| 153 | continue; | ||
| 154 | } | ||
| 155 | |||
| 156 | if (need_colon) { | ||
| 157 | if (*s != ':') | ||
| 158 | break; | ||
| 159 | ++s; | ||
| 160 | } | ||
| 161 | |||
| 162 | /* RFC 4291 2.2 form 3: the final two groups may be a dotted quad */ | ||
| 163 | if (prefixlen + suffixlen + 4 <= 16) { | ||
| 164 | size_t consumed = ip4_scan(s, into + *fill); | ||
| 165 | if (consumed) { | ||
| 166 | *fill += 4; | ||
| 167 | s += consumed; | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | while (digits < 4 && (nibble = hex_value(*s)) >= 0) { | ||
| 173 | value = value * 16 + (unsigned int)nibble; | ||
| 174 | ++digits; | ||
| 175 | ++s; | ||
| 176 | } | ||
| 177 | if (!digits) { | ||
| 178 | if (need_colon) | ||
| 179 | --s; /* leave the separator we ate for the caller */ | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (prefixlen + suffixlen + 2 > 16) | ||
| 184 | return 0; | ||
| 185 | |||
| 186 | into[(*fill)++] = (uint8_t)(value >> 8); | ||
| 187 | into[(*fill)++] = (uint8_t)value; | ||
| 188 | need_colon = 1; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (!prefixlen && !suffixlen && !have_gap) | ||
| 192 | return 0; | ||
| 193 | if (!have_gap && prefixlen + suffixlen != 16) | ||
| 194 | return 0; /* without "::" every group has to be spelled out */ | ||
| 195 | |||
| 196 | memset(ip, 0, 16); | ||
| 197 | memcpy(ip, prefix, prefixlen); | ||
| 198 | memcpy(ip + 16 - suffixlen, suffix, suffixlen); | ||
| 199 | |||
| 200 | return (size_t)(s - src); | ||
| 201 | } | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | #ifndef OT_IP_H__ | ||
| 7 | #define OT_IP_H__ | ||
| 8 | |||
| 9 | #include <stddef.h> | ||
| 10 | #include <string.h> | ||
| 11 | |||
| 12 | #include "trackerlogic.h" | ||
| 13 | |||
| 14 | /* opentracker holds every address as sixteen bytes, writing IPv4 as the v4 | ||
| 15 | mapped form of RFC 4291 section 2.5.5.2. */ | ||
| 16 | extern const char ip_v4mapped_prefix[12]; | ||
| 17 | |||
| 18 | static inline int ip_is_v4mapped(const void *ip) { return !memcmp(ip, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); } | ||
| 19 | |||
| 20 | /* Read an address and return how many characters it took, or zero if src | ||
| 21 | does not start with one. A plain IPv4 address is accepted and stored in | ||
| 22 | its v4 mapped form. | ||
| 23 | |||
| 24 | The count lets the caller carry on where the address ended, which is how | ||
| 25 | "address:port" and "address/bits" are read. */ | ||
| 26 | size_t ip_scan(const char *src, ot_ip6 ip); | ||
| 27 | |||
| 28 | /* Write an address and return how many characters it took. Nothing is | ||
| 29 | terminated, so a caller may keep appending. A v4 mapped address is written | ||
| 30 | as the plain dotted quad rather than "::ffff:1.2.3.4". */ | ||
| 31 | size_t ip_format(char *dest, const ot_ip6 ip); | ||
| 32 | |||
| 33 | #endif | ||
diff --git a/ot_livesync.c b/ot_livesync.c index c4dc6e5..8b2dee6 100644 --- a/ot_livesync.c +++ b/ot_livesync.c | |||
| @@ -13,11 +13,11 @@ | |||
| 13 | #include <unistd.h> | 13 | #include <unistd.h> |
| 14 | 14 | ||
| 15 | /* Libowfat */ | 15 | /* Libowfat */ |
| 16 | #include "ip6.h" | ||
| 17 | #include "socket.h" | 16 | #include "socket.h" |
| 18 | 17 | ||
| 19 | /* Opentracker */ | 18 | /* Opentracker */ |
| 20 | #include "ot_accesslist.h" | 19 | #include "ot_accesslist.h" |
| 20 | #include "ot_ip.h" | ||
| 21 | #include "ot_livesync.h" | 21 | #include "ot_livesync.h" |
| 22 | #include "ot_mutex.h" | 22 | #include "ot_mutex.h" |
| 23 | #include "ot_stats.h" | 23 | #include "ot_stats.h" |
| @@ -40,10 +40,10 @@ enum { OT_SYNC_PEER4, OT_SYNC_PEER6 }; | |||
| 40 | static void *livesync_worker(void *args); | 40 | static void *livesync_worker(void *args); |
| 41 | 41 | ||
| 42 | /* For outgoing packets */ | 42 | /* For outgoing packets */ |
| 43 | static int64 g_socket_in = -1; | 43 | static int64_t g_socket_in = -1; |
| 44 | 44 | ||
| 45 | /* For incoming packets */ | 45 | /* For incoming packets */ |
| 46 | static int64 g_socket_out = -1; | 46 | static int64_t g_socket_out = -1; |
| 47 | 47 | ||
| 48 | static pthread_mutex_t g_outbuf_mutex = PTHREAD_MUTEX_INITIALIZER; | 48 | static pthread_mutex_t g_outbuf_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 49 | typedef struct { | 49 | typedef struct { |
| @@ -92,7 +92,7 @@ void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { | |||
| 92 | char tmpip[4] = {0, 0, 0, 0}; | 92 | char tmpip[4] = {0, 0, 0, 0}; |
| 93 | char *v4ip; | 93 | char *v4ip; |
| 94 | 94 | ||
| 95 | if (!ip6_isv4mapped(ip)) | 95 | if (!ip_is_v4mapped(ip)) |
| 96 | exerr("v6 mcast support not yet available."); | 96 | exerr("v6 mcast support not yet available."); |
| 97 | v4ip = ip + 12; | 97 | v4ip = ip + 12; |
| 98 | 98 | ||
| @@ -140,14 +140,14 @@ static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) | |||
| 140 | 140 | ||
| 141 | /* Prepare peer record for v4mapped expansion */ | 141 | /* Prepare peer record for v4mapped expansion */ |
| 142 | if (peer_size == OT_PEER_SIZE4) | 142 | if (peer_size == OT_PEER_SIZE4) |
| 143 | memcpy(&ws->peer, V4mappedprefix, sizeof(V4mappedprefix)); | 143 | memcpy(&ws->peer, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); |
| 144 | 144 | ||
| 145 | /* Now basic sanity checks have been done on the live sync packet | 145 | /* Now basic sanity checks have been done on the live sync packet |
| 146 | We might add more testing and logging. */ | 146 | We might add more testing and logging. */ |
| 147 | while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= ws->request_size) { | 147 | while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= ws->request_size) { |
| 148 | char *peer_ip = ws->request + off + sizeof(ot_hash); | 148 | char *peer_ip = ws->request + off + sizeof(ot_hash); |
| 149 | if (peer_size == OT_PEER_SIZE4) | 149 | if (peer_size == OT_PEER_SIZE4) |
| 150 | memcpy(&ws->peer[0] + sizeof(V4mappedprefix), peer_ip, peer_size); | 150 | memcpy(&ws->peer[0] + sizeof(ip_v4mapped_prefix), peer_ip, peer_size); |
| 151 | else | 151 | else |
| 152 | memcpy(&ws->peer, peer_ip, peer_size); | 152 | memcpy(&ws->peer, peer_ip, peer_size); |
| 153 | ws->hash = (ot_hash *)(ws->request + off); | 153 | ws->hash = (ot_hash *)(ws->request + off); |
| @@ -215,7 +215,7 @@ static void *livesync_worker(void *args) { | |||
| 215 | ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE); | 215 | ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE); |
| 216 | ws.outbuf = ws.reply = 0; | 216 | ws.outbuf = ws.reply = 0; |
| 217 | 217 | ||
| 218 | memcpy(in_ip, V4mappedprefix, sizeof(V4mappedprefix)); | 218 | memcpy(in_ip, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); |
| 219 | 219 | ||
| 220 | while (1) { | 220 | while (1) { |
| 221 | uint32_t packet_type; | 221 | uint32_t packet_type; |
diff --git a/ot_livesync.h b/ot_livesync.h index ed710f0..6eca479 100644 --- a/ot_livesync.h +++ b/ot_livesync.h | |||
| @@ -62,7 +62,7 @@ void livesync_tell(struct ot_workstruct *ws); | |||
| 62 | void livesync_ticker(void); | 62 | void livesync_ticker(void); |
| 63 | 63 | ||
| 64 | /* Handle an incoming live sync packet */ | 64 | /* Handle an incoming live sync packet */ |
| 65 | void handle_livesync(const int64 sock); | 65 | void handle_livesync(const int64_t sock); |
| 66 | 66 | ||
| 67 | #else | 67 | #else |
| 68 | 68 | ||
| @@ -62,7 +62,7 @@ size_t mutex_get_torrent_count(void) { return g_torrent_count; } | |||
| 62 | struct ot_task { | 62 | struct ot_task { |
| 63 | ot_taskid taskid; | 63 | ot_taskid taskid; |
| 64 | ot_tasktype tasktype; | 64 | ot_tasktype tasktype; |
| 65 | int64 sock; | 65 | int64_t sock; |
| 66 | size_t iovec_entries; | 66 | size_t iovec_entries; |
| 67 | struct iovec *iovec; | 67 | struct iovec *iovec; |
| 68 | struct ot_task *next; | 68 | struct ot_task *next; |
| @@ -73,7 +73,7 @@ static struct ot_task *tasklist; | |||
| 73 | static pthread_mutex_t tasklist_mutex; | 73 | static pthread_mutex_t tasklist_mutex; |
| 74 | static pthread_cond_t tasklist_being_filled; | 74 | static pthread_cond_t tasklist_being_filled; |
| 75 | 75 | ||
| 76 | int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) { | 76 | int mutex_workqueue_pushtask(int64_t sock, ot_tasktype tasktype) { |
| 77 | struct ot_task **tmptask, *task; | 77 | struct ot_task **tmptask, *task; |
| 78 | 78 | ||
| 79 | task = malloc(sizeof(struct ot_task)); | 79 | task = malloc(sizeof(struct ot_task)); |
| @@ -102,7 +102,7 @@ int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) { | |||
| 102 | return 0; | 102 | return 0; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | void mutex_workqueue_canceltask(int64 sock) { | 105 | void mutex_workqueue_canceltask(int64_t sock) { |
| 106 | struct ot_task **task; | 106 | struct ot_task **task; |
| 107 | 107 | ||
| 108 | /* Want exclusive access to tasklist */ | 108 | /* Want exclusive access to tasklist */ |
| @@ -114,9 +114,10 @@ void mutex_workqueue_canceltask(int64 sock) { | |||
| 114 | struct ot_task *ptask = *task; | 114 | struct ot_task *ptask = *task; |
| 115 | size_t i; | 115 | size_t i; |
| 116 | 116 | ||
| 117 | /* Free task's iovec */ | 117 | /* Free task's iovec, the buffers it points at and the vector itself */ |
| 118 | for (i = 0; i < (*task)->iovec_entries; ++i) | 118 | for (i = 0; i < (*task)->iovec_entries; ++i) |
| 119 | free(iovec[i].iov_base); | 119 | free(iovec[i].iov_base); |
| 120 | free(iovec); | ||
| 120 | 121 | ||
| 121 | *task = (*task)->next; | 122 | *task = (*task)->next; |
| 122 | free(ptask); | 123 | free(ptask); |
| @@ -226,9 +227,9 @@ int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) { | |||
| 226 | return task ? 0 : -1; | 227 | return task ? 0 : -1; |
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | int64 mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovec, int *is_partial) { | 230 | int64_t mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovec, int *is_partial) { |
| 230 | struct ot_task **task; | 231 | struct ot_task **task; |
| 231 | int64 sock = -1; | 232 | int64_t sock = -1; |
| 232 | 233 | ||
| 233 | *is_partial = 0; | 234 | *is_partial = 0; |
| 234 | 235 | ||
| @@ -69,12 +69,12 @@ typedef enum { | |||
| 69 | 69 | ||
| 70 | typedef unsigned long ot_taskid; | 70 | typedef unsigned long ot_taskid; |
| 71 | 71 | ||
| 72 | int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype); | 72 | int mutex_workqueue_pushtask(int64_t sock, ot_tasktype tasktype); |
| 73 | void mutex_workqueue_canceltask(int64 sock); | 73 | void mutex_workqueue_canceltask(int64_t sock); |
| 74 | void mutex_workqueue_pushsuccess(ot_taskid taskid); | 74 | void mutex_workqueue_pushsuccess(ot_taskid taskid); |
| 75 | ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype); | 75 | ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype); |
| 76 | int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct iovec *iovector); | 76 | int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct iovec *iovector); |
| 77 | int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec); | 77 | int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec); |
| 78 | int64 mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovector, int *is_partial); | 78 | int64_t mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovector, int *is_partial); |
| 79 | 79 | ||
| 80 | #endif | 80 | #endif |
| @@ -18,13 +18,12 @@ | |||
| 18 | 18 | ||
| 19 | /* Libowfat */ | 19 | /* Libowfat */ |
| 20 | #include "io.h" | 20 | #include "io.h" |
| 21 | #include "ip4.h" | ||
| 22 | #include "ip6.h" | ||
| 23 | 21 | ||
| 24 | /* Opentracker */ | 22 | /* Opentracker */ |
| 25 | #include "ot_accesslist.h" | 23 | #include "ot_accesslist.h" |
| 26 | #include "ot_hex.h" | 24 | #include "ot_hex.h" |
| 27 | #include "ot_iovec.h" | 25 | #include "ot_iovec.h" |
| 26 | #include "ot_ip.h" | ||
| 28 | #include "ot_mutex.h" | 27 | #include "ot_mutex.h" |
| 29 | #include "ot_stats.h" | 28 | #include "ot_stats.h" |
| 30 | #include "trackerlogic.h" | 29 | #include "trackerlogic.h" |
| @@ -206,7 +205,7 @@ static size_t stats_return_busy_networks(char *reply, stats_network_node *tree, | |||
| 206 | if (scores[i - 1]) { | 205 | if (scores[i - 1]) { |
| 207 | r += sprintf(r, "%08zd: ", scores[i - 1]); | 206 | r += sprintf(r, "%08zd: ", scores[i - 1]); |
| 208 | // #ifdef WANT_V6 | 207 | // #ifdef WANT_V6 |
| 209 | r += fmt_ip6c(r, networks[i - 1]); | 208 | r += ip_format(r, networks[i - 1]); |
| 210 | #if 0 | 209 | #if 0 |
| 211 | // XXX | 210 | // XXX |
| 212 | r += fmt_ip4( r, networks[i - 1]); | 211 | r += fmt_ip4( r, networks[i - 1]); |
| @@ -470,7 +469,7 @@ static void stats_return_fulllog(size_t *iovec_entries, struct iovec **iovector, | |||
| 470 | re = r + 32 * OT_STATS_TMPSIZE; | 469 | re = r + 32 * OT_STATS_TMPSIZE; |
| 471 | } | 470 | } |
| 472 | r += sprintf(r, "%08ld: ", loglist->time); | 471 | r += sprintf(r, "%08ld: ", loglist->time); |
| 473 | r += fmt_ip6c(r, loglist->ip); | 472 | r += ip_format(r, loglist->ip); |
| 474 | *r++ = '\n'; | 473 | *r++ = '\n'; |
| 475 | memcpy(r, loglist->data, loglist->size); | 474 | memcpy(r, loglist->data, loglist->size); |
| 476 | r += loglist->size; | 475 | r += loglist->size; |
| @@ -663,7 +662,7 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_ | |||
| 663 | *peerid_hex = 0; | 662 | *peerid_hex = 0; |
| 664 | } | 663 | } |
| 665 | 664 | ||
| 666 | ip_readable[fmt_ip6c(ip_readable, (char *)&ws->peer)] = 0; | 665 | ip_readable[ip_format(ip_readable, (char *)&ws->peer)] = 0; |
| 667 | #if 0 | 666 | #if 0 |
| 668 | /* XXX */ | 667 | /* XXX */ |
| 669 | ip_readable[ fmt_ip4( ip_readable, (char*)&ws->peer ) ] = 0; | 668 | ip_readable[ fmt_ip4( ip_readable, (char*)&ws->peer ) ] = 0; |
| @@ -687,7 +686,7 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_ | |||
| 687 | ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ | 686 | ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ |
| 688 | char _debug[512]; | 687 | char _debug[512]; |
| 689 | int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time) / 60); | 688 | int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time) / 60); |
| 690 | off += fmt_ip6c(_debug + off, *ip); | 689 | off += ip_format(_debug + off, *ip); |
| 691 | off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); | 690 | off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); |
| 692 | (void)write(2, _debug, off); | 691 | (void)write(2, _debug, off); |
| 693 | ot_full_scrape_request_count++; | 692 | ot_full_scrape_request_count++; |
| @@ -696,7 +695,7 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_ | |||
| 696 | ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ | 695 | ot_ip6 *ip = (ot_ip6 *)event_data; /* ugly hack to transfer ip to stats */ |
| 697 | char _debug[512]; | 696 | char _debug[512]; |
| 698 | int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time) / 60); | 697 | int off = snprintf(_debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time) / 60); |
| 699 | off += fmt_ip6c(_debug + off, *ip); | 698 | off += ip_format(_debug + off, *ip); |
| 700 | off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); | 699 | off += snprintf(_debug + off, sizeof(_debug) - off, " - FULL SCRAPE\n"); |
| 701 | (void)write(2, _debug, off); | 700 | (void)write(2, _debug, off); |
| 702 | ot_full_scrape_request_count++; | 701 | ot_full_scrape_request_count++; |
| @@ -751,7 +750,7 @@ static void *stats_worker(void *args) { | |||
| 751 | return NULL; | 750 | return NULL; |
| 752 | } | 751 | } |
| 753 | 752 | ||
| 754 | void stats_deliver(int64 sock, int tasktype) { mutex_workqueue_pushtask(sock, tasktype); } | 753 | void stats_deliver(int64_t sock, int tasktype) { mutex_workqueue_pushtask(sock, tasktype); } |
| 755 | 754 | ||
| 756 | static pthread_t thread_id; | 755 | static pthread_t thread_id; |
| 757 | void stats_init(void) { | 756 | void stats_init(void) { |
| @@ -42,7 +42,7 @@ enum { | |||
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data); | 44 | void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data); |
| 45 | void stats_deliver(int64 sock, int tasktype); | 45 | void stats_deliver(int64_t sock, int tasktype); |
| 46 | void stats_cleanup(void); | 46 | void stats_cleanup(void); |
| 47 | size_t return_stats_for_tracker(char *reply, int mode, int format); | 47 | size_t return_stats_for_tracker(char *reply, int mode, int format); |
| 48 | size_t stats_return_tracker_version(char *reply); | 48 | size_t stats_return_tracker_version(char *reply); |
| @@ -163,7 +163,7 @@ void sync_deinit( ) { | |||
| 163 | pthread_cancel( thread_id ); | 163 | pthread_cancel( thread_id ); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | void sync_deliver( int64 socket ) { | 166 | void sync_deliver( int64_t socket ) { |
| 167 | mutex_workqueue_pushtask( socket, TASK_SYNC_OUT ); | 167 | mutex_workqueue_pushtask( socket, TASK_SYNC_OUT ); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| @@ -6,12 +6,14 @@ | |||
| 6 | #ifndef OT_SYNC_H__ | 6 | #ifndef OT_SYNC_H__ |
| 7 | #define OT_SYNC_H__ | 7 | #define OT_SYNC_H__ |
| 8 | 8 | ||
| 9 | #include <stdint.h> | ||
| 10 | |||
| 9 | #ifdef WANT_SYNC_BATCH | 11 | #ifdef WANT_SYNC_BATCH |
| 10 | enum { SYNC_IN, SYNC_OUT }; | 12 | enum { SYNC_IN, SYNC_OUT }; |
| 11 | 13 | ||
| 12 | void sync_init(); | 14 | void sync_init(); |
| 13 | void sync_deinit(); | 15 | void sync_deinit(); |
| 14 | void sync_deliver(int64 socket); | 16 | void sync_deliver(int64_t socket); |
| 15 | 17 | ||
| 16 | int add_changeset_to_tracker(uint8_t *data, size_t len); | 18 | int add_changeset_to_tracker(uint8_t *data, size_t len); |
| 17 | #else | 19 | #else |
| @@ -12,10 +12,10 @@ | |||
| 12 | 12 | ||
| 13 | /* Libowfat */ | 13 | /* Libowfat */ |
| 14 | #include "io.h" | 14 | #include "io.h" |
| 15 | #include "ip6.h" | ||
| 16 | #include "socket.h" | 15 | #include "socket.h" |
| 17 | 16 | ||
| 18 | /* Opentracker */ | 17 | /* Opentracker */ |
| 18 | #include "ot_ip.h" | ||
| 19 | #include "ot_random.h" | 19 | #include "ot_random.h" |
| 20 | #include "ot_rijndael.h" | 20 | #include "ot_rijndael.h" |
| 21 | #include "ot_stats.h" | 21 | #include "ot_stats.h" |
| @@ -71,7 +71,7 @@ static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int | |||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ | 73 | /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ |
| 74 | int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | 74 | int handle_udp6(int64_t serversocket, struct ot_workstruct *ws) { |
| 75 | ot_ip6 remoteip; | 75 | ot_ip6 remoteip; |
| 76 | uint32_t *inpacket = (uint32_t *)ws->inbuf; | 76 | uint32_t *inpacket = (uint32_t *)ws->inbuf; |
| 77 | uint32_t *outpacket = (uint32_t *)ws->outbuf; | 77 | uint32_t *outpacket = (uint32_t *)ws->outbuf; |
| @@ -176,7 +176,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 176 | } else { | 176 | } else { |
| 177 | /* Limit amount of peers to OT_MAX_PEERS_UDP */ | 177 | /* Limit amount of peers to OT_MAX_PEERS_UDP */ |
| 178 | uint32_t numwant = ntohl(inpacket[92 / 4]); | 178 | uint32_t numwant = ntohl(inpacket[92 / 4]); |
| 179 | size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6; | 179 | size_t max_peers = ip_is_v4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6; |
| 180 | if (numwant > max_peers) | 180 | if (numwant > max_peers) |
| 181 | numwant = max_peers; | 181 | numwant = max_peers; |
| 182 | 182 | ||
| @@ -203,7 +203,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static void *udp_worker(void *args) { | 205 | static void *udp_worker(void *args) { |
| 206 | int64 sock = (int64)args; | 206 | int64_t sock = (int64_t)args; |
| 207 | struct ot_workstruct ws; | 207 | struct ot_workstruct ws; |
| 208 | memset(&ws, 0, sizeof(ws)); | 208 | memset(&ws, 0, sizeof(ws)); |
| 209 | 209 | ||
| @@ -229,7 +229,7 @@ static void *udp_worker(void *args) { | |||
| 229 | return NULL; | 229 | return NULL; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | void udp_init(int64 sock, unsigned int worker_count) { | 232 | void udp_init(int64_t sock, unsigned int worker_count) { |
| 233 | pthread_t thread_id; | 233 | pthread_t thread_id; |
| 234 | if (!g_rijndael_round_key[0]) | 234 | if (!g_rijndael_round_key[0]) |
| 235 | udp_generate_rijndael_round_key(); | 235 | udp_generate_rijndael_round_key(); |
| @@ -6,8 +6,10 @@ | |||
| 6 | #ifndef OT_UDP_H__ | 6 | #ifndef OT_UDP_H__ |
| 7 | #define OT_UDP_H__ | 7 | #define OT_UDP_H__ |
| 8 | 8 | ||
| 9 | void udp_init(int64 sock, unsigned int worker_count); | 9 | #include <stdint.h> |
| 10 | |||
| 11 | void udp_init(int64_t sock, unsigned int worker_count); | ||
| 10 | void udp_kickoff(void); | 12 | void udp_kickoff(void); |
| 11 | int handle_udp6(int64 serversocket, struct ot_workstruct *ws); | 13 | int handle_udp6(int64_t serversocket, struct ot_workstruct *ws); |
| 12 | 14 | ||
| 13 | #endif | 15 | #endif |
diff --git a/ot_vector.c b/ot_vector.c index e3c3d3f..c4cd171 100644 --- a/ot_vector.c +++ b/ot_vector.c | |||
| @@ -156,8 +156,6 @@ void vector_remove_torrent(ot_vector *vector, ot_torrent *match) { | |||
| 156 | if (!vector->size) | 156 | if (!vector->size) |
| 157 | return; | 157 | return; |
| 158 | 158 | ||
| 159 | /* If this is being called after a unsuccessful malloc() for peer_list | ||
| 160 | in add_peer_to_torrent, match->peer_list actually might be NULL */ | ||
| 161 | free_peerlist(match->peer_list6); | 159 | free_peerlist(match->peer_list6); |
| 162 | free_peerlist(match->peer_list4); | 160 | free_peerlist(match->peer_list4); |
| 163 | 161 | ||
| @@ -19,13 +19,13 @@ | |||
| 19 | /* Libowfat */ | 19 | /* Libowfat */ |
| 20 | #include "io.h" | 20 | #include "io.h" |
| 21 | #include "iob.h" | 21 | #include "iob.h" |
| 22 | #include "ip6.h" | ||
| 23 | #include "socket.h" | 22 | #include "socket.h" |
| 24 | 23 | ||
| 25 | /* Opentracker */ | 24 | /* Opentracker */ |
| 25 | #include "ot_ip.h" | ||
| 26 | #include "ot_mutex.h" | 26 | #include "ot_mutex.h" |
| 27 | #include "ot_scan.h" | ||
| 28 | #include "ot_random.h" | 27 | #include "ot_random.h" |
| 28 | #include "ot_scan.h" | ||
| 29 | #include "ot_stats.h" | 29 | #include "ot_stats.h" |
| 30 | #include "ot_vector.h" | 30 | #include "ot_vector.h" |
| 31 | #include "trackerlogic.h" | 31 | #include "trackerlogic.h" |
| @@ -63,11 +63,11 @@ enum { OT_SYNC_PEER4, OT_SYNC_PEER6 }; | |||
| 63 | enum { FLAG_SERVERSOCKET = 1 }; | 63 | enum { FLAG_SERVERSOCKET = 1 }; |
| 64 | 64 | ||
| 65 | /* For incoming packets */ | 65 | /* For incoming packets */ |
| 66 | static int64 g_socket_in = -1; | 66 | static int64_t g_socket_in = -1; |
| 67 | static uint8_t g_inbuffer[LIVESYNC_INCOMING_BUFFSIZE]; | 67 | static uint8_t g_inbuffer[LIVESYNC_INCOMING_BUFFSIZE]; |
| 68 | 68 | ||
| 69 | /* For outgoing packets */ | 69 | /* For outgoing packets */ |
| 70 | static int64 g_socket_out = -1; | 70 | static int64_t g_socket_out = -1; |
| 71 | static uint8_t g_peerbuffer_start[LIVESYNC_OUTGOING_BUFFSIZE_PEERS]; | 71 | static uint8_t g_peerbuffer_start[LIVESYNC_OUTGOING_BUFFSIZE_PEERS]; |
| 72 | static uint8_t *g_peerbuffer_pos; | 72 | static uint8_t *g_peerbuffer_pos; |
| 73 | static uint8_t *g_peerbuffer_highwater = g_peerbuffer_start + LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS; | 73 | static uint8_t *g_peerbuffer_highwater = g_peerbuffer_start + LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS; |
| @@ -92,7 +92,7 @@ void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { | |||
| 92 | char tmpip[4] = {0, 0, 0, 0}; | 92 | char tmpip[4] = {0, 0, 0, 0}; |
| 93 | char *v4ip; | 93 | char *v4ip; |
| 94 | 94 | ||
| 95 | if (!ip6_isv4mapped(ip)) | 95 | if (!ip_is_v4mapped(ip)) |
| 96 | exerr("v6 mcast support not yet available."); | 96 | exerr("v6 mcast support not yet available."); |
| 97 | v4ip = ip + 12; | 97 | v4ip = ip + 12; |
| 98 | 98 | ||
| @@ -249,7 +249,7 @@ typedef struct { | |||
| 249 | uint8_t indata[8192 * 16]; /* Any data not processed yet */ | 249 | uint8_t indata[8192 * 16]; /* Any data not processed yet */ |
| 250 | size_t indata_length; /* Length of unprocessed data */ | 250 | size_t indata_length; /* Length of unprocessed data */ |
| 251 | uint32_t tracker_id; /* How the other end greeted */ | 251 | uint32_t tracker_id; /* How the other end greeted */ |
| 252 | int64 fd; /* A file handle, if connected, <= 0 is disconnected (0 initially, -1 else) */ | 252 | int64_t fd; /* A file handle, if connected, <= 0 is disconnected (0 initially, -1 else) */ |
| 253 | io_batch outdata; /* The iobatch containing our sync data */ | 253 | io_batch outdata; /* The iobatch containing our sync data */ |
| 254 | 254 | ||
| 255 | size_t packet_tcount; /* Number of unprocessed torrents in packet we currently receive */ | 255 | size_t packet_tcount; /* Number of unprocessed torrents in packet we currently receive */ |
| @@ -283,7 +283,7 @@ static void handle_reconnects(void) { | |||
| 283 | size_t i; | 283 | size_t i; |
| 284 | for (i = 0; i < g_connection_count; ++i) | 284 | for (i = 0; i < g_connection_count; ++i) |
| 285 | if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) { | 285 | if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) { |
| 286 | int64 newfd = socket_tcp6(); | 286 | int64_t newfd = socket_tcp6(); |
| 287 | fprintf(stderr, "(Re)connecting to peer..."); | 287 | fprintf(stderr, "(Re)connecting to peer..."); |
| 288 | if (newfd < 0) | 288 | if (newfd < 0) |
| 289 | continue; /* No socket for you */ | 289 | continue; /* No socket for you */ |
| @@ -308,10 +308,10 @@ static void handle_reconnects(void) { | |||
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | /* Handle incoming connection requests, check against whitelist */ | 310 | /* Handle incoming connection requests, check against whitelist */ |
| 311 | static void handle_accept(int64 serversocket) { | 311 | static void handle_accept(int64_t serversocket) { |
| 312 | int64 newfd; | 312 | int64_t newfd; |
| 313 | ot_ip6 ip; | 313 | ot_ip6 ip; |
| 314 | uint16 port; | 314 | uint16 port; |
| 315 | 315 | ||
| 316 | while ((newfd = socket_accept6(serversocket, ip, &port, NULL)) != -1) { | 316 | while ((newfd = socket_accept6(serversocket, ip, &port, NULL)) != -1) { |
| 317 | 317 | ||
| @@ -351,9 +351,9 @@ static void handle_accept(int64 serversocket) { | |||
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | /* New sync data on the stream */ | 353 | /* New sync data on the stream */ |
| 354 | static void handle_read(int64 peersocket) { | 354 | static void handle_read(int64_t peersocket) { |
| 355 | int i; | 355 | int i; |
| 356 | int64 datalen; | 356 | int64_t datalen; |
| 357 | uint32_t tracker_id; | 357 | uint32_t tracker_id; |
| 358 | proxy_peer *peer = io_getcookie(peersocket); | 358 | proxy_peer *peer = io_getcookie(peersocket); |
| 359 | 359 | ||
| @@ -420,7 +420,7 @@ static void handle_read(int64 peersocket) { | |||
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | /* Can write new sync data to the stream */ | 422 | /* Can write new sync data to the stream */ |
| 423 | static void handle_write(int64 peersocket) { | 423 | static void handle_write(int64_t peersocket) { |
| 424 | proxy_peer *peer = io_getcookie(peersocket); | 424 | proxy_peer *peer = io_getcookie(peersocket); |
| 425 | 425 | ||
| 426 | if (!peer) { | 426 | if (!peer) { |
| @@ -472,7 +472,7 @@ static void handle_write(int64 peersocket) { | |||
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | static void server_mainloop() { | 474 | static void server_mainloop() { |
| 475 | int64 sock; | 475 | int64_t sock; |
| 476 | uint32_t packet_type; | 476 | uint32_t packet_type; |
| 477 | 477 | ||
| 478 | /* inlined livesync_init() */ | 478 | /* inlined livesync_init() */ |
| @@ -515,7 +515,7 @@ static void panic(const char *routine) { | |||
| 515 | } | 515 | } |
| 516 | 516 | ||
| 517 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port) { | 517 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port) { |
| 518 | int64 sock = socket_tcp6(); | 518 | int64_t sock = socket_tcp6(); |
| 519 | 519 | ||
| 520 | if (socket_bind6_reuse(sock, ip, port, 0) == -1) | 520 | if (socket_bind6_reuse(sock, ip, port, 0) == -1) |
| 521 | panic("socket_bind6_reuse"); | 521 | panic("socket_bind6_reuse"); |
| @@ -539,14 +539,14 @@ static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { | |||
| 539 | ++s; | 539 | ++s; |
| 540 | if (*s == '[') | 540 | if (*s == '[') |
| 541 | ++s, ++bracket; /* for v6 style notation */ | 541 | ++s, ++bracket; /* for v6 style notation */ |
| 542 | if (!(off = scan_ip6(s, ip))) | 542 | if (!(off = ip_scan(s, ip))) |
| 543 | return 0; | 543 | return 0; |
| 544 | s += off; | 544 | s += off; |
| 545 | if (*s == 0 || isspace(*s)) | 545 | if (*s == 0 || isspace(*s)) |
| 546 | return s - src; | 546 | return s - src; |
| 547 | if (*s == ']' && bracket) | 547 | if (*s == ']' && bracket) |
| 548 | ++s; | 548 | ++s; |
| 549 | if (!ip6_isv4mapped(ip)) { | 549 | if (!ip_is_v4mapped(ip)) { |
| 550 | if ((bracket && *(s) != ':') || (*(s) != '.')) | 550 | if ((bracket && *(s) != ':') || (*(s) != '.')) |
| 551 | return 0; | 551 | return 0; |
| 552 | s++; | 552 | s++; |
diff --git a/tests/runner.c b/tests/runner.c index 370b92b..10b6625 100644 --- a/tests/runner.c +++ b/tests/runner.c | |||
| @@ -20,6 +20,8 @@ static const struct module modules[] = {{"scan_urlencoded_query", test_scan_urle | |||
| 20 | {"ot_random", test_random}, | 20 | {"ot_random", test_random}, |
| 21 | {"ot_hex", test_hex}, | 21 | {"ot_hex", test_hex}, |
| 22 | {"ot_scan", test_scan}, | 22 | {"ot_scan", test_scan}, |
| 23 | {"ot_buf", test_buf}, | ||
| 24 | {"ot_ip", test_ip}, | ||
| 23 | {"ot_accesslist", test_accesslist}, | 25 | {"ot_accesslist", test_accesslist}, |
| 24 | {NULL, NULL}}; | 26 | {NULL, NULL}}; |
| 25 | 27 | ||
diff --git a/tests/t_buf.c b/tests/t_buf.c new file mode 100644 index 0000000..dcfb0bb --- /dev/null +++ b/tests/t_buf.c | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | /* System */ | ||
| 7 | #include <stdint.h> | ||
| 8 | #include <string.h> | ||
| 9 | |||
| 10 | /* Opentracker */ | ||
| 11 | #include "ot_buf.h" | ||
| 12 | #include "test.h" | ||
| 13 | |||
| 14 | static void case_starts_empty(void) { | ||
| 15 | ot_buf buf = {NULL, 0}; | ||
| 16 | |||
| 17 | test_case("a fresh buffer holds nothing and has no data pointer"); | ||
| 18 | CHECK_PTR(buf.data, NULL); | ||
| 19 | CHECK_INT(buf.size, 0); | ||
| 20 | } | ||
| 21 | |||
| 22 | static void case_cat_appends(void) { | ||
| 23 | ot_buf buf = {NULL, 0}; | ||
| 24 | |||
| 25 | test_case("appends concatenate in order and report success"); | ||
| 26 | CHECK_INT(buf_cat(&buf, "GET /ann", 8), 0); | ||
| 27 | CHECK(buf.data != NULL); | ||
| 28 | CHECK_INT(buf.size, 8); | ||
| 29 | CHECK_INT(buf_cat(&buf, "ounce", 5), 0); | ||
| 30 | CHECK_INT(buf.size, 13); | ||
| 31 | CHECK_MEM(buf.data, "GET /announce", 13); | ||
| 32 | buf_reset(&buf); | ||
| 33 | } | ||
| 34 | |||
| 35 | static void case_cat_of_nothing_allocates_nothing(void) { | ||
| 36 | ot_buf buf = {NULL, 0}; | ||
| 37 | |||
| 38 | /* handle_read tells an untouched buffer from a partial request by the data | ||
| 39 | pointer, so a zero length append must not quietly allocate one */ | ||
| 40 | test_case("appending zero bytes leaves the buffer untouched"); | ||
| 41 | CHECK_INT(buf_cat(&buf, "ignored", 0), 0); | ||
| 42 | CHECK_PTR(buf.data, NULL); | ||
| 43 | CHECK_INT(buf.size, 0); | ||
| 44 | buf_reset(&buf); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void case_grows_across_many_appends(void) { | ||
| 48 | ot_buf buf = {NULL, 0}; | ||
| 49 | char chunk[100]; | ||
| 50 | size_t i; | ||
| 51 | |||
| 52 | test_case("content survives growing one packet at a time"); | ||
| 53 | memset(chunk, 'x', sizeof(chunk)); | ||
| 54 | for (i = 0; i < 100; ++i) | ||
| 55 | if (buf_cat(&buf, chunk, sizeof(chunk))) { | ||
| 56 | test_failf(__FILE__, __LINE__, "append %zu was refused", i); | ||
| 57 | buf_reset(&buf); | ||
| 58 | return; | ||
| 59 | } | ||
| 60 | ++test_checks; | ||
| 61 | CHECK_INT(buf.size, 10000); | ||
| 62 | for (i = 0; i < 10000; ++i) | ||
| 63 | if (buf.data[i] != 'x') { | ||
| 64 | test_failf(__FILE__, __LINE__, "byte %zu was not preserved across growth", i); | ||
| 65 | buf_reset(&buf); | ||
| 66 | return; | ||
| 67 | } | ||
| 68 | ++test_checks; | ||
| 69 | buf_reset(&buf); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void case_grows_one_byte_at_a_time(void) { | ||
| 73 | ot_buf buf = {NULL, 0}; | ||
| 74 | size_t i; | ||
| 75 | |||
| 76 | /* The shape a trickling client produces. Nothing here is optimised for it, | ||
| 77 | so the point is only that it stays correct. */ | ||
| 78 | test_case("a byte at a time accumulates correctly"); | ||
| 79 | for (i = 0; i < 2048; ++i) { | ||
| 80 | char c = (char)('a' + (i % 26)); | ||
| 81 | if (buf_cat(&buf, &c, 1)) { | ||
| 82 | test_failf(__FILE__, __LINE__, "append %zu was refused", i); | ||
| 83 | buf_reset(&buf); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | ++test_checks; | ||
| 88 | CHECK_INT(buf.size, 2048); | ||
| 89 | for (i = 0; i < 2048; ++i) | ||
| 90 | if (buf.data[i] != (char)('a' + (i % 26))) { | ||
| 91 | test_failf(__FILE__, __LINE__, "byte %zu differs", i); | ||
| 92 | buf_reset(&buf); | ||
| 93 | return; | ||
| 94 | } | ||
| 95 | ++test_checks; | ||
| 96 | buf_reset(&buf); | ||
| 97 | } | ||
| 98 | |||
| 99 | static void case_truncate_shrinks_only(void) { | ||
| 100 | ot_buf buf = {NULL, 0}; | ||
| 101 | |||
| 102 | test_case("truncate drops the tail but never grows"); | ||
| 103 | buf_cat(&buf, "0123456789", 10); | ||
| 104 | buf_truncate(&buf, 4); | ||
| 105 | CHECK_INT(buf.size, 4); | ||
| 106 | CHECK_MEM(buf.data, "0123", 4); | ||
| 107 | |||
| 108 | buf_truncate(&buf, 9); | ||
| 109 | CHECK_INT(buf.size, 4); | ||
| 110 | buf_truncate(&buf, 4); | ||
| 111 | CHECK_INT(buf.size, 4); | ||
| 112 | |||
| 113 | buf_truncate(&buf, 0); | ||
| 114 | CHECK_INT(buf.size, 0); | ||
| 115 | buf_reset(&buf); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void case_append_after_truncate(void) { | ||
| 119 | ot_buf buf = {NULL, 0}; | ||
| 120 | |||
| 121 | test_case("appending after a truncate overwrites the dropped tail"); | ||
| 122 | buf_cat(&buf, "keepdrop", 8); | ||
| 123 | buf_truncate(&buf, 4); | ||
| 124 | CHECK_INT(buf_cat(&buf, "MORE", 4), 0); | ||
| 125 | CHECK_INT(buf.size, 8); | ||
| 126 | CHECK_MEM(buf.data, "keepMORE", 8); | ||
| 127 | buf_reset(&buf); | ||
| 128 | } | ||
| 129 | |||
| 130 | static void case_reset_clears_everything(void) { | ||
| 131 | ot_buf buf = {NULL, 0}; | ||
| 132 | |||
| 133 | test_case("reset releases the buffer and restores the initial state"); | ||
| 134 | buf_cat(&buf, "something", 9); | ||
| 135 | buf_reset(&buf); | ||
| 136 | CHECK_PTR(buf.data, NULL); | ||
| 137 | CHECK_INT(buf.size, 0); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void case_reset_of_empty_is_safe(void) { | ||
| 141 | ot_buf buf = {NULL, 0}; | ||
| 142 | |||
| 143 | test_case("resetting a buffer that was never used is harmless"); | ||
| 144 | buf_reset(&buf); | ||
| 145 | buf_reset(&buf); | ||
| 146 | CHECK_PTR(buf.data, NULL); | ||
| 147 | CHECK_INT(buf.size, 0); | ||
| 148 | } | ||
| 149 | |||
| 150 | static void case_refused_append_is_harmless(void) { | ||
| 151 | ot_buf buf = {NULL, 0}; | ||
| 152 | |||
| 153 | /* A length that would wrap the size is rejected before src is read and | ||
| 154 | before anything is allocated, so a short string is safe to pass here. | ||
| 155 | A refused append must not destroy the partial request already collected: | ||
| 156 | the caller answers and closes rather than losing both. */ | ||
| 157 | test_case("a length that would wrap the size is refused"); | ||
| 158 | CHECK_INT(buf_cat(&buf, "already here", 12), 0); | ||
| 159 | CHECK_INT(buf_cat(&buf, "x", (size_t)-1), -1); | ||
| 160 | |||
| 161 | test_case("and earlier content survives it"); | ||
| 162 | CHECK_INT(buf.size, 12); | ||
| 163 | CHECK_MEM(buf.data, "already here", 12); | ||
| 164 | |||
| 165 | test_case("and the buffer still works afterwards"); | ||
| 166 | CHECK_INT(buf_cat(&buf, "!", 1), 0); | ||
| 167 | CHECK_INT(buf.size, 13); | ||
| 168 | CHECK_MEM(buf.data, "already here!", 13); | ||
| 169 | buf_reset(&buf); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void case_accumulates_a_split_request(void) { | ||
| 173 | /* What handle_read actually does: collect a request that arrived in | ||
| 174 | pieces, then hand over the whole of it */ | ||
| 175 | ot_buf buf = {NULL, 0}; | ||
| 176 | const char *pieces[] = {"GET /announce?info_hash=", "0123456789abcdefghij", " HTTP/1.0\r\n\r\n"}; | ||
| 177 | size_t i; | ||
| 178 | |||
| 179 | test_case("a request split over several reads is reassembled"); | ||
| 180 | for (i = 0; i < 3; ++i) | ||
| 181 | if (buf_cat(&buf, pieces[i], strlen(pieces[i]))) { | ||
| 182 | test_failf(__FILE__, __LINE__, "piece %zu was refused", i); | ||
| 183 | buf_reset(&buf); | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | ++test_checks; | ||
| 187 | |||
| 188 | CHECK_INT(buf.size, 24 + 20 + 13); | ||
| 189 | CHECK_MEM(buf.data, "GET /announce?info_hash=0123456789abcdefghij HTTP/1.0\r\n\r\n", 57); | ||
| 190 | buf_reset(&buf); | ||
| 191 | } | ||
| 192 | |||
| 193 | void test_buf(void) { | ||
| 194 | case_starts_empty(); | ||
| 195 | case_cat_appends(); | ||
| 196 | case_cat_of_nothing_allocates_nothing(); | ||
| 197 | case_grows_across_many_appends(); | ||
| 198 | case_grows_one_byte_at_a_time(); | ||
| 199 | case_truncate_shrinks_only(); | ||
| 200 | case_append_after_truncate(); | ||
| 201 | case_reset_clears_everything(); | ||
| 202 | case_reset_of_empty_is_safe(); | ||
| 203 | case_refused_append_is_harmless(); | ||
| 204 | case_accumulates_a_split_request(); | ||
| 205 | } | ||
diff --git a/tests/t_ip.c b/tests/t_ip.c new file mode 100644 index 0000000..2fe3a72 --- /dev/null +++ b/tests/t_ip.c | |||
| @@ -0,0 +1,217 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | /* System */ | ||
| 7 | #include <stdint.h> | ||
| 8 | #include <string.h> | ||
| 9 | |||
| 10 | /* Opentracker */ | ||
| 11 | #include "ot_ip.h" | ||
| 12 | #include "test.h" | ||
| 13 | |||
| 14 | static char text[64]; | ||
| 15 | |||
| 16 | static const char *formatted(const char *ip) { | ||
| 17 | text[ip_format(text, ip)] = 0; | ||
| 18 | return text; | ||
| 19 | } | ||
| 20 | |||
| 21 | /* ------------------------------------------------------------------ IPv4 */ | ||
| 22 | |||
| 23 | /* ------------------------------------------------------- RFC 5952 output */ | ||
| 24 | |||
| 25 | static void case_format_rfc5952(void) { | ||
| 26 | test_case("4.1 leading zeros in a group are suppressed"); | ||
| 27 | CHECK_STR(formatted("\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), "2001:db8::1"); | ||
| 28 | |||
| 29 | test_case("4.2.1 the longest run of zero groups becomes ::"); | ||
| 30 | CHECK_STR(formatted("\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01"), "2001:db8::2:1"); | ||
| 31 | |||
| 32 | test_case("4.2.2 a single zero group is never shortened"); | ||
| 33 | CHECK_STR(formatted("\x20\x01\x0d\xb8\x00\x00\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01"), "2001:db8:0:1:1:1:1:1"); | ||
| 34 | |||
| 35 | test_case("4.2.1 a longer run wins over an earlier shorter one"); | ||
| 36 | CHECK_STR(formatted("\x20\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01"), "2001:0:0:1::1"); | ||
| 37 | |||
| 38 | test_case("4.2.3 of two runs of equal length the first is shortened"); | ||
| 39 | CHECK_STR(formatted("\x20\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x01"), "2001::1:0:0:1:1"); | ||
| 40 | |||
| 41 | test_case("4.3 hexadecimal digits are lower case"); | ||
| 42 | CHECK_STR(formatted("\xab\xcd\xef\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), "abcd:ef01::1"); | ||
| 43 | |||
| 44 | test_case("the unspecified and loopback addresses"); | ||
| 45 | CHECK_STR(formatted("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), "::"); | ||
| 46 | CHECK_STR(formatted("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), "::1"); | ||
| 47 | |||
| 48 | test_case("a full address with no zero group"); | ||
| 49 | CHECK_STR(formatted("\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88"), "1111:2222:3333:4444:5555:6666:7777:8888"); | ||
| 50 | } | ||
| 51 | |||
| 52 | static void case_format_trailing_zero_group(void) { | ||
| 53 | /* libowfat's formatter looked two bytes past the address to decide this | ||
| 54 | one, so a peer address ending in a zero group came out as "::" whenever | ||
| 55 | the bytes that happened to follow were not themselves zero. In | ||
| 56 | ot_stats.c those bytes are the peer's port. */ | ||
| 57 | const char ip[] = "\x20\x01\x0d\xb8\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x00"; | ||
| 58 | |||
| 59 | test_case("a single trailing zero group is written out, not shortened"); | ||
| 60 | CHECK_STR(formatted(ip), "2001:db8:1:2:3:4:5:0"); | ||
| 61 | |||
| 62 | test_case("and nothing beyond the sixteen bytes is consulted"); | ||
| 63 | { | ||
| 64 | char padded[20]; | ||
| 65 | memcpy(padded, ip, 16); | ||
| 66 | memset(padded + 16, 0xff, 4); /* a port and flags, as a peer record has */ | ||
| 67 | CHECK_STR(formatted(padded), "2001:db8:1:2:3:4:5:0"); | ||
| 68 | memset(padded + 16, 0x00, 4); | ||
| 69 | CHECK_STR(formatted(padded), "2001:db8:1:2:3:4:5:0"); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | static void case_v4mapped(void) { | ||
| 74 | const char mapped[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x0a\x00\x00\x01"; | ||
| 75 | const char unmapped[] = "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"; | ||
| 76 | |||
| 77 | test_case("a v4 mapped address is recognised"); | ||
| 78 | CHECK(ip_is_v4mapped(mapped)); | ||
| 79 | CHECK_INT(ip_is_v4mapped(unmapped), 0); | ||
| 80 | |||
| 81 | /* The tracker has only ever shown the plain quad, so that is the one | ||
| 82 | form the formatter produces; "::ffff:10.0.0.1" is not written anywhere */ | ||
| 83 | test_case("a mapped address is written as the plain dotted quad"); | ||
| 84 | CHECK_STR(formatted(mapped), "10.0.0.1"); | ||
| 85 | CHECK_STR(formatted("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00"), "0.0.0.0"); | ||
| 86 | CHECK_STR(formatted("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff"), "255.255.255.255"); | ||
| 87 | |||
| 88 | test_case("anything else follows RFC 5952"); | ||
| 89 | CHECK_STR(formatted(unmapped), "2001:db8::1"); | ||
| 90 | } | ||
| 91 | |||
| 92 | /* -------------------------------------------------------- RFC 4291 input */ | ||
| 93 | |||
| 94 | static void case_scan_forms(void) { | ||
| 95 | char ip[16]; | ||
| 96 | |||
| 97 | test_case("2.2 form 1, every group spelled out"); | ||
| 98 | CHECK_INT(ip_scan("1111:2222:3333:4444:5555:6666:7777:8888", ip), 39); | ||
| 99 | CHECK_MEM(ip, "\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88", 16); | ||
| 100 | |||
| 101 | test_case("2.2 form 2, zero groups abbreviated"); | ||
| 102 | CHECK_INT(ip_scan("2001:db8::1", ip), 11); | ||
| 103 | CHECK_MEM(ip, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); | ||
| 104 | CHECK_INT(ip_scan("::1", ip), 3); | ||
| 105 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); | ||
| 106 | CHECK_INT(ip_scan("::", ip), 2); | ||
| 107 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); | ||
| 108 | CHECK_INT(ip_scan("1::", ip), 3); | ||
| 109 | CHECK_MEM(ip, "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); | ||
| 110 | |||
| 111 | test_case("2.2 form 3, a dotted quad in the last two groups"); | ||
| 112 | CHECK_INT(ip_scan("::ffff:1.2.3.4", ip), 14); | ||
| 113 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x03\x04", 16); | ||
| 114 | CHECK_INT(ip_scan("1:2:3:4:5:6:1.2.3.4", ip), 19); | ||
| 115 | CHECK_MEM(ip, "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x02\x03\x04", 16); | ||
| 116 | |||
| 117 | test_case("upper case input is accepted"); | ||
| 118 | CHECK_INT(ip_scan("2001:DB8::1", ip), 11); | ||
| 119 | CHECK_MEM(ip, "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16); | ||
| 120 | } | ||
| 121 | |||
| 122 | static void case_scan_accepts_bare_ipv4(void) { | ||
| 123 | char ip[16]; | ||
| 124 | |||
| 125 | /* Every address opentracker holds is sixteen bytes, so an operator writing | ||
| 126 | a plain IPv4 address in the config has to land as the v4 mapped form */ | ||
| 127 | test_case("a bare IPv4 address is stored v4 mapped"); | ||
| 128 | CHECK_INT(ip_scan("10.0.0.1", ip), 8); | ||
| 129 | CHECK_MEM(ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x0a\x00\x00\x01", 16); | ||
| 130 | CHECK(ip_is_v4mapped(ip)); | ||
| 131 | } | ||
| 132 | |||
| 133 | static void case_scan_reports_length(void) { | ||
| 134 | char ip[16]; | ||
| 135 | |||
| 136 | /* The config parser continues from where the address ended, which is how | ||
| 137 | "address:port" and "address/bits" are read */ | ||
| 138 | test_case("scanning stops at the character after the address"); | ||
| 139 | CHECK_INT(ip_scan("10.0.0.1:6969", ip), 8); | ||
| 140 | CHECK_INT(ip_scan("2001:db8::1/64", ip), 11); | ||
| 141 | CHECK_INT(ip_scan("::1]", ip), 3); | ||
| 142 | CHECK_INT(ip_scan("1:2:3:4:5:6:7:8 trailing", ip), 15); | ||
| 143 | } | ||
| 144 | |||
| 145 | static void case_scan_rejects(void) { | ||
| 146 | char ip[16]; | ||
| 147 | |||
| 148 | test_case("an empty or junk string is refused"); | ||
| 149 | CHECK_INT(ip_scan("", ip), 0); | ||
| 150 | CHECK_INT(ip_scan("x", ip), 0); | ||
| 151 | CHECK_INT(ip_scan(":", ip), 0); | ||
| 152 | CHECK_INT(ip_scan(":1:2", ip), 0); | ||
| 153 | |||
| 154 | test_case("too few groups without :: are refused"); | ||
| 155 | CHECK_INT(ip_scan("1:2:3:4:5:6:7", ip), 0); | ||
| 156 | CHECK_INT(ip_scan("2001:db8:1", ip), 0); | ||
| 157 | |||
| 158 | /* libowfat accepted a prefix of each of these and carried on. Taking only | ||
| 159 | part of a malformed address is worse than refusing it, especially where | ||
| 160 | the text comes from a config file or an X-Forwarded-For header. */ | ||
| 161 | test_case("a second :: is refused rather than truncated"); | ||
| 162 | CHECK_INT(ip_scan("1::2::3", ip), 0); | ||
| 163 | CHECK_INT(ip_scan("::1::", ip), 0); | ||
| 164 | CHECK_INT(ip_scan("::::", ip), 0); | ||
| 165 | |||
| 166 | test_case("more than eight groups is refused"); | ||
| 167 | CHECK_INT(ip_scan("1:2:3:4:5:6:7:8:9", ip), 0); | ||
| 168 | |||
| 169 | test_case("a group of more than four digits is refused, not truncated"); | ||
| 170 | CHECK_INT(ip_scan("12345::1", ip), 0); | ||
| 171 | CHECK_INT(ip_scan("fffff::1", ip), 0); | ||
| 172 | } | ||
| 173 | |||
| 174 | static void case_round_trip(void) { | ||
| 175 | /* Whatever the formatter writes, the scanner has to read back */ | ||
| 176 | static const char *const samples[] = {"::", | ||
| 177 | "::1", | ||
| 178 | "1::", | ||
| 179 | "2001:db8::1", | ||
| 180 | "2001:db8:1:2:3:4:5:0", | ||
| 181 | "1111:2222:3333:4444:5555:6666:7777:8888", | ||
| 182 | "2001::1:0:0:1", | ||
| 183 | "abcd:ef01::1", | ||
| 184 | NULL}; | ||
| 185 | char ip[16], again[16]; | ||
| 186 | size_t i; | ||
| 187 | |||
| 188 | test_case("every formatted address scans back to the same bytes"); | ||
| 189 | for (i = 0; samples[i]; ++i) { | ||
| 190 | size_t n = ip_scan(samples[i], ip); | ||
| 191 | if (n != strlen(samples[i])) { | ||
| 192 | test_failf(__FILE__, __LINE__, "\"%s\" consumed %zu of %zu", samples[i], n, strlen(samples[i])); | ||
| 193 | return; | ||
| 194 | } | ||
| 195 | text[ip_format(text, ip)] = 0; | ||
| 196 | if (strcmp(text, samples[i])) { | ||
| 197 | test_failf(__FILE__, __LINE__, "\"%s\" formatted back as \"%s\"", samples[i], text); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | if (!ip_scan(text, again) || memcmp(ip, again, 16)) { | ||
| 201 | test_failf(__FILE__, __LINE__, "\"%s\" did not survive a second pass", samples[i]); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | ++test_checks; | ||
| 206 | } | ||
| 207 | |||
| 208 | void test_ip(void) { | ||
| 209 | case_format_rfc5952(); | ||
| 210 | case_format_trailing_zero_group(); | ||
| 211 | case_v4mapped(); | ||
| 212 | case_scan_forms(); | ||
| 213 | case_scan_accepts_bare_ipv4(); | ||
| 214 | case_scan_reports_length(); | ||
| 215 | case_scan_rejects(); | ||
| 216 | case_round_trip(); | ||
| 217 | } | ||
diff --git a/tests/test.h b/tests/test.h index f0f2360..7449b73 100644 --- a/tests/test.h +++ b/tests/test.h | |||
| @@ -83,5 +83,7 @@ void test_random(void); | |||
| 83 | void test_hex(void); | 83 | void test_hex(void); |
| 84 | void test_accesslist(void); | 84 | void test_accesslist(void); |
| 85 | void test_scan(void); | 85 | void test_scan(void); |
| 86 | void test_buf(void); | ||
| 87 | void test_ip(void); | ||
| 86 | 88 | ||
| 87 | #endif | 89 | #endif |
diff --git a/trackerlogic.c b/trackerlogic.c index d8a2f9b..db1d787 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
| @@ -13,26 +13,26 @@ | |||
| 13 | /* Libowfat */ | 13 | /* Libowfat */ |
| 14 | #include "io.h" | 14 | #include "io.h" |
| 15 | #include "iob.h" | 15 | #include "iob.h" |
| 16 | #include "ip6.h" | ||
| 17 | 16 | ||
| 18 | /* Opentracker */ | 17 | /* Opentracker */ |
| 19 | #include "ot_accesslist.h" | 18 | #include "ot_accesslist.h" |
| 20 | #include "ot_clean.h" | 19 | #include "ot_clean.h" |
| 21 | #include "ot_fullscrape.h" | 20 | #include "ot_fullscrape.h" |
| 22 | #include "ot_http.h" | 21 | #include "ot_http.h" |
| 22 | #include "ot_ip.h" | ||
| 23 | #include "ot_livesync.h" | 23 | #include "ot_livesync.h" |
| 24 | #include "ot_mutex.h" | 24 | #include "ot_mutex.h" |
| 25 | #include "ot_random.h" | 25 | #include "ot_random.h" |
| 26 | #include "ot_stats.h" | 26 | #include "ot_stats.h" |
| 27 | #include "ot_vector.h" | ||
| 28 | #include "ot_udp.h" | 27 | #include "ot_udp.h" |
| 28 | #include "ot_vector.h" | ||
| 29 | #include "trackerlogic.h" | 29 | #include "trackerlogic.h" |
| 30 | 30 | ||
| 31 | /* Forward declaration */ | 31 | /* Forward declaration */ |
| 32 | size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto); | 32 | size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto); |
| 33 | 33 | ||
| 34 | void free_peerlist(ot_peerlist *peer_list) { | 34 | void free_peerlist(ot_peerlist *peer_list) { |
| 35 | if (peer_list->peers.data) { | 35 | if (peer_list && peer_list->peers.data) { |
| 36 | if (OT_PEERLIST_HASBUCKETS(peer_list)) | 36 | if (OT_PEERLIST_HASBUCKETS(peer_list)) |
| 37 | vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size); | 37 | vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size); |
| 38 | else | 38 | else |
| @@ -511,7 +511,7 @@ void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), | |||
| 511 | 511 | ||
| 512 | ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size) { | 512 | ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size) { |
| 513 | ot_ip6 *ip = (ot_ip6 *)peer; | 513 | ot_ip6 *ip = (ot_ip6 *)peer; |
| 514 | if (!ip6_isv4mapped(ip)) { | 514 | if (!ip_is_v4mapped(ip)) { |
| 515 | *peer_size = OT_PEER_SIZE6; | 515 | *peer_size = OT_PEER_SIZE6; |
| 516 | return (ot_peer *)peer; | 516 | return (ot_peer *)peer; |
| 517 | } | 517 | } |
| @@ -521,7 +521,7 @@ ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size) { | |||
| 521 | 521 | ||
| 522 | size_t peer_size_from_peer6(ot_peer6 *peer) { | 522 | size_t peer_size_from_peer6(ot_peer6 *peer) { |
| 523 | ot_ip6 *ip = (ot_ip6 *)peer; | 523 | ot_ip6 *ip = (ot_ip6 *)peer; |
| 524 | if (!ip6_isv4mapped(ip)) | 524 | if (!ip_is_v4mapped(ip)) |
| 525 | return OT_PEER_SIZE6; | 525 | return OT_PEER_SIZE6; |
| 526 | return OT_PEER_SIZE4; | 526 | return OT_PEER_SIZE4; |
| 527 | } | 527 | } |
