Navigation


Changeset 25:67ca08d5bc48 in freeDiameter for freeDiameter/sctp.c


Ignore:
Timestamp:
Oct 26, 2009, 4:00:49 PM (15 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Completed connection context files

File:
1 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/sctp.c

    r24 r25  
    3535
    3636#include "fD.h"
     37#include "cnxctx.h"
     38
    3739#include <netinet/sctp.h>
    3840#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 */
    3946
    4047/* Pre-binding socket options -- # streams read in config */
     
    744751
    745752/* 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 )
     753int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )
    747754{
    748755        struct sctp_status status;
     
    776783        #endif /* DEBUG_SCTP */
    777784       
    778         *in = (int)status.sstat_instrms;
    779         *out = (int)status.sstat_outstrms;
     785        *in = status.sstat_instrms;
     786        *out = status.sstat_outstrms;
    780787       
    781788        if (primary)
     
    893900}
    894901
     902/* Send a buffer over a specified stream */
     903int 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 */
     949int 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. */
     975incomplete:
     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.