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 {
"Welcome to our mercurial repository"