diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2012-01-27 13:48:30 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2012-01-27 13:48:30 +0000 |
commit | 3d6d182f86ba766bc31223853508449dde5dee38 (patch) | |
tree | 2417201a04b962a03e07eea7d9ce91f8c575cd73 /src/transport/plugin_transport_unix.c | |
parent | 8d27a7aa70365aa8c096ddf04671e4c30fadd5b2 (diff) | |
download | gnunet-3d6d182f86ba766bc31223853508449dde5dee38.tar.gz gnunet-3d6d182f86ba766bc31223853508449dde5dee38.zip |
complete select write implementation
Diffstat (limited to 'src/transport/plugin_transport_unix.c')
-rw-r--r-- | src/transport/plugin_transport_unix.c | 270 |
1 files changed, 124 insertions, 146 deletions
diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c index 06918d39d..294ef5fd0 100644 --- a/src/transport/plugin_transport_unix.c +++ b/src/transport/plugin_transport_unix.c | |||
@@ -64,6 +64,8 @@ | |||
64 | */ | 64 | */ |
65 | #define UNIX_NAT_DEFAULT_PORT 22086 | 65 | #define UNIX_NAT_DEFAULT_PORT 22086 |
66 | 66 | ||
67 | #define MAX_RETRIES 5 | ||
68 | |||
67 | GNUNET_NETWORK_STRUCT_BEGIN | 69 | GNUNET_NETWORK_STRUCT_BEGIN |
68 | 70 | ||
69 | /** | 71 | /** |
@@ -83,22 +85,26 @@ struct UNIXMessage | |||
83 | 85 | ||
84 | }; | 86 | }; |
85 | 87 | ||
86 | struct RetryList | 88 | struct UNIXMessageWrapper |
87 | { | 89 | { |
88 | /** | 90 | struct UNIXMessageWrapper *next; |
89 | * Pointer to next element. | 91 | struct UNIXMessageWrapper *prev; |
90 | */ | ||
91 | struct RetryList *next; | ||
92 | 92 | ||
93 | /** | 93 | struct UNIXMessage * msg; |
94 | * Pointer to previous element. | 94 | size_t msgsize; |
95 | */ | ||
96 | struct RetryList *prev; | ||
97 | 95 | ||
98 | /** | 96 | int retry_counter; |
99 | * The actual retry context. | 97 | |
100 | */ | 98 | struct GNUNET_PeerIdentity target; |
101 | struct RetrySendContext *retry_ctx; | 99 | |
100 | struct GNUNET_TIME_Relative timeout; | ||
101 | unsigned int priority; | ||
102 | |||
103 | void *addr; | ||
104 | size_t addrlen; | ||
105 | struct Session *session; | ||
106 | GNUNET_TRANSPORT_TransmitContinuation cont; | ||
107 | void *cont_cls; | ||
102 | }; | 108 | }; |
103 | 109 | ||
104 | /** | 110 | /** |
@@ -339,6 +345,9 @@ struct Plugin | |||
339 | */ | 345 | */ |
340 | char *unix_socket_path; | 346 | char *unix_socket_path; |
341 | 347 | ||
348 | struct UNIXMessageWrapper *msg_head; | ||
349 | struct UNIXMessageWrapper *msg_tail; | ||
350 | |||
342 | /** | 351 | /** |
343 | * ATS network | 352 | * ATS network |
344 | */ | 353 | */ |
@@ -346,17 +355,6 @@ struct Plugin | |||
346 | }; | 355 | }; |
347 | 356 | ||
348 | /** | 357 | /** |
349 | * Head of retry DLL. | ||
350 | */ | ||
351 | static struct RetryList *retry_list_head; | ||
352 | |||
353 | /** | ||
354 | * Tail of retry DLL. | ||
355 | */ | ||
356 | static struct RetryList *retry_list_tail; | ||
357 | |||
358 | |||
359 | /** | ||
360 | * Disconnect from a remote node. Clean up session if we have one for this peer | 358 | * Disconnect from a remote node. Clean up session if we have one for this peer |
361 | * | 359 | * |
362 | * @param cls closure for this call (should be handle to Plugin) | 360 | * @param cls closure for this call (should be handle to Plugin) |
@@ -383,21 +381,16 @@ static int | |||
383 | unix_transport_server_stop (void *cls) | 381 | unix_transport_server_stop (void *cls) |
384 | { | 382 | { |
385 | struct Plugin *plugin = cls; | 383 | struct Plugin *plugin = cls; |
386 | struct RetryList *pos; | ||
387 | 384 | ||
388 | pos = retry_list_head; | 385 | struct UNIXMessageWrapper * msgw = plugin->msg_head; |
389 | 386 | ||
390 | while (NULL != (pos = retry_list_head)) | 387 | while (NULL != (msgw = plugin->msg_head)) |
391 | { | 388 | { |
392 | GNUNET_CONTAINER_DLL_remove (retry_list_head, retry_list_tail, pos); | 389 | GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw); |
393 | if (GNUNET_SCHEDULER_NO_TASK != pos->retry_ctx->retry_task) | 390 | if (msgw->cont != NULL) |
394 | { | 391 | msgw->cont (msgw->cont_cls, &msgw->target, GNUNET_SYSERR); |
395 | GNUNET_SCHEDULER_cancel (pos->retry_ctx->retry_task); | 392 | GNUNET_free (msgw->msg); |
396 | } | 393 | GNUNET_free (msgw); |
397 | GNUNET_free (pos->retry_ctx->msg); | ||
398 | GNUNET_free (pos->retry_ctx->addr); | ||
399 | GNUNET_free (pos->retry_ctx); | ||
400 | GNUNET_free (pos); | ||
401 | } | 394 | } |
402 | 395 | ||
403 | if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) | 396 | if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) |
@@ -441,34 +434,6 @@ unix_real_send (void *cls, struct RetrySendContext *incoming_retry_context, | |||
441 | void *cont_cls); | 434 | void *cont_cls); |
442 | 435 | ||
443 | /** | 436 | /** |
444 | * Retry sending a message. | ||
445 | * | ||
446 | * @param cls closure a struct RetrySendContext | ||
447 | * @param tc context information | ||
448 | */ | ||
449 | void | ||
450 | retry_send_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
451 | { | ||
452 | struct RetrySendContext *retry_ctx = cls; | ||
453 | |||
454 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
455 | { | ||
456 | GNUNET_free (retry_ctx->msg); | ||
457 | GNUNET_free (retry_ctx->addr); | ||
458 | GNUNET_free (retry_ctx); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | unix_real_send (retry_ctx->plugin, retry_ctx, retry_ctx->send_handle, | ||
463 | &retry_ctx->target, retry_ctx->msg, retry_ctx->msg_size, | ||
464 | retry_ctx->priority, | ||
465 | GNUNET_TIME_absolute_get_remaining (retry_ctx->timeout), | ||
466 | retry_ctx->addr, retry_ctx->addrlen, retry_ctx->cont, | ||
467 | retry_ctx->cont_cls); | ||
468 | return; | ||
469 | } | ||
470 | |||
471 | /** | ||
472 | * Actually send out the message, assume we've got the address and | 437 | * Actually send out the message, assume we've got the address and |
473 | * send_handle squared away! | 438 | * send_handle squared away! |
474 | * | 439 | * |
@@ -499,16 +464,12 @@ unix_real_send (void *cls, struct RetrySendContext *incoming_retry_context, | |||
499 | size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, | 464 | size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, |
500 | void *cont_cls) | 465 | void *cont_cls) |
501 | { | 466 | { |
502 | struct Plugin *plugin = cls; | 467 | |
503 | struct UNIXMessage *message; | ||
504 | struct RetrySendContext *retry_ctx; | ||
505 | int ssize; | ||
506 | ssize_t sent; | 468 | ssize_t sent; |
507 | const void *sb; | 469 | const void *sb; |
508 | size_t sbs; | 470 | size_t sbs; |
509 | struct sockaddr_un un; | 471 | struct sockaddr_un un; |
510 | size_t slen; | 472 | size_t slen; |
511 | struct RetryList *retry_list_entry; | ||
512 | int retry; | 473 | int retry; |
513 | 474 | ||
514 | if (send_handle == NULL) | 475 | if (send_handle == NULL) |
@@ -533,16 +494,6 @@ unix_real_send (void *cls, struct RetrySendContext *incoming_retry_context, | |||
533 | return 0; /* Can never send if we don't have an address!! */ | 494 | return 0; /* Can never send if we don't have an address!! */ |
534 | } | 495 | } |
535 | 496 | ||
536 | /* Build the message to be sent */ | ||
537 | message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size); | ||
538 | ssize = sizeof (struct UNIXMessage) + msgbuf_size; | ||
539 | |||
540 | message->header.size = htons (ssize); | ||
541 | message->header.type = htons (0); | ||
542 | memcpy (&message->sender, plugin->env->my_identity, | ||
543 | sizeof (struct GNUNET_PeerIdentity)); | ||
544 | memcpy (&message[1], msgbuf, msgbuf_size); | ||
545 | |||
546 | memset (&un, 0, sizeof (un)); | 497 | memset (&un, 0, sizeof (un)); |
547 | un.sun_family = AF_UNIX; | 498 | un.sun_family = AF_UNIX; |
548 | slen = strlen (addr) + 1; | 499 | slen = strlen (addr) + 1; |
@@ -562,8 +513,7 @@ unix_real_send (void *cls, struct RetrySendContext *incoming_retry_context, | |||
562 | sb = (struct sockaddr *) &un; | 513 | sb = (struct sockaddr *) &un; |
563 | sbs = slen; | 514 | sbs = slen; |
564 | retry = GNUNET_NO; | 515 | retry = GNUNET_NO; |
565 | 516 | sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs); | |
566 | sent = GNUNET_NETWORK_socket_sendto (send_handle, message, ssize, sb, sbs); | ||
567 | 517 | ||
568 | if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS))) | 518 | if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS))) |
569 | retry = GNUNET_YES; | 519 | retry = GNUNET_YES; |
@@ -577,14 +527,14 @@ unix_real_send (void *cls, struct RetrySendContext *incoming_retry_context, | |||
577 | send_handle, SOL_SOCKET, SO_SNDBUF, &size, | 527 | send_handle, SOL_SOCKET, SO_SNDBUF, &size, |
578 | &len); | 528 | &len); |
579 | 529 | ||
580 | if (size < ssize) | 530 | if (size < msgbuf_size) |
581 | { | 531 | { |
582 | #if DEBUG_UNIX | 532 | #if DEBUG_UNIX |
583 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 533 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
584 | "Trying to increase socket buffer size from %i to %i for message size %i\n", | 534 | "Trying to increase socket buffer size from %i to %i for message size %i\n", |
585 | size, ((ssize / 1000) + 2) * 1000, ssize); | 535 | size, ((ssize / 1000) + 2) * 1000, ssize); |
586 | #endif | 536 | #endif |
587 | size = ((ssize / 1000) + 2) * 1000; | 537 | size = ((msgbuf_size / 1000) + 2) * 1000; |
588 | if (GNUNET_NETWORK_socket_setsockopt | 538 | if (GNUNET_NETWORK_socket_setsockopt |
589 | ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF, | 539 | ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF, |
590 | &size, sizeof (size)) == GNUNET_OK) | 540 | &size, sizeof (size)) == GNUNET_OK) |
@@ -594,71 +544,31 @@ unix_real_send (void *cls, struct RetrySendContext *incoming_retry_context, | |||
594 | } | 544 | } |
595 | } | 545 | } |
596 | 546 | ||
597 | if (retry == GNUNET_YES) | ||
598 | { | ||
599 | if (incoming_retry_context == NULL) | ||
600 | { | ||
601 | retry_list_entry = GNUNET_malloc (sizeof (struct RetryList)); | ||
602 | retry_ctx = GNUNET_malloc (sizeof (struct RetrySendContext)); | ||
603 | retry_ctx->addr = GNUNET_malloc (addrlen); | ||
604 | retry_ctx->msg = GNUNET_malloc (msgbuf_size); | ||
605 | retry_ctx->plugin = plugin; | ||
606 | memcpy (retry_ctx->addr, addr, addrlen); | ||
607 | memcpy (retry_ctx->msg, msgbuf, msgbuf_size); | ||
608 | retry_ctx->msg_size = msgbuf_size; | ||
609 | retry_ctx->addrlen = addrlen; | ||
610 | retry_ctx->send_handle = send_handle; | ||
611 | retry_ctx->cont = cont; | ||
612 | retry_ctx->cont_cls = cont_cls; | ||
613 | retry_ctx->priority = priority; | ||
614 | retry_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
615 | memcpy (&retry_ctx->target, target, sizeof (struct GNUNET_PeerIdentity)); | ||
616 | retry_ctx->delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
617 | retry_ctx->retry_list_entry = retry_list_entry; | ||
618 | retry_list_entry->retry_ctx = retry_ctx; | ||
619 | GNUNET_CONTAINER_DLL_insert (retry_list_head, retry_list_tail, | ||
620 | retry_list_entry); | ||
621 | } | ||
622 | else | ||
623 | { | ||
624 | retry_ctx = incoming_retry_context; | ||
625 | retry_ctx->delay = GNUNET_TIME_relative_multiply (retry_ctx->delay, 2); | ||
626 | } | ||
627 | retry_ctx->retry_task = | ||
628 | GNUNET_SCHEDULER_add_delayed (retry_ctx->delay, &retry_send_message, | ||
629 | retry_ctx); | ||
630 | |||
631 | //GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send"); | ||
632 | GNUNET_free (message); | ||
633 | return ssize; | ||
634 | } | ||
635 | #if DEBUG_UNIX | 547 | #if DEBUG_UNIX |
636 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 548 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
637 | "UNIX transmit %u-byte message to %s (%d: %s)\n", | 549 | "UNIX transmit %u-byte message to %s (%d: %s)\n", |
638 | (unsigned int) ssize, GNUNET_a2s (sb, sbs), (int) sent, | 550 | (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent, |
639 | (sent < 0) ? STRERROR (errno) : "ok"); | 551 | (sent < 0) ? STRERROR (errno) : "ok"); |
640 | #endif | 552 | #endif |
553 | /* Calling continuation */ | ||
641 | if (cont != NULL) | 554 | if (cont != NULL) |
642 | { | 555 | { |
643 | if (sent == GNUNET_SYSERR) | 556 | if ((sent == GNUNET_SYSERR) && (retry == GNUNET_NO)) |
644 | cont (cont_cls, target, GNUNET_SYSERR); | 557 | cont (cont_cls, target, GNUNET_SYSERR); |
645 | else | 558 | if (sent > 0) |
646 | { | ||
647 | cont (cont_cls, target, GNUNET_OK); | 559 | cont (cont_cls, target, GNUNET_OK); |
648 | } | ||
649 | } | 560 | } |
650 | 561 | ||
651 | if (incoming_retry_context != NULL) | 562 | /* return number of bytes successfully sent */ |
652 | { | 563 | if (sent > 0) |
653 | GNUNET_CONTAINER_DLL_remove (retry_list_head, retry_list_tail, | 564 | return sent; |
654 | incoming_retry_context->retry_list_entry); | 565 | /* failed and retry: return 0 */ |
655 | GNUNET_free (incoming_retry_context->retry_list_entry); | 566 | if ((GNUNET_SYSERR == sent) && (retry == GNUNET_YES)) |
656 | GNUNET_free (incoming_retry_context->msg); | 567 | return 0; |
657 | GNUNET_free (incoming_retry_context->addr); | 568 | /* failed and no retry: return -1 */ |
658 | GNUNET_free (incoming_retry_context); | 569 | if ((GNUNET_SYSERR == sent) && (retry == GNUNET_NO)) |
659 | } | 570 | return -1; |
660 | 571 | ||
661 | GNUNET_free (message); | ||
662 | return sent; | 572 | return sent; |
663 | } | 573 | } |
664 | 574 | ||
@@ -756,25 +666,47 @@ unix_plugin_send_old (void *cls, const struct GNUNET_PeerIdentity *target, | |||
756 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | 666 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) |
757 | { | 667 | { |
758 | struct Plugin *plugin = cls; | 668 | struct Plugin *plugin = cls; |
759 | ssize_t sent; | 669 | struct UNIXMessage *message; |
670 | struct UNIXMessageWrapper *wrapper; | ||
671 | int ssize; | ||
760 | 672 | ||
761 | GNUNET_assert (NULL == session); | 673 | GNUNET_assert (NULL == session); |
762 | 674 | ||
675 | /* Build the message to be sent */ | ||
676 | wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper) + addrlen); | ||
677 | message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size); | ||
678 | ssize = sizeof (struct UNIXMessage) + msgbuf_size; | ||
679 | |||
763 | #if DEBUG_UNIX | 680 | #if DEBUG_UNIX |
764 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to send message to `%s'\n", | 681 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to send message to `%s'\n", |
765 | (char *) addr); | 682 | (char *) addr); |
766 | #endif | 683 | #endif |
767 | sent = | 684 | |
768 | unix_real_send (cls, NULL, plugin->unix_sock.desc, target, msgbuf, | 685 | message->header.size = htons (ssize); |
769 | msgbuf_size, priority, timeout, addr, addrlen, cont, | 686 | message->header.type = htons (0); |
770 | cont_cls); | 687 | memcpy (&message->sender, plugin->env->my_identity, |
688 | sizeof (struct GNUNET_PeerIdentity)); | ||
689 | memcpy (&message[1], msgbuf, msgbuf_size); | ||
690 | |||
691 | wrapper->msg = message; | ||
692 | wrapper->msgsize = ssize; | ||
693 | wrapper->priority = priority; | ||
694 | wrapper->timeout = timeout; | ||
695 | wrapper->cont = cont; | ||
696 | wrapper->cont_cls = cont_cls; | ||
697 | wrapper->addr = &wrapper[1]; | ||
698 | wrapper->addrlen = addrlen; | ||
699 | wrapper->retry_counter = 0; | ||
700 | memcpy (&wrapper->target, target, sizeof (struct GNUNET_PeerIdentity)); | ||
701 | memcpy (&wrapper[1], addr, addrlen); | ||
702 | |||
703 | GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper); | ||
704 | |||
771 | #if DEBUG_UNIX | 705 | #if DEBUG_UNIX |
772 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", sent, | 706 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", sent, |
773 | (char *) addr); | 707 | (char *) addr); |
774 | #endif | 708 | #endif |
775 | if (sent == GNUNET_SYSERR) | 709 | return ssize; |
776 | return 0; | ||
777 | return sent; | ||
778 | } | 710 | } |
779 | 711 | ||
780 | 712 | ||
@@ -880,7 +812,52 @@ unix_plugin_select_read (struct Plugin * plugin) | |||
880 | static void | 812 | static void |
881 | unix_plugin_select_write (struct Plugin * plugin) | 813 | unix_plugin_select_write (struct Plugin * plugin) |
882 | { | 814 | { |
815 | int sent = 0; | ||
816 | struct UNIXMessageWrapper * msgw = plugin->msg_head; | ||
817 | |||
818 | sent = unix_real_send (plugin, NULL, | ||
819 | plugin->unix_sock.desc, | ||
820 | &msgw->target, | ||
821 | (const char *) msgw->msg, | ||
822 | msgw->msgsize, | ||
823 | msgw->priority, | ||
824 | msgw->timeout, | ||
825 | msgw->addr, | ||
826 | msgw->addrlen, | ||
827 | msgw->cont, msgw->cont_cls); | ||
828 | |||
829 | /* successfully sent bytes */ | ||
830 | if (sent > 0) | ||
831 | { | ||
832 | GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); | ||
833 | GNUNET_free (msgw); | ||
834 | return; | ||
835 | } | ||
836 | |||
837 | /* max retries */ | ||
838 | if (msgw->retry_counter > MAX_RETRIES) | ||
839 | { | ||
840 | msgw->cont (msgw->cont_cls, &msgw->target, GNUNET_SYSERR); | ||
841 | GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); | ||
842 | GNUNET_break (0); | ||
843 | GNUNET_free (msgw); | ||
844 | return; | ||
845 | } | ||
846 | |||
847 | /* failed and no retry */ | ||
848 | if (sent == -1) | ||
849 | { | ||
850 | GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); | ||
851 | GNUNET_free (msgw); | ||
852 | return; | ||
853 | } | ||
883 | 854 | ||
855 | /* failed and retry */ | ||
856 | if (sent == 0) | ||
857 | { | ||
858 | msgw->retry_counter++; | ||
859 | return; | ||
860 | } | ||
884 | 861 | ||
885 | } | 862 | } |
886 | 863 | ||
@@ -907,7 +884,8 @@ unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
907 | { | 884 | { |
908 | GNUNET_assert (GNUNET_NETWORK_fdset_isset | 885 | GNUNET_assert (GNUNET_NETWORK_fdset_isset |
909 | (tc->write_ready, plugin->unix_sock.desc)); | 886 | (tc->write_ready, plugin->unix_sock.desc)); |
910 | unix_plugin_select_write (plugin); | 887 | if (plugin->msg_head != NULL) |
888 | unix_plugin_select_write (plugin); | ||
911 | } | 889 | } |
912 | 890 | ||
913 | if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) | 891 | if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) |