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

 

 

 


Ø  Overview: 

Useful Documents:

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

·     An association is different from a connection since 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:    is digitally signed record containing state information to ensure association validity.

 


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

 

 

 


Ø SCTP 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 the following “something” hosts:

·     something (128.82.4.210)

·     somethingelse (128.82.4.120)

·     somethingmore (128.82.4.209)

And the following “fast” hosts:

·     vega (128.82.4.19)

·     deneb (128.82.4.118)

·     antares (128.82.4.98)

 

 


Ø Modifications 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 )




 

#include "def"

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  tcpServerSctp & tcpClientSctp:

 

% 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   udpServerSctp & udpClientSctp:

 

% cd   ~/public_html/sctpSolries10


something % udpServerSctp    //it uses port  10111


somethingmore % udpClientSctp  something

 

ª    Amazing! marriage beteeen tcp & udp

 

something % udpServerSctp   

somethingmore % tcpClientSctp  something

also try: % udpClientSctp  something

 

something % tcpServerSctp  

somethingmore % udpClientSctp  something

 

 


Ø  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    //it uses port 10111


somethingmore % sctp_clientQ 1234 something 10111

somethingmore % sctp_clientS  something  10111

 

 

 

Ø 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    10111     //  (echo)

somethingmore % sctp_client  something   10111       //(chargen)

somethingmore % sctp_client  something   10111       //(discard)

 

 


Ø  Advanced Features: 

 

 

ü Autoclosing:

 

Lets an SCTP endpoint 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);
 

ü   sctp_serverQpeel.c 

(modified from sctp_serverQ.c) 

 

 

. . . . .

      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) ;

     
      FD_ZERO(&rset);

     while (1) {
          FD_SET(echo_s, &rset);
          select(5, &rset, NULL, NULL, NULL);
          if (FD_ISSET(echo_s, &rset) ) {
             

              if ((ret = recvmsg(echo_s, &mhdr, MSG_DONTWAIT)) < 0) {
                   perror("recvmsg()");
              }
                       
              if (sendmsg(echo_s, &mhdr, MSG_DONTWAIT) < 0) {
                   perror("sendmsg()");
              }
                 
                  if( (connfd = sctp_peeloff(echo_s, sinfo->sinfo_assoc_id)) == -1) {
                               printf("sctp_peeloff fails");
                               continue;
               }
               else {
                    FD_SET(connfd, &rset);
                    FD_CLR (echo_s, &rset);
              }
                    
            }
            if (FD_ISSET(connfd, &rset) ) {
              rc=read (connfd, data, sizeof(data));
              write(connfd, data, rc);
         }
      }
}

 

 

ü 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  = 30; 
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.