diff options
Diffstat (limited to 'src/ats/ats_api_scheduling.c')
-rw-r--r-- | src/ats/ats_api_scheduling.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c index 0658e362c..c5a9c623f 100644 --- a/src/ats/ats_api_scheduling.c +++ b/src/ats/ats_api_scheduling.c | |||
@@ -80,6 +80,19 @@ struct SessionRecord | |||
80 | }; | 80 | }; |
81 | 81 | ||
82 | 82 | ||
83 | struct ATS_Network | ||
84 | { | ||
85 | struct ATS_Network * next; | ||
86 | |||
87 | struct ATS_Network * prev; | ||
88 | |||
89 | struct sockaddr *network; | ||
90 | struct sockaddr *netmask; | ||
91 | socklen_t length; | ||
92 | }; | ||
93 | |||
94 | |||
95 | |||
83 | /** | 96 | /** |
84 | * Handle to the ATS subsystem for bandwidth/transport scheduling information. | 97 | * Handle to the ATS subsystem for bandwidth/transport scheduling information. |
85 | */ | 98 | */ |
@@ -122,6 +135,17 @@ struct GNUNET_ATS_SchedulingHandle | |||
122 | struct GNUNET_CLIENT_TransmitHandle *th; | 135 | struct GNUNET_CLIENT_TransmitHandle *th; |
123 | 136 | ||
124 | /** | 137 | /** |
138 | * Head of network list | ||
139 | */ | ||
140 | struct ATS_Network * net_head; | ||
141 | |||
142 | /** | ||
143 | * Tail of network list | ||
144 | */ | ||
145 | struct ATS_Network * net_tail; | ||
146 | |||
147 | |||
148 | /** | ||
125 | * Array of session objects (we need to translate them to numbers and back | 149 | * Array of session objects (we need to translate them to numbers and back |
126 | * for the protocol; the offset in the array is the session number on the | 150 | * for the protocol; the offset in the array is the session number on the |
127 | * network). Index 0 is always NULL and reserved to represent the NULL pointer. | 151 | * network). Index 0 is always NULL and reserved to represent the NULL pointer. |
@@ -135,6 +159,13 @@ struct GNUNET_ATS_SchedulingHandle | |||
135 | GNUNET_SCHEDULER_TaskIdentifier task; | 159 | GNUNET_SCHEDULER_TaskIdentifier task; |
136 | 160 | ||
137 | /** | 161 | /** |
162 | * Task retrieving interfaces from the system | ||
163 | */ | ||
164 | |||
165 | GNUNET_SCHEDULER_TaskIdentifier interface_task; | ||
166 | |||
167 | |||
168 | /** | ||
138 | * Size of the session array. | 169 | * Size of the session array. |
139 | */ | 170 | */ |
140 | unsigned int session_array_size; | 171 | unsigned int session_array_size; |
@@ -585,6 +616,228 @@ reconnect (struct GNUNET_ATS_SchedulingHandle *sh) | |||
585 | do_transmit (sh); | 616 | do_transmit (sh); |
586 | } | 617 | } |
587 | 618 | ||
619 | /** | ||
620 | * delete the current network list | ||
621 | */ | ||
622 | |||
623 | static void | ||
624 | delete_networks (struct GNUNET_ATS_SchedulingHandle *sh) | ||
625 | { | ||
626 | struct ATS_Network * cur = sh->net_head; | ||
627 | while (cur != NULL) | ||
628 | { | ||
629 | GNUNET_CONTAINER_DLL_remove(sh->net_head, sh->net_tail, cur); | ||
630 | GNUNET_free (cur); | ||
631 | cur = sh->net_head; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | |||
636 | static int | ||
637 | interface_proc (void *cls, const char *name, | ||
638 | int isDefault, | ||
639 | const struct sockaddr * | ||
640 | addr, | ||
641 | const struct sockaddr * | ||
642 | broadcast_addr, | ||
643 | const struct sockaddr * | ||
644 | netmask, socklen_t addrlen) | ||
645 | { | ||
646 | struct GNUNET_ATS_SchedulingHandle * sh = cls; | ||
647 | /* Calculate network */ | ||
648 | struct ATS_Network *net = NULL; | ||
649 | |||
650 | /* Skipping IPv4 loopback addresses since we have special check */ | ||
651 | if (addr->sa_family == AF_INET) | ||
652 | { | ||
653 | struct sockaddr_in * a4 = (struct sockaddr_in *) addr; | ||
654 | |||
655 | if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) | ||
656 | return GNUNET_OK; | ||
657 | } | ||
658 | /* Skipping IPv6 loopback addresses since we have special check */ | ||
659 | if (addr->sa_family == AF_INET6) | ||
660 | { | ||
661 | struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; | ||
662 | if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) | ||
663 | return GNUNET_OK; | ||
664 | } | ||
665 | |||
666 | if (addr->sa_family == AF_INET) | ||
667 | { | ||
668 | struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; | ||
669 | struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask; | ||
670 | struct sockaddr_in *tmp = NULL; | ||
671 | struct sockaddr_in network4; | ||
672 | |||
673 | net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in)); | ||
674 | tmp = (struct sockaddr_in *) &net[1]; | ||
675 | net->network = (struct sockaddr *) &tmp[0]; | ||
676 | net->netmask = (struct sockaddr *) &tmp[1]; | ||
677 | net->length = addrlen; | ||
678 | |||
679 | network4.sin_family = AF_INET; | ||
680 | network4.sin_port = htons (0); | ||
681 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
682 | network4.sin_len = sizeof (network4); | ||
683 | #endif | ||
684 | network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr); | ||
685 | |||
686 | memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in)); | ||
687 | memcpy (net->network, &network4, sizeof (struct sockaddr_in)); | ||
688 | } | ||
689 | |||
690 | if (addr->sa_family == AF_INET6) | ||
691 | { | ||
692 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; | ||
693 | struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask; | ||
694 | struct sockaddr_in6 * tmp = NULL; | ||
695 | struct sockaddr_in6 network6; | ||
696 | |||
697 | net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6)); | ||
698 | tmp = (struct sockaddr_in6 *) &net[1]; | ||
699 | net->network = (struct sockaddr *) &tmp[0]; | ||
700 | net->netmask = (struct sockaddr *) &tmp[1]; | ||
701 | net->length = addrlen; | ||
702 | |||
703 | network6.sin6_family = AF_INET6; | ||
704 | network6.sin6_port = htons (0); | ||
705 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
706 | network6.sin6_len = sizeof (network6); | ||
707 | #endif | ||
708 | int c = 0; | ||
709 | uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr; | ||
710 | uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr; | ||
711 | uint32_t *net_elem = (uint32_t *) &network6.sin6_addr; | ||
712 | for (c = 0; c < 4; c++) | ||
713 | net_elem[c] = addr_elem[c] & mask_elem[c]; | ||
714 | |||
715 | memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6)); | ||
716 | memcpy (net->network, &network6, sizeof (struct sockaddr_in6)); | ||
717 | } | ||
718 | |||
719 | /* Store in list */ | ||
720 | if (net != NULL) | ||
721 | { | ||
722 | char * netmask = strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen)); | ||
723 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n", | ||
724 | GNUNET_a2s((struct sockaddr *) net->network, addrlen), | ||
725 | netmask); | ||
726 | GNUNET_free (netmask); | ||
727 | GNUNET_CONTAINER_DLL_insert(sh->net_head, sh->net_tail, net); | ||
728 | } | ||
729 | return GNUNET_OK; | ||
730 | } | ||
731 | |||
732 | |||
733 | |||
734 | /** | ||
735 | * Periodically get list of addresses | ||
736 | * @param cls closure | ||
737 | * @param tc Task context | ||
738 | */ | ||
739 | static void | ||
740 | get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
741 | { | ||
742 | struct GNUNET_ATS_SchedulingHandle * sh = cls; | ||
743 | sh->interface_task = GNUNET_SCHEDULER_NO_TASK; | ||
744 | delete_networks (sh); | ||
745 | GNUNET_OS_network_interfaces_list(interface_proc, sh); | ||
746 | |||
747 | sh->interface_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, get_addresses, NULL); | ||
748 | } | ||
749 | |||
750 | /** | ||
751 | * Returns where the address is located: LAN or WAN or ... | ||
752 | * @param addr address | ||
753 | * @param addrlen address length | ||
754 | * @return location as GNUNET_ATS_Information | ||
755 | */ | ||
756 | |||
757 | struct GNUNET_ATS_Information | ||
758 | GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle * sh, const struct sockaddr * addr, socklen_t addrlen) | ||
759 | { | ||
760 | struct GNUNET_ATS_Information ats; | ||
761 | struct ATS_Network * cur = sh->net_head; | ||
762 | int type = GNUNET_ATS_NET_UNSPECIFIED; | ||
763 | |||
764 | /* IPv4 loopback check */ | ||
765 | if (addr->sa_family == AF_INET) | ||
766 | { | ||
767 | struct sockaddr_in * a4 = (struct sockaddr_in *) addr; | ||
768 | |||
769 | if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) | ||
770 | type = GNUNET_ATS_NET_LOOPBACK; | ||
771 | } | ||
772 | /* IPv6 loopback check */ | ||
773 | if (addr->sa_family == AF_INET6) | ||
774 | { | ||
775 | struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; | ||
776 | if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) | ||
777 | type = GNUNET_ATS_NET_LOOPBACK; | ||
778 | } | ||
779 | |||
780 | /* Check local networks */ | ||
781 | while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED)) | ||
782 | { | ||
783 | if (addrlen != cur->length) | ||
784 | { | ||
785 | cur = cur->next; | ||
786 | continue; | ||
787 | } | ||
788 | |||
789 | if (addr->sa_family == AF_INET) | ||
790 | { | ||
791 | struct sockaddr_in * a4 = (struct sockaddr_in *) addr; | ||
792 | struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network; | ||
793 | struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask; | ||
794 | |||
795 | if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr) | ||
796 | { | ||
797 | char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen)); | ||
798 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", | ||
799 | GNUNET_a2s ((const struct sockaddr *)a4, addrlen), | ||
800 | net); | ||
801 | GNUNET_free (net); | ||
802 | type = GNUNET_ATS_NET_LAN; | ||
803 | } | ||
804 | } | ||
805 | if (addr->sa_family == AF_INET6) | ||
806 | { | ||
807 | struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; | ||
808 | struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network; | ||
809 | struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask; | ||
810 | |||
811 | int res = GNUNET_YES; | ||
812 | int c = 0; | ||
813 | uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr; | ||
814 | uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr; | ||
815 | uint32_t *net_elem = (uint32_t *) &net6->sin6_addr; | ||
816 | for (c = 0; c < 4; c++) | ||
817 | if ((addr_elem[c] & mask_elem[c]) != net_elem[c]) | ||
818 | res = GNUNET_NO; | ||
819 | |||
820 | if (res == GNUNET_YES) | ||
821 | { | ||
822 | char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen)); | ||
823 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", | ||
824 | GNUNET_a2s ((const struct sockaddr *) a6, addrlen), | ||
825 | net); | ||
826 | GNUNET_free (net); | ||
827 | type = GNUNET_ATS_NET_LAN; | ||
828 | } | ||
829 | } | ||
830 | cur = cur->next; | ||
831 | } | ||
832 | |||
833 | /* local network found for this address, default: WAN */ | ||
834 | if (type == GNUNET_ATS_NET_UNSPECIFIED) | ||
835 | type = GNUNET_ATS_NET_WAN; | ||
836 | |||
837 | ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); | ||
838 | ats.value = htonl (type); | ||
839 | return ats; | ||
840 | } | ||
588 | 841 | ||
589 | /** | 842 | /** |
590 | * Initialize the ATS subsystem. | 843 | * Initialize the ATS subsystem. |
@@ -606,6 +859,8 @@ GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
606 | sh->suggest_cb = suggest_cb; | 859 | sh->suggest_cb = suggest_cb; |
607 | sh->suggest_cb_cls = suggest_cb_cls; | 860 | sh->suggest_cb_cls = suggest_cb_cls; |
608 | GNUNET_array_grow (sh->session_array, sh->session_array_size, 4); | 861 | GNUNET_array_grow (sh->session_array, sh->session_array_size, 4); |
862 | GNUNET_OS_network_interfaces_list(interface_proc, sh); | ||
863 | sh->interface_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, get_addresses, NULL); | ||
609 | reconnect (sh); | 864 | reconnect (sh); |
610 | return sh; | 865 | return sh; |
611 | } | 866 | } |
@@ -636,6 +891,14 @@ GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh) | |||
636 | GNUNET_SCHEDULER_cancel (sh->task); | 891 | GNUNET_SCHEDULER_cancel (sh->task); |
637 | sh->task = GNUNET_SCHEDULER_NO_TASK; | 892 | sh->task = GNUNET_SCHEDULER_NO_TASK; |
638 | } | 893 | } |
894 | |||
895 | delete_networks (sh); | ||
896 | if (sh->interface_task != GNUNET_SCHEDULER_NO_TASK) | ||
897 | { | ||
898 | GNUNET_SCHEDULER_cancel(sh->interface_task); | ||
899 | sh->interface_task = GNUNET_SCHEDULER_NO_TASK; | ||
900 | } | ||
901 | |||
639 | GNUNET_array_grow (sh->session_array, sh->session_array_size, 0); | 902 | GNUNET_array_grow (sh->session_array, sh->session_array_size, 0); |
640 | GNUNET_free (sh); | 903 | GNUNET_free (sh); |
641 | } | 904 | } |