SCTP

Stream Control Transmission Protocol

Overview

State Transitions

Dr. Wahab Examples

tcpServerSctp  &  tcpClientSctp

udpServerSctp & udpClientSctp

 

Basic Examples

sctp_serverQ  &  sctp_clientQ

sctp_serverS   &  sctp_clientS

 

Advanced Examples

sctp_server  & sctp_client

 

Advanced Features

Autoclosing

Peeloff, sctp_serverQpeel

Streems

 

 


v   Useful Documents:

·       PaulAmerPaper.pdf

·       SCTP_tutorial.ppt

·       Stream Control Transmission Protocol (SCTP) Part2.mht

·       Stream Control Transmission Protocol (SCTP).mht

·       http_www.ibm.pdf

·       rfc2960SCTP.html

 

 


v     Overview:

 

·       Provides an association between a server and one or more clients.

·       An association is different from a connection, each entity may have more than one IP address (multi-home).

·       Each association has multiple independent streams.

·       SCTP is message oriented Protocol (like udp).

 

 

Association Establishment: (4-way handshake)


fig2-6-4way


Ta, Tz:     are tags.
J, K:
         are initial sequence numbers.
Cookie:
    contains state information to ensure association validity.

 


Association Termination:

 


http://www.cs.odu.edu/~cs779/spring06/lectures/sctp_lect_files/fig2-7-close.jpg

 

 

 


vSCTP State Transition Diagram:

sctpState

 


Watching the packets:

fig2-9-exchange

 


SCTP Options:

·      Dynamic address extension (add/delete IP address from an association).

·      Partial reliability extension (limit the retransmission of data).

 

 

Protocol Usage:

http://www.cs.odu.edu/~cs779/spring06/lectures/sctp_lect_files/fig2-19-protocol-usage.jpg

 

 

 

 

SCTP  Examples

 

All the examples are under:

http://www.cs.odu.edu/~cs779/sctpSolaries10/

The programs can compile and run on our “something” hosts:

·      something (128.82.4.210)

·      somethingelse (128.82.4.120)

·      somethingmore (128.82.4.209)

And the “fast” hosts, e.g:

·      capella (128.82.4.118)

·      antares (128.82.4.98)

·      procyon (128.82.4.170)

 

 


vModifications of Dr. Wahab’s Simple Examples

 

ê   tcpServerSctp.c  (Modified from tcpServer.c )



#include "def"
main()
{
   int sd, psd;
   struct   sockaddr_in name;
   char   buf[1024];
   int    cc;

   sd = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP);


    name.sin_family = AF_INET;
   name.sin_addr.s_addr = htonl(INADDR_ANY);
   name.sin_port = htons(10111);
   bind( sd, (SA *) &name, sizeof(name) );
   listen(sd,1);
   psd = accept(sd, 0, 0);
   close(sd);
   for(;;) {

          cc=recv(psd,buf,sizeof(buf), 0) ;
          if (cc == 0) exit (0);
          buf[cc] = NULL;
          printf("message received: %s\n", buf);

   }

}

 

 

 

ê   tcpClientSctp.c (Modified from tcpClient.c )





main(argc, argv )
int argc;
char *argv[];

