Mercurial > hg > freeDiameter
comparison freeDiameter/sctp.c @ 220:5f2ce627db3c
Try to fix the old bug on sctp_getpaddrs
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Fri, 19 Feb 2010 18:09:43 +0900 |
parents | b9f48f2f2a22 |
children | 482d3ebc4cb9 |
comparison
equal
deleted
inserted
replaced
219:e5bcc8c9322e | 220:5f2ce627db3c |
---|---|
583 #endif /* SCTP_AUTO_ASCONF */ | 583 #endif /* SCTP_AUTO_ASCONF */ |
584 | 584 |
585 return 0; | 585 return 0; |
586 } | 586 } |
587 | 587 |
588 /* Add addresses from a list to an array, with filter on the flags */ | |
589 static int add_addresses_from_list_mask(uint8_t ** array, size_t * size, int * addr_count, int target_family, uint16_t port, struct fd_list * list, uint32_t mask, uint32_t val) | |
590 { | |
591 struct fd_list * li; | |
592 int to_add4 = 0; | |
593 int to_add6 = 0; | |
594 union { | |
595 uint8_t *buf; | |
596 sSA4 *sin; | |
597 sSA6 *sin6; | |
598 } ptr; | |
599 size_t sz; | |
600 | |
601 /* First, count the number of addresses to add */ | |
602 for (li = list->next; li != list; li = li->next) { | |
603 struct fd_endpoint * ep = (struct fd_endpoint *) li; | |
604 | |
605 /* Do the flag match ? */ | |
606 if ((val & mask) != (ep->flags & mask)) | |
607 continue; | |
608 | |
609 if (ep->sa.sa_family == AF_INET) { | |
610 to_add4 ++; | |
611 } else { | |
612 to_add6 ++; | |
613 } | |
614 } | |
615 | |
616 if ((to_add4 + to_add6) == 0) | |
617 return 0; /* nothing to do */ | |
618 | |
619 /* The size to add */ | |
620 if (target_family == AF_INET) { | |
621 sz = to_add4 * sizeof(sSA4); | |
622 } else { | |
623 #ifndef SCTP_USE_MAPPED_ADDRESSES | |
624 sz = (to_add4 * sizeof(sSA4)) + (to_add6 * sizeof(sSA6)); | |
625 #else /* SCTP_USE_MAPPED_ADDRESSES */ | |
626 sz = (to_add4 + to_add6) * sizeof(sSA6); | |
627 #endif /* SCTP_USE_MAPPED_ADDRESSES */ | |
628 } | |
629 | |
630 /* Now, (re)alloc the array to store the new addresses */ | |
631 CHECK_MALLOC( *array = realloc(*array, *size + sz) ); | |
632 | |
633 /* Finally, add the addresses */ | |
634 for (li = list->next; li != list; li = li->next) { | |
635 struct fd_endpoint * ep = (struct fd_endpoint *) li; | |
636 | |
637 /* Skip v6 addresses for v4 socket */ | |
638 if ((target_family == AF_INET) && (ep->sa.sa_family == AF_INET6)) | |
639 continue; | |
640 | |
641 /* Are the flags matching ? */ | |
642 if ((val & mask) != (ep->flags & mask)) | |
643 continue; | |
644 | |
645 /* Size of the new SA we are adding (array may contain a mix of sockaddr_in and sockaddr_in6) */ | |
646 #ifndef SCTP_USE_MAPPED_ADDRESSES | |
647 if (ep->sa.sa_family == AF_INET6) | |
648 #else /* SCTP_USE_MAPPED_ADDRESSES */ | |
649 if (target_family == AF_INET6) { | |
650 #endif /* SCTP_USE_MAPPED_ADDRESSES */ | |
651 sz = sizeof(sSA6); | |
652 else | |
653 sz = sizeof(sSA4); | |
654 | |
655 /* Place where we add the new address */ | |
656 ptr.buf = *array + *size; /* place of the new SA */ | |
657 | |
658 /* Update other information */ | |
659 *size += sz; | |
660 *addr_count += 1; | |
661 | |
662 /* And write the addr in the buffer */ | |
663 if (sz == sizeof(sSA4)) { | |
664 memcpy(ptr.buf, &ep->sin, sz); | |
665 ptr.sin->sin_port = port; | |
666 } else { | |
667 if (ep->sa.sa_family == AF_INET) { /* We must map the address */ | |
668 memset(ptr.buf, 0, sz); | |
669 ptr.sin6->sin6_family = AF_INET6; | |
670 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); | |
671 } else { | |
672 memcpy(ptr.sin6, &ep->sin6, sz); | |
673 } | |
674 ptr.sin6->sin6_port = port; | |
675 } | |
676 } | |
677 | |
678 return 0; | |
679 } | |
680 | |
588 /* Create a socket server and bind it according to daemon s configuration */ | 681 /* Create a socket server and bind it according to daemon s configuration */ |
589 int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port ) | 682 int fd_sctp_create_bind_server( int * sock, int family, struct fd_list * list, uint16_t port ) |
590 { | 683 { |
591 int family; | |
592 int bind_default; | 684 int bind_default; |
593 | 685 |
594 TRACE_ENTRY("%p %p %hu", sock, list, port); | 686 TRACE_ENTRY("%p %i %p %hu", sock, family, list, port); |
595 CHECK_PARAMS(sock); | 687 CHECK_PARAMS(sock); |
596 | |
597 if (fd_g_config->cnf_flags.no_ip6) { | |
598 family = AF_INET; | |
599 } else { | |
600 family = AF_INET6; /* can create socket for both IP and IPv6 */ | |
601 } | |
602 | 688 |
603 /* Create the socket */ | 689 /* Create the socket */ |
604 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) ); | 690 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) ); |
605 | 691 |
606 /* Set pre-binding socket options, including number of streams etc... */ | 692 /* Set pre-binding socket options, including number of streams etc... */ |
630 CHECK_SYS( bind(*sock, &s.sa, sizeof(s)) ); | 716 CHECK_SYS( bind(*sock, &s.sa, sizeof(s)) ); |
631 | 717 |
632 } else { | 718 } else { |
633 /* Explicit endpoints to bind to from config */ | 719 /* Explicit endpoints to bind to from config */ |
634 | 720 |
635 union { | 721 sSA * sar = NULL; /* array of addresses */ |
636 sSA * sa; | 722 size_t sz = 0; /* size of the array */ |
637 sSA4 *sin; | 723 int count = 0; /* number of sock addr in the array */ |
638 sSA6 *sin6; | 724 |
639 uint8_t *buf; | 725 /* Create the array of configured addresses */ |
640 } ptr; | 726 CHECK_FCT( add_addresses_from_list_mask((void *)&sar, &sz, &count, family, port, list, EP_FL_CONF, EP_FL_CONF) ); |
641 union { | |
642 sSA * sa; | |
643 uint8_t * buf; | |
644 } sar; | |
645 int count = 0; /* number of sock addr in sar array */ | |
646 size_t offset = 0; | |
647 struct fd_list * li; | |
648 | |
649 sar.buf = NULL; | |
650 | |
651 /* Create a flat array from the list of configured addresses */ | |
652 for (li = list->next; li != list; li = li->next) { | |
653 struct fd_endpoint * ep = (struct fd_endpoint *)li; | |
654 size_t sz = 0; | |
655 | |
656 if (! (ep->flags & EP_FL_CONF)) | |
657 continue; | |
658 | |
659 count++; | |
660 | |
661 /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */ | |
662 #ifndef SCTP_USE_MAPPED_ADDRESSES | |
663 if (ep->sa.sa_family == AF_INET6) | |
664 #else /* SCTP_USE_MAPPED_ADDRESSES */ | |
665 if (family == AF_INET6) | |
666 #endif /* SCTP_USE_MAPPED_ADDRESSES */ | |
667 sz = sizeof(sSA6); | |
668 else | |
669 sz = sizeof(sSA4); | |
670 | |
671 /* augment sar to contain the additional info */ | |
672 CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz) ); | |
673 | |
674 ptr.buf = sar.buf + offset; /* place of the new SA */ | |
675 offset += sz; /* update to end of sar */ | |
676 | |
677 if (sz == sizeof(sSA4)) { | |
678 memcpy(ptr.buf, &ep->sin, sz); | |
679 ptr.sin->sin_port = htons(port); | |
680 } else { | |
681 if (ep->sa.sa_family == AF_INET) { /* We must map the address */ | |
682 memset(ptr.buf, 0, sz); | |
683 ptr.sin6->sin6_family = AF_INET6; | |
684 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); | |
685 } else { | |
686 memcpy(ptr.sin6, &ep->sin6, sz); | |
687 } | |
688 ptr.sin6->sin6_port = htons(port); | |
689 } | |
690 } | |
691 | 727 |
692 if (!count) { | 728 if (!count) { |
693 /* None of the addresses in the list came from configuration, we bind to default */ | 729 /* None of the addresses in the list came from configuration, we bind to default */ |
694 bind_default = 1; | 730 bind_default = 1; |
695 goto redo; | 731 goto redo; |
696 } | 732 } |
697 | 733 |
698 if (TRACE_BOOL(SCTP_LEVEL)) { | 734 if (TRACE_BOOL(SCTP_LEVEL)) { |
735 union { | |
736 sSA *sa; | |
737 uint8_t *buf; | |
738 } ptr; | |
699 int i; | 739 int i; |
700 ptr.buf = sar.buf; | 740 ptr.sa = sar; |
701 fd_log_debug("Calling sctp_bindx with the following address array:\n"); | 741 fd_log_debug("Calling sctp_bindx with the following address array:\n"); |
702 for (i = 0; i < count; i++) { | 742 for (i = 0; i < count; i++) { |
703 TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); | 743 TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); |
704 ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ; | 744 ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ; |
705 } | 745 } |
706 } | 746 } |
707 | 747 |
708 /* Bind to this array */ | 748 /* Bind to this array */ |
709 CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) ); | 749 CHECK_SYS( sctp_bindx(*sock, sar, count, SCTP_BINDX_ADD_ADDR) ); |
710 | 750 |
711 /* We don't need sar anymore */ | 751 /* We don't need sar anymore */ |
712 free(sar.buf); | 752 free(sar); |
713 } | 753 } |
714 | 754 |
715 /* Now, the server is bound, set remaining sockopt */ | 755 /* Now, the server is bound, set remaining sockopt */ |
716 CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) ); | 756 CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) ); |
717 | 757 |
742 TRACE_ENTRY("%d", sock); | 782 TRACE_ENTRY("%d", sock); |
743 CHECK_SYS( listen(sock, 5) ); | 783 CHECK_SYS( listen(sock, 5) ); |
744 return 0; | 784 return 0; |
745 } | 785 } |
746 | 786 |
747 /* Add addresses from the list that match the flags to the array */ | |
748 static int add_addresses_from_list_mask(uint8_t ** array, int * count, size_t * offset, uint16_t port, struct fd_list * list, uint32_t mask, uint32_t val) | |
749 { | |
750 size_t sz; | |
751 struct fd_list * li; | |
752 union { | |
753 uint8_t *buf; | |
754 sSA4 *sin; | |
755 sSA6 *sin6; | |
756 } ptr; | |
757 | |
758 for (li = list->next; li != list; li = li->next) { | |
759 struct fd_endpoint * ep = (struct fd_endpoint *) li; | |
760 | |
761 /* Do the flag match ? */ | |
762 if ((val & mask) != (ep->flags & mask)) | |
763 continue; | |
764 | |
765 /* We add this endpoint at the end of array */ | |
766 (*count)++; | |
767 | |
768 /* Size of the new SA we are adding (array may contain a mix of sockaddr_in and sockaddr_in6) */ | |
769 #ifndef SCTP_USE_MAPPED_ADDRESSES | |
770 if (ep->sa.sa_family == AF_INET6) | |
771 #else /* SCTP_USE_MAPPED_ADDRESSES */ | |
772 if (family == AF_INET6) | |
773 #endif /* SCTP_USE_MAPPED_ADDRESSES */ | |
774 sz = sizeof(sSA6); | |
775 else | |
776 sz = sizeof(sSA4); | |
777 | |
778 /* augment array to contain the additional info */ | |
779 CHECK_MALLOC( *array = realloc(*array, (*offset) + sz) ); | |
780 | |
781 ptr.buf = *array + *offset; /* place of the new SA */ | |
782 (*offset) += sz; /* update to end of sar */ | |
783 | |
784 if (sz == sizeof(sSA4)) { | |
785 memcpy(ptr.buf, &ep->sin, sz); | |
786 ptr.sin->sin_port = port; | |
787 } else { | |
788 if (ep->sa.sa_family == AF_INET) { /* We must map the address */ | |
789 memset(ptr.buf, 0, sz); | |
790 ptr.sin6->sin6_family = AF_INET6; | |
791 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); | |
792 } else { | |
793 memcpy(ptr.sin6, &ep->sin6, sz); | |
794 } | |
795 ptr.sin6->sin6_port = port; | |
796 } | |
797 } | |
798 | |
799 return 0; | |
800 } | |
801 | |
802 /* Create a client socket and connect to remote server */ | 787 /* Create a client socket and connect to remote server */ |
803 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list ) | 788 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list ) |
804 { | 789 { |
805 int family; | 790 int family; |
806 int count = 0; | |
807 size_t offset = 0; | |
808 union { | 791 union { |
809 uint8_t *buf; | 792 uint8_t *buf; |
810 sSA *sa; | 793 sSA *sa; |
811 } sar; | 794 } sar; |
795 size_t size = 0; | |
796 int count = 0; | |
812 int ret; | 797 int ret; |
813 | 798 |
814 sar.buf = NULL; | 799 sar.buf = NULL; |
815 | 800 |
816 TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list); | 801 TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list); |
830 | 815 |
831 /* Set the socket options */ | 816 /* Set the socket options */ |
832 CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail ); | 817 CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail ); |
833 | 818 |
834 /* Create the array of addresses, add first the configured addresses, then the discovered, then the other ones */ | 819 /* Create the array of addresses, add first the configured addresses, then the discovered, then the other ones */ |
835 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF, EP_FL_CONF ), goto fail ); | 820 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF, EP_FL_CONF ), goto fail ); |
836 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF | EP_FL_DISC, EP_FL_DISC ), goto fail ); | 821 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF | EP_FL_DISC, EP_FL_DISC ), goto fail ); |
837 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF | EP_FL_DISC, 0 ), goto fail ); | 822 CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &size, &count, family, htons(port), list, EP_FL_CONF | EP_FL_DISC, 0 ), goto fail ); |
838 | 823 |
839 /* Try connecting */ | 824 /* Try connecting */ |
840 if (TRACE_BOOL(FULL)) { | 825 if (TRACE_BOOL(FULL)) { |
841 TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted) :", count); | 826 TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted) :", count); |
842 /* Dump the SAs */ | 827 /* Dump the SAs */ |
857 #ifdef SCTP_CONNECTX_4_ARGS | 842 #ifdef SCTP_CONNECTX_4_ARGS |
858 CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count, NULL), { ret = errno; goto fail; } ); | 843 CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count, NULL), { ret = errno; goto fail; } ); |
859 #else /* SCTP_CONNECTX_4_ARGS */ | 844 #else /* SCTP_CONNECTX_4_ARGS */ |
860 CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } ); | 845 CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } ); |
861 #endif /* SCTP_CONNECTX_4_ARGS */ | 846 #endif /* SCTP_CONNECTX_4_ARGS */ |
862 | |
863 /***************** | |
864 BUG : received "EINVAL" at reconnection attempt... Should probably filter what is in that list ! | |
865 *****************/ | |
866 | 847 |
867 free(sar.buf); sar.buf = NULL; | 848 free(sar.buf); sar.buf = NULL; |
868 | 849 |
869 /* Set the remaining sockopts */ | 850 /* Set the remaining sockopts */ |
870 CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail_deco ); | 851 CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail_deco ); |
934 union { | 915 union { |
935 sSA *sa; | 916 sSA *sa; |
936 uint8_t *buf; | 917 uint8_t *buf; |
937 } ptr; | 918 } ptr; |
938 | 919 |
939 sSA * data; | 920 sSA * data = NULL; |
940 int count; | 921 int count; |
941 | 922 |
942 TRACE_ENTRY("%d %p", sock, list); | 923 TRACE_ENTRY("%d %p", sock, list); |
943 CHECK_PARAMS(list); | 924 CHECK_PARAMS(list); |
944 | 925 |
951 switch (ptr.sa->sa_family) { | 932 switch (ptr.sa->sa_family) { |
952 case AF_INET: sl = sizeof(sSA4); break; | 933 case AF_INET: sl = sizeof(sSA4); break; |
953 case AF_INET6: sl = sizeof(sSA6); break; | 934 case AF_INET6: sl = sizeof(sSA6); break; |
954 default: | 935 default: |
955 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family); | 936 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family); |
937 TRACE_DEBUG_BUFFER(NONE, "DEBUG: Parsed data : [", data, ptr.buf - (uint8_t *)data, "]" ); | |
938 TRACE_DEBUG(NONE, "DEBUG: Remaining %d addresses to parse in :", count) | |
939 TRACE_DEBUG_BUFFER(NONE, "DEBUG: Unable to parse [", ptr.buf, count * sizeof(sSA), "]" ); | |
940 goto stop; | |
956 } | 941 } |
957 | 942 |
958 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); | 943 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); |
959 ptr.buf += sl; | 944 ptr.buf += sl; |
960 count --; | 945 count --; |
961 } | 946 } |
962 | 947 stop: |
963 /* Free the list */ | 948 /* Free the list */ |
964 sctp_freeladdrs(data); | 949 sctp_freeladdrs(data); |
965 | 950 |
966 /* Now get the primary address, the add function will take care of merging with existing entry */ | 951 /* Now get the primary address, the add function will take care of merging with existing entry */ |
967 { | 952 { |
991 | 976 |
992 /* Read the list on the socket */ | 977 /* Read the list on the socket */ |
993 CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data) ); | 978 CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data) ); |
994 ptr.sa = data; | 979 ptr.sa = data; |
995 | 980 |
996 TRACE_DEBUG(NONE, "DEBUG: count = %d", count); | |
997 TRACE_DEBUG_BUFFER(NONE, "DEBUG: data = ", ptr.buf, count * sizeof(sSA4), "" ); | |
998 | |
999 while (count) { | 981 while (count) { |
1000 socklen_t sl; | 982 socklen_t sl; |
1001 switch (ptr.sa->sa_family) { | 983 switch (ptr.sa->sa_family) { |
1002 case AF_INET: sl = sizeof(sSA4); break; | 984 case AF_INET: sl = sizeof(sSA4); break; |
1003 case AF_INET6: sl = sizeof(sSA6); break; | 985 case AF_INET6: sl = sizeof(sSA6); break; |
1004 default: | 986 default: |
1005 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d, skip", ptr.sa->sa_family); | 987 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d, skip", ptr.sa->sa_family); |
1006 goto next; | 988 TRACE_DEBUG_BUFFER(NONE, "DEBUG: Parsed data : [", data, ptr.buf - (uint8_t *)data, "]" ); |
989 TRACE_DEBUG(NONE, "DEBUG: Remaining %d addresses to parse in :", count) | |
990 TRACE_DEBUG_BUFFER(NONE, "DEBUG: Unable to parse [", ptr.buf, count * sizeof(sSA), "]" ); | |
991 goto stop; | |
1007 } | 992 } |
1008 | 993 |
1009 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); | 994 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); |
1010 ptr.buf += sl; | 995 ptr.buf += sl; |
1011 count --; | 996 count --; |
1012 } | 997 } |
1013 next: | 998 stop: |
1014 /* Free the list */ | 999 /* Free the list */ |
1015 sctp_freepaddrs(data); | 1000 sctp_freepaddrs(data); |
1016 | 1001 |
1017 /* Now get the primary address, the add function will take care of merging with existing entry */ | 1002 /* Now get the primary address, the add function will take care of merging with existing entry */ |
1018 { | 1003 { |