aboutsummaryrefslogtreecommitdiff
path: root/src/ats/ats_api_scheduling.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ats/ats_api_scheduling.c')
-rw-r--r--src/ats/ats_api_scheduling.c263
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
83struct 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
623static void
624delete_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
636static int
637interface_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 */
739static void
740get_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
757struct GNUNET_ATS_Information
758GNUNET_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}