{
     int     sd;
     struct          sockaddr_in server;
     struct  hostent *hp, *gethostbyname();

    
sd = socket (AF_INET,SOCK_STREAM,IPPROTO_SCTP);

     server.sin_family = AF_INET;
     hp = gethostbyname(argv[1]);
     bcopy ( hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
     server.sin_port = htons(10111);
     connect(sd, (SA *) &server, sizeof(server));
     for (;;) {
            send(sd, "HI", 2, 0 );
           printf("sent HI\n");
           sleep(2);
    }
}

 

ü Testing 

 

% cd   ~/public_html/sctpSolries10


something%  tcpServerSctp    //it uses port  10111


somethingmore%  tcpClientSctp  something

 

ê   udpServerSctp.c  (Modified from udpServer.c)

main()
{
    

     server.sin_family = AF_INET;
     server.sin_addr.s_addr = htonl(INADDR_ANY);
     server.sin_port = htons(10111);

    
sd = socket (AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);

     bind( sd, (SA *) &server, sizeof(server));

     len = sizeof(struct sockaddr_in);

 

/* use recvmsg, or recfrom
rc = sctp_recvmsg(sd, buf, sizeof(buf), (SA *)&cliaddr, &len, &sri, &msg_flags);
*/                        
rc = recvfrom (sd, buf, sizeof(buf), 0, (SA *) &cliaddr, &len);
buf[rc]= (char) NULL;
printf("Received: %s\n", buf);

 

       }

 

ê   udpClientSctp.c      (Modified from udpClient.c)

main(argc, argv )
int argc;
char *argv[];
{
         

         
sd = socket (AF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);

 

          server.sin_family = AF_INET;
          hp = gethostbyname(argv[1]);
          bcopy ( hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
          server.sin_port = htons(10111);


for (;;) {
    sctp_sendmsg(sd, "HI", 2, (SA *)&server, sizeof(server), 0, 0, 0, 0, 0);

/* use sendto or sendmsg
    sendto(sd, "HI",2, 0, (SA *) &server, sizeof(server));
*/

    printf("sent HI\n");
    sleep(2);
}

      }

 

 

ü Testing  

 

% cd   ~/public_html/sctpSolries10


something % udpServerSctp    //it uses port  10111


somethingmore % udpClientSctp  something

 

*                 Amazing!  
The marriage of tcp & udp

 

something % udpServerSctp   

somethingmore % tcpClientSctp  something

also try:

something % tcpServerSctp  

somethingmore % udpClientSctp  something

 

 


v   Basic Echo Servers and Clients

 

ª   Echo Servers:

msg structure used in sendmsg and recvmsg calls:

 

msgHeader

 
 

ê   sctp_serverQ.c

 

#define MAXIDLETIME     100


static void
print_src (int fd, sctp_assoc_t assoc_id)
{
        if (sctp_opt_info(fd, assoc_id, SCTP_STATUS, &sstat, &ulen) < 0) {
                        perror("sctp_opt_info()");
                        return;
        }
        spinfo = &sstat.sstat_primary;

        s_in = (struct sockaddr_in *)&spinfo->spinfo_address;
        inet_ntop(AF_INET, &s_in->sin_addr, tmpname, sizeof (tmpname));
        port = ntohs(s_in->sin_port);
        printf("Msg from %d: %s/%d\n", assoc_id, tmpname, port);
}

int
main(int argc, char **argv)
{

 

               
               
echo_s = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);

                bzero(&laddr, sizeof (laddr));
                laddr.sin_family = AF_INET;
                laddr.sin_port = htons(atoi(argv[1]));
               
if (bind(echo_s, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) {
                                perror("bind(ECHO_PORT)");
                                exit(1);
                }
               
listen(echo_s, 1) ;

               

                bzero(&ses, sizeof (ses));
                ses.sctp_data_io_event = 1;
                setsockopt(echo_s, IPPROTO_SCTP, SCTP_EVENTS, &ses, sizeof (ses));

                FD_ZERO(&rset);

               
while (1) {
                                FD_SET(echo_s, &rset);
                               
select(5, &rset, NULL, NULL, NULL);
                                if (FD_ISSET(echo_s, &rset) ) {
                                                bzero(cdata, sizeof (cdata));
                                                bzero(&mhdr, sizeof (mhdr));
                                                mhdr.msg_name = &from;
                                                mhdr.msg_namelen = fromlen;
                                                mhdr.msg_iov = &iov;
                                                mhdr.msg_iovlen = 1;
                                                mhdr.msg_control = cdata;
                                                mhdr.msg_controllen = sizeof (cdata);
                                                iov.iov_base = data;
                                                iov.iov_len = sizeof (data);
                                                cmsg = (struct cmsghdr *)cdata;
                                                sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);

                                               
if ((ret = recvmsg(echo_s, &mhdr, MSG_DONTWAIT)) < 0) {
                                                                perror("recvmsg()");
                                                }
                                                if (mhdr.msg_controllen) {
                                                               
print_src (echo_s, sinfo->sinfo_assoc_id);
                                                }
                                                /* echo back */
                                                iov.iov_len = ret;
                                               
if (sendmsg(echo_s, &mhdr, MSG_DONTWAIT) < 0) {
                                                                perror("sendmsg()");
                                                }
                                                printf("received:");
                                                fflush(stdout);
                                                write(1, data, ret);
                                }
                }
}

 

 

 

ê  sctp_serverS.c

 

It is the same as tcpservselect01.c

 

The only difference is that:

 

listenfd = Socket(AF_INET, SOCK_STREAM, 0);

 

change to:

 

listenfd = Socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP );

 

 
 

