diff options
Diffstat (limited to 'toxcore/network.c')
-rw-r--r-- | toxcore/network.c | 71 |
1 files changed, 51 insertions, 20 deletions
diff --git a/toxcore/network.c b/toxcore/network.c index 839618bf..35b55bf1 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -315,17 +315,17 @@ typedef struct { | |||
315 | uint64_t send_fail_eagain; | 315 | uint64_t send_fail_eagain; |
316 | } select_info; | 316 | } select_info; |
317 | 317 | ||
318 | int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data, uint16_t *lenptr) | 318 | size_t networking_wait_data_size() |
319 | { | 319 | { |
320 | if ((data == NULL) || !lenptr || (*lenptr < sizeof(select_info))) { | 320 | return sizeof(select_info); |
321 | if (lenptr) { | 321 | } |
322 | *lenptr = sizeof(select_info); | 322 | |
323 | return 0; | 323 | int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uint8_t *data) |
324 | } else | 324 | { |
325 | return -1; | 325 | if (data == NULL) { |
326 | return 0; | ||
326 | } | 327 | } |
327 | 328 | ||
328 | *lenptr = sizeof(select_info); | ||
329 | select_info *s = (select_info *)data; | 329 | select_info *s = (select_info *)data; |
330 | s->sock = net->sock; | 330 | s->sock = net->sock; |
331 | s->sendqueue_length = sendqueue_length; | 331 | s->sendqueue_length = sendqueue_length; |
@@ -335,25 +335,41 @@ int networking_wait_prepare(Networking_Core *net, uint32_t sendqueue_length, uin | |||
335 | return 1; | 335 | return 1; |
336 | } | 336 | } |
337 | 337 | ||
338 | int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) | 338 | /* *** Function MUSTN'T poll. *** |
339 | * The function mustn't modify anything at all, so it can be called completely | ||
340 | * asynchronously without any worry. | ||
341 | */ | ||
342 | int networking_wait_execute(uint8_t *data, long seconds, long microseconds) | ||
339 | { | 343 | { |
340 | /* WIN32: supported since Win2K, but might need some adjustements */ | 344 | /* WIN32: supported since Win2K, but might need some adjustements */ |
341 | /* UNIX: this should work for any remotely Unix'ish system */ | 345 | /* UNIX: this should work for any remotely Unix'ish system */ |
342 | 346 | ||
347 | if (data == NULL) { | ||
348 | return 0; | ||
349 | } | ||
350 | |||
343 | select_info *s = (select_info *)data; | 351 | select_info *s = (select_info *)data; |
344 | 352 | ||
345 | /* add only if we had a failed write */ | 353 | /* add only if we had a failed write */ |
346 | int writefds_add = 0; | 354 | int writefds_add = 0; |
347 | 355 | ||
356 | /* if send_fail_eagain is set, that means that socket's buffer was full and couldn't fit data we tried to send, | ||
357 | * so this is the only case when we need to know when the socket becomes write-ready, i.e. socket's buffer gets | ||
358 | * some free space for us to put data to be sent in, but select will tell us that the socket is writable even | ||
359 | * if we can fit a small part of our data (say 1 byte), so we wait some time, in hope that large enough chunk | ||
360 | * of socket's buffer will be available (at least that's how I understand intentions of the previous author of | ||
361 | * that code) | ||
362 | */ | ||
348 | if (s->send_fail_eagain != 0) { | 363 | if (s->send_fail_eagain != 0) { |
349 | // current_time(): microseconds | 364 | // current_time(): microseconds |
350 | uint64_t now = current_time(); | 365 | uint64_t now = current_time(); |
351 | 366 | ||
352 | /* s->sendqueue_length: might be used to guess how long we keep checking */ | 367 | /* s->sendqueue_length: might be used to guess how long we keep checking */ |
353 | /* for now, threshold is hardcoded to 500ms, too long for a really really | 368 | /* for now, threshold is hardcoded to 250ms, too long for a really really |
354 | * fast link, but too short for a sloooooow link... */ | 369 | * fast link, but too short for a sloooooow link... */ |
355 | if (now - s->send_fail_eagain < 500000) | 370 | if (now - s->send_fail_eagain < 250000) { |
356 | writefds_add = 1; | 371 | writefds_add = 1; |
372 | } | ||
357 | } | 373 | } |
358 | 374 | ||
359 | int nfds = 1 + s->sock; | 375 | int nfds = 1 + s->sock; |
@@ -366,27 +382,34 @@ int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) | |||
366 | fd_set writefds; | 382 | fd_set writefds; |
367 | FD_ZERO(&writefds); | 383 | FD_ZERO(&writefds); |
368 | 384 | ||
369 | if (writefds_add) | 385 | if (writefds_add) { |
370 | FD_SET(s->sock, &writefds); | 386 | FD_SET(s->sock, &writefds); |
387 | } | ||
371 | 388 | ||
372 | fd_set exceptfds; | 389 | fd_set exceptfds; |
373 | FD_ZERO(&exceptfds); | 390 | FD_ZERO(&exceptfds); |
374 | FD_SET(s->sock, &exceptfds); | 391 | FD_SET(s->sock, &exceptfds); |
375 | 392 | ||
376 | struct timeval timeout; | 393 | struct timeval timeout; |
377 | timeout.tv_sec = 0; | 394 | struct timeval *timeout_ptr = &timeout; |
378 | timeout.tv_usec = milliseconds * 1000; | 395 | |
396 | if (seconds < 0 || microseconds < 0) { | ||
397 | timeout_ptr = NULL; | ||
398 | } else { | ||
399 | timeout.tv_sec = seconds; | ||
400 | timeout.tv_usec = microseconds; | ||
401 | } | ||
379 | 402 | ||
380 | #ifdef LOGGING | 403 | #ifdef LOGGING |
381 | errno = 0; | 404 | errno = 0; |
382 | #endif | 405 | #endif |
383 | /* returns -1 on error, 0 on timeout, the socket on activity */ | 406 | /* returns -1 on error, 0 on timeout, the socket on activity */ |
384 | int res = select(nfds, &readfds, &writefds, &exceptfds, &timeout); | 407 | int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr); |
385 | #ifdef LOGGING | 408 | #ifdef LOGGING |
386 | 409 | ||
387 | /* only dump if not timeout */ | 410 | /* only dump if not timeout */ |
388 | if (res) { | 411 | if (res) { |
389 | sprintf(logbuffer, "select(%d): %d (%d, %s) - %d %d %d\n", milliseconds, res, errno, | 412 | sprintf(logbuffer, "select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno, |
390 | strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds), | 413 | strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds), |
391 | FD_ISSET(s->sock, &exceptfds)); | 414 | FD_ISSET(s->sock, &exceptfds)); |
392 | loglog(logbuffer); | 415 | loglog(logbuffer); |
@@ -394,18 +417,26 @@ int networking_wait_execute(uint8_t *data, uint16_t len, uint16_t milliseconds) | |||
394 | 417 | ||
395 | #endif | 418 | #endif |
396 | 419 | ||
397 | if (FD_ISSET(s->sock, &writefds)) | 420 | if (FD_ISSET(s->sock, &writefds)) { |
398 | s->send_fail_reset = 1; | 421 | s->send_fail_reset = 1; |
422 | } | ||
399 | 423 | ||
400 | return res > 0 ? 1 : 0; | 424 | return res > 0 ? 2 : 1; |
401 | } | 425 | } |
402 | 426 | ||
403 | void networking_wait_cleanup(Networking_Core *net, uint8_t *data, uint16_t len) | 427 | int networking_wait_cleanup(Networking_Core *net, uint8_t *data) |
404 | { | 428 | { |
429 | if (data == NULL) { | ||
430 | return 0; | ||
431 | } | ||
432 | |||
405 | select_info *s = (select_info *)data; | 433 | select_info *s = (select_info *)data; |
406 | 434 | ||
407 | if (s->send_fail_reset) | 435 | if (s->send_fail_reset) { |
408 | net->send_fail_eagain = 0; | 436 | net->send_fail_eagain = 0; |
437 | } | ||
438 | |||
439 | return 1; | ||
409 | } | 440 | } |
410 | 441 | ||
411 | uint8_t at_startup_ran = 0; | 442 | uint8_t at_startup_ran = 0; |