Changeset 25:67ca08d5bc48 in freeDiameter for freeDiameter/sctp.c
- Timestamp:
- Oct 26, 2009, 4:00:49 PM (15 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/sctp.c
r24 r25 35 35 36 36 #include "fD.h" 37 #include "cnxctx.h" 38 37 39 #include <netinet/sctp.h> 38 40 #include <sys/uio.h> 41 42 /* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */ 43 #ifndef CMSG_BUF_LEN 44 #define CMSG_BUF_LEN 1024 45 #endif /* CMSG_BUF_LEN */ 39 46 40 47 /* Pre-binding socket options -- # streams read in config */ … … 744 751 745 752 /* Retrieve streams information from a connected association -- optionaly provide the primary address */ 746 int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary )753 int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary ) 747 754 { 748 755 struct sctp_status status; … … 776 783 #endif /* DEBUG_SCTP */ 777 784 778 *in = (int)status.sstat_instrms;779 *out = (int)status.sstat_outstrms;785 *in = status.sstat_instrms; 786 *out = status.sstat_outstrms; 780 787 781 788 if (primary) … … 893 900 } 894 901 902 /* Send a buffer over a specified stream */ 903 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len) 904 { 905 struct msghdr mhdr; 906 struct iovec iov; 907 struct { 908 struct cmsghdr hdr; 909 struct sctp_sndrcvinfo sndrcv; 910 } anci; 911 ssize_t ret; 912 913 TRACE_ENTRY("%d %hu %p %g", sock, strid, buf, len); 914 915 memset(&mhdr, 0, sizeof(mhdr)); 916 memset(&iov, 0, sizeof(iov)); 917 memset(&anci, 0, sizeof(anci)); 918 919 /* IO Vector: message data */ 920 iov.iov_base = buf; 921 iov.iov_len = len; 922 923 /* Anciliary data: specify SCTP stream */ 924 anci.hdr.cmsg_len = sizeof(anci); 925 anci.hdr.cmsg_level = IPPROTO_SCTP; 926 anci.hdr.cmsg_type = SCTP_SNDRCV; 927 anci.sndrcv.sinfo_stream = strid; 928 /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */ 929 930 /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */ 931 932 mhdr.msg_iov = &iov; 933 mhdr.msg_iovlen = 1; 934 935 mhdr.msg_control = &anci; 936 mhdr.msg_controllen = sizeof(anci); 937 938 #ifdef DEBUG_SCTP 939 TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock); 940 #endif /* DEBUG_SCTP */ 941 942 CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) ); 943 ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */ 944 945 return 0; 946 } 947 948 /* Receive the next data from the socket, or next notification */ 949 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event) 950 { 951 ssize_t ret = 0; 952 struct msghdr mhdr; 953 char ancidata[ CMSG_BUF_LEN ]; 954 struct iovec iov; 955 uint8_t *data = NULL; 956 size_t bufsz = 0, datasize = 0; 957 size_t mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */ 958 959 TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event); 960 CHECK_PARAMS( (sock > 0) && buf && len && event ); 961 962 /* Cleanup out parameters */ 963 *buf = NULL; 964 *len = 0; 965 *event = 0; 966 967 /* Prepare header for receiving message */ 968 memset(&mhdr, 0, sizeof(mhdr)); 969 mhdr.msg_iov = &iov; 970 mhdr.msg_iovlen = 1; 971 mhdr.msg_control = &ancidata; 972 mhdr.msg_controllen = sizeof(ancidata); 973 974 /* We will loop while all data is not received. */ 975 incomplete: 976 if (datasize == bufsz) { 977 /* The buffer is full, enlarge it */ 978 bufsz += mempagesz; 979 CHECK_MALLOC( data = realloc(data, bufsz) ); 980 } 981 /* the new data will be received following the preceding */ 982 memset(&iov, 0, sizeof(iov)); 983 iov.iov_base = data + datasize ; 984 iov.iov_len = bufsz - datasize; 985 986 /* Receive data from the socket */ 987 pthread_cleanup_push(free, data); 988 ret = recvmsg(sock, &mhdr, 0); 989 pthread_cleanup_pop(0); 990 991 /* Handle errors */ 992 if (ret <= 0) { /* Socket is closed, or an error occurred */ 993 CHECK_SYS_DO(ret, /* to log in case of error */); 994 free(data); 995 *event = FDEVP_CNX_ERROR; 996 return 0; 997 } 998 999 /* Update the size of data we received */ 1000 datasize += ret; 1001 1002 /* SCTP provides an indication when we received a full record; loop if it is not the case */ 1003 if ( ! (mhdr.msg_flags & MSG_EOR) ) { 1004 goto incomplete; 1005 } 1006 1007 /* Handle the case where the data received is a notification */ 1008 if (mhdr.msg_flags & MSG_NOTIFICATION) { 1009 union sctp_notification * notif = (union sctp_notification *) data; 1010 1011 switch (notif->sn_header.sn_type) { 1012 1013 case SCTP_ASSOC_CHANGE: 1014 #ifdef DEBUG_SCTP 1015 TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification"); 1016 TRACE_DEBUG(FULL, " state : %hu", notif->sn_assoc_change.sac_state); 1017 TRACE_DEBUG(FULL, " error : %hu", notif->sn_assoc_change.sac_error); 1018 TRACE_DEBUG(FULL, " instr : %hu", notif->sn_assoc_change.sac_inbound_streams); 1019 TRACE_DEBUG(FULL, " outstr : %hu", notif->sn_assoc_change.sac_outbound_streams); 1020 #endif /* DEBUG_SCTP */ 1021 1022 *event = FDEVP_CNX_EP_CHANGE; 1023 break; 1024 1025 case SCTP_PEER_ADDR_CHANGE: 1026 #ifdef DEBUG_SCTP 1027 TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification"); 1028 TRACE_DEBUG_sSA(FULL, " intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" ); 1029 TRACE_DEBUG(FULL, " state : %d", notif->sn_paddr_change.spc_state); 1030 TRACE_DEBUG(FULL, " error : %d", notif->sn_paddr_change.spc_error); 1031 #endif /* DEBUG_SCTP */ 1032 1033 *event = FDEVP_CNX_EP_CHANGE; 1034 break; 1035 1036 case SCTP_SEND_FAILED: 1037 #ifdef DEBUG_SCTP 1038 TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification"); 1039 TRACE_DEBUG(FULL, " len : %hu", notif->sn_send_failed.ssf_length); 1040 TRACE_DEBUG(FULL, " err : %d", notif->sn_send_failed.ssf_error); 1041 #endif /* DEBUG_SCTP */ 1042 1043 *event = FDEVP_CNX_ERROR; 1044 break; 1045 1046 case SCTP_REMOTE_ERROR: 1047 #ifdef DEBUG_SCTP 1048 TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification"); 1049 TRACE_DEBUG(FULL, " err : %hu", ntohs(notif->sn_remote_error.sre_error)); 1050 TRACE_DEBUG(FULL, " len : %hu", ntohs(notif->sn_remote_error.sre_length)); 1051 #endif /* DEBUG_SCTP */ 1052 1053 *event = FDEVP_CNX_ERROR; 1054 break; 1055 1056 case SCTP_SHUTDOWN_EVENT: 1057 #ifdef DEBUG_SCTP 1058 TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification"); 1059 #endif /* DEBUG_SCTP */ 1060 1061 *event = FDEVP_CNX_ERROR; 1062 break; 1063 1064 default: 1065 TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type); 1066 *event = FDEVP_CNX_ERROR; 1067 } 1068 1069 free(data); 1070 return 0; 1071 } 1072 1073 /* From this point, we have received a message */ 1074 *event = FDEVP_CNX_MSG_RECV; 1075 *buf = data; 1076 *len = datasize; 1077 1078 if (strid) { 1079 struct cmsghdr *hdr; 1080 struct sctp_sndrcvinfo *sndrcv; 1081 1082 /* Handle the anciliary data */ 1083 for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) { 1084 1085 /* We deal only with anciliary data at SCTP level */ 1086 if (hdr->cmsg_level != IPPROTO_SCTP) { 1087 TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level); 1088 continue; 1089 } 1090 1091 /* Also only interested in SCTP_SNDRCV message for the moment */ 1092 if (hdr->cmsg_type != SCTP_SNDRCV) { 1093 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type); 1094 continue; 1095 } 1096 1097 sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr); 1098 #ifdef DEBUG_SCTP 1099 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV"); 1100 TRACE_DEBUG(FULL, " sinfo_stream : %hu", sndrcv->sinfo_stream); 1101 TRACE_DEBUG(FULL, " sinfo_ssn : %hu", sndrcv->sinfo_ssn); 1102 TRACE_DEBUG(FULL, " sinfo_flags : %hu", sndrcv->sinfo_flags); 1103 /* TRACE_DEBUG(FULL, " sinfo_pr_policy : %hu", sndrcv->sinfo_pr_policy); */ 1104 TRACE_DEBUG(FULL, " sinfo_ppid : %u" , sndrcv->sinfo_ppid); 1105 TRACE_DEBUG(FULL, " sinfo_context : %u" , sndrcv->sinfo_context); 1106 /* TRACE_DEBUG(FULL, " sinfo_pr_value : %u" , sndrcv->sinfo_pr_value); */ 1107 TRACE_DEBUG(FULL, " sinfo_tsn : %u" , sndrcv->sinfo_tsn); 1108 TRACE_DEBUG(FULL, " sinfo_cumtsn : %u" , sndrcv->sinfo_cumtsn); 1109 #endif /* DEBUG_SCTP */ 1110 1111 *strid = sndrcv->sinfo_stream; 1112 } 1113 } 1114 1115 return 0; 1116 }
Note: See TracChangeset
for help on using the changeset viewer.