ª   Echo Clients:



êsctp_clientQ.c

 

 

#define MAXIDLETIME     1000

#define   BUFLEN  1024


static void
print_src(int fd, sctp_assoc_t assoc_id)
{
}

int echo_s;
struct sockaddr_in laddr;

int
main(int argc, char **argv)
{
     lport = atoi(argv[1]);
     rport = atoi(argv[3]);

     bzero(&laddr, sizeof (laddr));
     laddr.sin_family = AF_INET;
     laddr.sin_addr.s_addr = INADDR_ANY;
     laddr.sin_port = htons(lport);

    
CreateSocket();

    
     bzero(&toaddr, sizeof (toaddr));
     hp = getipnodebyname(argv[2], AF_INET, AI_DEFAULT, &error);
     if (hp == NULL) {
                     fprintf(stderr, "host not found\n");
                     exit(1);
     }
     toaddr.sin_family = AF_INET;
     toaddr.sin_addr.s_addr = *(ipaddr_t *)hp->h_addr_list[0];
     toaddr.sin_port = htons(rport);

     bzero(&ses, sizeof (ses));
     ses.sctp_data_io_event = 1;
     setsockopt(echo_s, IPPROTO_SCTP, SCTP_EVENTS, &ses, sizeof (ses));

     FD_ZERO(&rset);

    
while (1) {

                     FD_SET(echo_s, &rset);
                     FD_SET(0, &rset);
                    
select(5, &rset, NULL, NULL, NULL);
                     if (FD_ISSET (echo_s, &rset)) {
                                     bzero(cdata, sizeof (cdata));
                                     bzero(&In_mhdr, sizeof (In_mhdr));
                                     In_mhdr.msg_name = &from;
                                     In_mhdr.msg_namelen = fromlen;
                                     In_mhdr.msg_iov = &iov;
                                     In_mhdr.msg_iovlen = 1;
                                     In_mhdr.msg_control = cdata;
                                     In_mhdr.msg_controllen = sizeof (cdata);
                                     iov.iov_base = data;
                                     iov.iov_len = sizeof (data);
                                     cmsg = (struct cmsghdr *)cdata;
                                     sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);

                                    
if ((ret = recvmsg(echo_s, &In_mhdr, MSG_DONTWAIT)) < 0) {
                                                     perror("recvmsg()");
                                     }
                                     if (In_mhdr.msg_controllen) {
                                                    
print_src(echo_s, sinfo->sinfo_assoc_id);
                                     }
                        printf("got back: "); fflush (stdout);
                                     write(1, data, ret);

                     }
                    
if (FD_ISSET (0, &rset)) {
                                     bzero(cdata, sizeof (cdata));
                                     bzero(&Out_mhdr, sizeof (Out_mhdr));
                                     Out_mhdr.msg_name = &toaddr;
                                     Out_mhdr.msg_namelen = tolen;
                                     Out_mhdr.msg_iov = &iov;
                                     Out_mhdr.msg_iovlen = 1;
                                     Out_mhdr.msg_control = cdata;
                                     Out_mhdr.msg_controllen = sizeof (cdata);
                                     iov.iov_base = data;
                                     iov.iov_len = sizeof (data);
                                     cmsg = (struct cmsghdr *)cdata;
                                     sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);

                                     ret = read(0, data, BUFLEN);
                        printf("data input: "); fflush(stdout);
                        write (1, data, ret);
                                     iov.iov_len = ret;
                                    
if (sendmsg(echo_s, &Out_mhdr, MSG_DONTWAIT) < 0) {
                                                     perror("sendmsg()");
                                     }
                     }
     }
}
CreateSocket()
{

    
echo_s = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);


    if (bind(echo_s, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) {
                perror("bind(ECHO_PORT)");
                exit(1);
    }
}

 

 

 

 

êsctp_clientS.c

 


int
main(int argc, char **argv)
{

        bzero(&dest, sizeof (dest));
        hp = getipnodebyname(argv[1], AF_INET, AI_DEFAULT, &error);
        if (hp == NULL) {
                fprintf(stderr, "host not found\n");
                exit(1);
        }
               port = atoi(argv[2]);
        dest.sin_family = AF_INET;
        dest.sin_addr.s_addr = *(ipaddr_t *)hp->h_addr_list[0];
        dest.sin_port = htons(port);



            
s = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);

            
if (connect(s, (struct sockaddr *)&dest, sizeof (dest)) < 0) {
                                             perror("connect");
                                             exit(1);
             }


        bzero(pfds, sizeof (pfds));
        pfds[0].fd = 0;
        pfds[0].events = POLLIN;
        pfds[1].fd = s;
        pfds[1].events = POLLIN;

       
while (1) {
                tmp = poll(pfds, 2, INFTIM);
                if (tmp < 0) {
                        perror("poll()");
                        exit(1);
                }
                for (i = 0; i < 2; i++) {
                        if (tmp == 0) {
                                continue;
                        }
                        
if (pfds[i].revents) {
                                tmp = read(pfds[i].fd, data, sizeof (data));
                                printf("got from %d\n", pfds[i].fd); fflush(stdout);
                                if (tmp < 0) {
                                        perror("read()");
                                        exit(1);
                                } else if (tmp == 0) {
                                        exit(0);
                                } else {
                                        
if (write(pfds[(i + 1) % 2].fd, data, tmp) < 0) {
                                                perror("write()");
                                                exit(1);
                                        }
/* write to 0 is the same as write to 1! */
                                }
                        }
                }
        }
        return (0);
}

 

ª   Testing   sctp_serverQ:

 

% cd   ~/public_html/sctpSolries10


something % sctp_serverQ 10111  


somethingmore % sctp_clientQ 1234 something 10111

somethingmore % sctp_clientS  something 10111 

 

ª   Testing   sctp_serverS:

 

% cd   ~/public_html/sctpSolries10


something % sctp_serverS    10111


somethingmore % sctp_clientQ 1234 something 10111

somethingmore % sctp_clientS  something  10111

 

 

 

v Advanced  SCTP  Examples

MultiFunction   Server:

êsctp_server.c


#define    ECHO_PORT        1117

#define    CHARGEN_PORT                1118

#define    DISCARD_PORT  1119

#define    MAXCONN                          64

#define    MAXIDLETIME   30

static void
print_src(int fd, sctp_assoc_t assoc_id)
{
                struct sctp_status sstat;
                struct sctp_paddrinfo *spinfo;
                char tmpname[INET6_ADDRSTRLEN];
                unsigned int port;
                unsigned int ulen;

                bzero(&sstat, sizeof (sstat));

                ulen = sizeof (sstat);
                if (sctp_opt_info(fd, assoc_id, SCTP_STATUS, &sstat, &ulen) < 0) {
                                perror("sctp_opt_info()");
                                return;
                }
                spinfo = &sstat.sstat_primary;
                if (spinfo->spinfo_address.ss_family == AF_INET6) {
                                struct sockaddr_in6 *sin6;

                                sin6 = (struct sockaddr_in6 *)&spinfo->spinfo_address;
                                inet_ntop(AF_INET6, &sin6->sin6_addr, tmpname,
                                    sizeof (tmpname));
                                port = ntohs(sin6->sin6_port);
                } else if (spinfo->spinfo_address.ss_family == AF_INET) {
                                struct sockaddr_in *s_in;

                                s_in = (struct sockaddr_in *)&spinfo->spinfo_address;
                                inet_ntop(AF_INET, &s_in->sin_addr, tmpname, sizeof (tmpname));
                                port = ntohs(s_in->sin_port);
                } else {
                                sprintf(tmpname, "<Unknown name>");
                }
                printf("Msg from %d: %s/%d\n", assoc_id, tmpname, port);
}

int
main(int argc, char **argv)
{
                struct sigaction act;
                int echo_s, discard_s, chargen_s;
                struct pollfd pfds[MAXCONN + 3];
                struct sockaddr_in6 laddr;
                struct sctp_event_subscribe ses;
                int ret, nofds, i, j = 0;
                struct msghdr mhdr;
                struct iovec iov;
                char data[8192], chargen_data[128], *ch;
                char cdata[sizeof (struct sctp_sndrcvinfo) + sizeof (struct cmsghdr)];
                struct cmsghdr *cmsg;
                struct sctp_sndrcvinfo *sinfo;
                struct sctp_assoc_change *sac;
                struct sockaddr_in6 from;
                socklen_t fromlen = sizeof (struct sockaddr_in6);

                for (i = 0; i < sizeof (chargen_data); i++) {
                                for (;;) {
                                                if (isprint(j)) {
                                                                chargen_data[i] = j++;
                                                                break;
                                                }
                                                j++;
                                                if (j >= 128) {
                                                                j = 0;
                                                }
                                }
                }
                bzero(&act, sizeof (act));
                act.sa_sigaction = SIG_IGN;
                sigfillset(&act.sa_mask);
                if (sigaction(SIGPIPE, &act, NULL) < 0) {
                                perror("sigaction()");
                                exit(1);
                }

                /*
                 * Create sockets
                 */
               
echo_s = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);


          discard_s = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);


          chargen_s = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP);


                if ((echo_s < 0) || (discard_s < 0) || (chargen_s < 0)) {
                                perror("socket()");
                                exit(1);
                }

                i = 1;
                if (setsockopt(echo_s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)) < 0 ||
                    setsockopt(discard_s, SOL_SOCKET, SO_REUSEADDR, &i,
                                sizeof (i)) < 0 ||
                    setsockopt(chargen_s, SOL_SOCKET, SO_REUSEADDR, &i,
                                sizeof (i)) < 0) {
                                perror("setsockopt(SO_REUSEADDR)");
                                exit(1);
                }

          if (ioctl(chargen_s, FIONBIO, &i) < 0) {
                   perror("ioctl(FIONBIO)");
                   exit(1);
          }


                i = MAXIDLETIME;
                if (setsockopt(echo_s, IPPROTO_SCTP, SCTP_AUTOCLOSE, &i,
                                sizeof (i)) < 0 ||
                    setsockopt(discard_s, IPPROTO_SCTP, SCTP_AUTOCLOSE, &i,
                                sizeof (i)) < 0) {
                                perror("setsockopt(SCTP_AUTOCLOSE)");
                                exit(1);
                }

                /*
                 * Be prepared for incoming v4/v6 traffic
                 */
                bzero(&laddr, sizeof (laddr));
                laddr.sin6_family = AF_INET6;
                laddr.sin6_port = htons(ECHO_PORT);
                if (bind(echo_s, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) {
                                perror("bind(ECHO_PORT)");
                                exit(1);
                }
                laddr.sin6_port = htons(DISCARD_PORT);
                if (bind(discard_s, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) {
                                perror("bind(DISCARD_PORT)");
                                exit(1);
                }
                laddr.sin6_port = htons(CHARGEN_PORT);
                if (bind(chargen_s, (struct sockaddr *)&laddr, sizeof (laddr)) < 0) {
                                perror("bind(CHARGEN_PORT)");
                                exit(1);
                }

                /*
                 * Turn on association events for one of the sockets
                 */
                bzero(&ses, sizeof (ses));
                ses.sctp_data_io_event = 1;
                if (setsockopt(echo_s, IPPROTO_SCTP, SCTP_EVENTS, &ses,
                                sizeof (ses))) {
                                perror("setsockopt(SCTP_EVENTS)");
                                exit(1);
                }

                ses.sctp_association_event = 1;
                if (setsockopt(discard_s, IPPROTO_SCTP, SCTP_EVENTS, &ses,
                                sizeof (ses))) {
                                perror("setsockopt(SCTP_EVENTS)");
                                exit(1);
                }

                if (listen(echo_s, 5) < 0 ||
                    listen(discard_s, 5) < 0 ||
                    listen(chargen_s, 5) < 0) {
                                perror("listen()");
                                exit(1);
                }

                /*
                 * Start polling for incoming connections, messages
                 */
                bzero(pfds, sizeof (pfds));
                pfds[0].fd = echo_s;
                pfds[0].events = POLLIN|POLLRDNORM;
                pfds[1].fd = discard_s;
                pfds[1].events = POLLIN|POLLRDNORM;
                pfds[2].fd = chargen_s;
                pfds[2].events = POLLIN|POLLRDNORM;
                nofds = 3;

                while (1) {
                                ret = poll(pfds, nofds, -1);
                                if (ret < 0) {
                                                perror("poll()");
                                                exit(1);
                                }
                                if (ret == 0) {
                                                printf("Timeout?!?\n");
                                                continue;
                                }
                                for (i = 0; i < nofds; i++) {
                                                if (!pfds[i].revents) {
                                                                continue;
                                                }
                                                if (i < 2) {
                                                                /* 1-N sockets */
                                                                bzero(cdata, sizeof (cdata));
                                                                bzero(&mhdr, sizeof (mhdr));
                                                                mhdr.msg_name = &from;
                                                                mhdr.msg_namelen = fromlen;
                                                                mhdr.msg_iov = &iov;
                                                                mhdr.msg_iovlen = 1;
                                                                mhdr.msg_control = cdata;
                                                                mhdr.msg_controllen = sizeof (cdata);
                                                                iov.iov_base = data;
                                                                iov.iov_len = sizeof (data);
                                                                cmsg = (struct cmsghdr *)cdata;
                                                                sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);

                                                                if ((ret = recvmsg(pfds[i].fd, &mhdr,
                                                                                MSG_DONTWAIT)) < 0) {
                                                                                perror("recvmsg()");
                                                                }
                                                                if (mhdr.msg_controllen) {
                                                                                print_src(pfds[i].fd,
                                                                                    sinfo->sinfo_assoc_id);
                                                                }
                                                                if (i == 0) {
                                                                                /* echo */
                                                                                iov.iov_len = ret;
                                                                                /* should read until MSG_EOR */
                                                                                if (sendmsg(pfds[i].fd, &mhdr,
                                                                                                MSG_DONTWAIT) < 0) {
                                                                                                perror("sendmsg()");
                                                                                }
                                                                                continue;
                                                                }
                                                                /* discard */
                                                                if (mhdr.msg_flags & MSG_NOTIFICATION) {
                                                                                sac = (struct sctp_assoc_change *)data;
                                                                                if (sac->sac_type !=
                                                                                    SCTP_ASSOC_CHANGE) {
                                                                                                printf("Shouldn't happen!\n");
                                                                                                continue;
                                                                                }
                                                                                if (sac->sac_state == SCTP_COMM_UP) {
                                                                                                printf("New assoc, id: %d\n",
                                                                                                    sac->sac_assoc_id);
                                                                                } else if (sac->sac_state ==
                                                                                    SCTP_SHUTDOWN_COMP) {
                                                                                                printf("Assoc gone, id: %d\n",
                                                                                                    sac->sac_assoc_id);
                                                                                } else {
                                                                                                printf("Another event (%d) "
                                                                                                    "id:%d\n", sac->sac_state,
                                                                                                    sac->sac_assoc_id);
                                                                                }
                                                                                continue;
                                                                }
                                                                continue;
                                                }
                                                if (i == 2) {
                                                                /* chargen, incoming conn */
                                                                pfds[nofds].fd = accept(chargen_s, NULL, NULL);
                                                                if (pfds[nofds].fd < 0) {
                                                                                perror("accept()");
                                                                                continue;
                                                                }
                                                                pfds[nofds].events = POLLOUT;
                                                                nofds++;
                                                                continue;
                                                }
                                               
while ((ret = write(pfds[i].fd, chargen_data,   sizeof (chargen_data))) ==sizeof (chargen_data));
                                                if (ret < 0) {
                                                                if (errno == EAGAIN) {
                                                                                continue;
                                                                }
                                                                if (errno != EPIPE) {
                                                                                perror("write()");
                                                                }
                                                                close(pfds[i].fd);
                                                                pfds[i] = pfds[nofds - 1];
                                                                nofds--;
                                                                i--;
                                                }
                                }
                }
                return (0);
}

 

MultiFunction Client:

 

êsctp_client.c

 


int
main(int argc, char **argv)
{
                int s, af, tmp, i;
                struct in6_addr a6;
                struct in_addr a;
                struct hostent *hp;
                int port;
                char data[8192];
                struct sockaddr_in6 des6;
                struct sockaddr_in dest;
                struct pollfd pfds[2];

                if (argc < 3) {
                                printf("Usage %s desthost destport\n", argv[0]);
                                exit(1);
                }

                if (inet_pton(AF_INET6, argv[1], &a6) == 1) {
                                af = AF_INET6;
                } else if (inet_pton(AF_INET, argv[1], &a) == 1) {
                                af = AF_INET;
                } else if ((hp = getipnodebyname(argv[1], AF_INET6, 0,
                                                &tmp)) != NULL) {
                                af = AF_INET6;
                                bcopy(hp->h_addr_list[0], &a6, sizeof (a6));
                } else if ((hp = gethostbyname(argv[1])) != NULL) {
                                af = AF_INET;
                                bcopy(hp->h_addr_list[0], &a, sizeof (a));
                } else {
                                printf("Couldn't resolve hostname: %s\n", argv[1]);
                                exit(1);
                }

                port = atoi(argv[2]);
                if (!port) {
                                printf("Couldn't parse destination port: %s\n", argv[2]);
                                exit(1);
                }

               
s = socket(af, SOCK_STREAM, IPPROTO_SCTP);


                if (s < 0) {
                                perror("socket()");
                                exit(1);
                }
                if (af == AF_INET6) {
                                bzero(&des6, sizeof (des6));

                                des6.sin6_family = AF_INET6;
                                des6.sin6_addr = a6;
                                des6.sin6_port = htons(port);

                                inet_ntop(AF_INET6, &a6, data, sizeof (data));
                                printf("Connect v6 to %s/%d\n", data, port);

                                if (connect(s, (struct sockaddr *)&des6, sizeof (des6)) < 0) {
                                                perror("connect");
                                                exit(1);
                                }
                } else {
                                bzero(&dest, sizeof (dest));

                                dest.sin_family = AF_INET;
                                dest.sin_addr = a;
                                dest.sin_port = htons(port);

                                inet_ntop(AF_INET, &a, data, sizeof (data));
                                printf("Connect v4 to %s/%d\n", data, port);

                                if (connect(s, (struct sockaddr *)&dest, sizeof (dest)) < 0) {
                                                perror("connect");
                                                exit(1);
                                }
                }

                bzero(pfds, sizeof (pfds));
                pfds[0].fd = 0;
                pfds[0].events = POLLIN;
                pfds[1].fd = s;
                pfds[1].events = POLLIN;

                while (1) {
                                tmp = poll(pfds, 2, -1);
                                if (tmp < 0) {
                                                perror("poll()");
                                                exit(1);
                                }
                                for (i = 0; i < 2; i++) {
                                                if (tmp == 0) {
                                                                continue;
                                                }
                                                if (pfds[i].revents) {
                                                                tmp = read(pfds[i].fd, data, sizeof (data));
                                                                if (tmp < 0) {
                                                                                perror("read()");
                                                                                exit(1);
                                                                } else if (tmp == 0) {
                                                                                exit(0);
                                                                } else {
                                                                                if (write(pfds[(i + 1) % 2].fd, data,
                                                                                                tmp) < 0) {
                                                                                                perror("write()");
                                                                                                exit(1);
                                                                                }
                                                                }
                                                }
                                }
                }
                return (0);
}

 

 

 

To test:

 

% cd   ~/public_html/sctpSolries10


something % sctp_server  


somethingmore % sctp_client  something   10117       //  (echo)

somethingmore % sctp_client  something   10118       //(chargen)

somethingmore % sctp_client  something   10119       //(discard)

 

 


v Advanced Features: 

 

 

ü Autoclosing:

 

Specify a maximum number of seconds an association remain idle.

  
close_time = 120;

setsockopt(sock_fd, IPPROTO_SCTP, SCTP_AUTOCLOSE, &close_time, sizeof(close_time));
 
Example:
 AutoCloseServer & 
 AutoCloseClient.
 
% AutoCloseServer 10123   5
Try: 
% AutoCloseClient something 10123   4
And then 
% AutoCloseClient something 10123   6
 

ü Peeloff:

connfd = sctp_peeloff (socket, assoc_id);
Example:

sctp_serverQpeel.c  (modified from sctp_serverQ.c) 

 

. . . .        

 

ü Streams:

 

â Sending on a Specific Stream:

struct sctp_sndrcvinfo   sri;

sri.sinfo_stream = 5 ;

 

means to send on stream 5 instead the default (1).

 

âControlling Number of Streams:
initm.sinit_num_ostreams  = 20; 
setsockopt(sock_fd, IPPROTO_SCTP, SCTP_INITMSG, &initm, sizeof(initm));
 

means the server will  use 20 streams instead of the default (10).

 

Example: 
StreamServer & 
StreamClient.