Dhananjay Joshi wrote:

> Yes, 192.83 was rebooted around frame #74.
> 192.80 SCTP retransmits INIT from #79 to #82.
> But it stops after that.
> Why should it stop re-transmission? 


It will stop for a peer address after the number of
retransmission to that address exceeds a value, which
is default to be 5 (the ndd param sctp_pp_max_retr).


> It did not send COM LOST either to
> application.
> I have re-ran tests and waited for long time (10 minutes).
> But I did not see SCTP transmitting Init further.


The association has already timed out so there is no
more retransmission.  In my test, your program did get
both the address unreachable and the comm lost events, as
can be seen from the output I sent last time.

I forgot to mention one thing.  There is a bug in your
program such that it should get a "Segmentation fault" error.
If it does not Seg fault, it probably has some data corruption.
I'm not sure if this is the cause of what you've seen.  I've
attached the changed .c file and you can try it.  Note that
I did not go through the whole source to see if there are
other problems.  It is just that your program did not work
until I fixed that bug.


> Regarding dtrace utility, is this command sufficient to check if SCTP is
> transmitting Init:
> dtrace -n BEGIN -n fbt:ip:sctp_init_mp:entry


I think the problem is not about INIT retransmission.  The
retransmission is done properly AFAIK.  The problem is that
your program does not get the events.  Please try the fixed
program and see if it works for you.  It seems to be a program
error.

On how to write dtrace script, please refer to the "Solaris
Dynamic Tracing Guide" and "DTrace User Guide" available from

        http://docs.sun.com/


BTW, there is a bug in the peer's SCTP stack as I mentioned in
the previous email.  The peer's SCTP stack does not generate a
correct ABORT chunk.  You may want to tell your vendor about this.



-- 

                                                K. Poon.
                                                [EMAIL PROTECTED]

/*
 * Copyright 2006 teleSys Software Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/* To enable socket features used for SCTP socket. */
#define _XPG4_2
#define __EXTENSIONS__

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>

#include <netinet/sctp.h>

#define Ulong int
#define Ushort short
#define Int int
#define SCTP_SIZE_MAX_IP_ADDR 4
#define SctpAssocId int
#define Char char
#define SUCCESS 0  
#define SCTP_MAX_USR_DATA_SIZE 1500

#define SCTP_ERR_DOWN 10
#define SCTP_ERR_ASSOC_IN_PROGRESS 1

in_addr_t localIp[4], remoteIp;
int16_t port;
int gVerbose;
int gConnect = 0;

Int solSctpInitialize(int16_t portNumber, in_addr_t *addresses, int numAddr, int *fd);
Int  solSctpSend(int fd, SctpAssocId assocId, Char *data, int size);
Int solSctpReceive();
void solSctpEvents(int sockFd, char * data, struct sockaddr_in * fromAddr);
void handleSolSctpCommUp(int sockFd, struct sctp_assoc_change *sac, struct sockaddr_in * fromAddr);
Int  solSctpAbort(int sockFd, SctpAssocId assocId, Int cause);
Int solSctpAssociate(int sockFd, int16_t port, in_addr_t address);
void SOL_SCTP_DEBUG(char dbglevel, char *fmt, ...);
Int solSctpSetParameters(int sock, sctp_assoc_t id);



Int solSctpInitialize(int16_t portNumber, in_addr_t *addresses, int numAddr, int *fd)
{
  int sockFd;
  struct sockaddr_in src_addr[SCTP_SIZE_MAX_IP_ADDR];
  int addr_len = sizeof(struct sockaddr_in);
  struct sctp_event_subscribe events;
  struct sctp_initmsg  initmsg;
  int count, flags, i;
  union sctp_notification *snp;

  gVerbose = 2; /*Debug level 2 */

 /* Create a one-many SCTP socket  */
 if ((sockFd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) == -1) {
  perror("socket");
  return SCTP_ERR_DOWN;
 }

 if (numAddr > SCTP_SIZE_MAX_IP_ADDR)
     numAddr = SCTP_SIZE_MAX_IP_ADDR;
 if(numAddr) /* Bind first address */
 {
   memset(src_addr, 0, addr_len);
   src_addr[0].sin_family = AF_INET;
   src_addr[0].sin_port = htons(portNumber);
   src_addr[0].sin_addr.s_addr = addresses[0];
   if (bind(sockFd, (struct sockaddr *)&(src_addr[0]), addr_len) == -1) 
   {
      perror("bind");
      return SCTP_ERR_DOWN;
   }
   numAddr--;
   for(i=0;i<numAddr;i++)
   {
     memset(&src_addr[i], 0, addr_len);
     src_addr[i].sin_family = AF_INET;
     src_addr[i].sin_port = htons(portNumber);
     src_addr[i].sin_addr.s_addr = addresses[i+1];
   }
   if (numAddr)
     if (sctp_bindx(sockFd, (struct sockaddr *)src_addr, numAddr, SCTP_BINDX_ADD_ADDR) == -1)
     {
         perror("bindx");
     }
 }
  (void) memset(&initmsg, 0, sizeof(struct sctp_initmsg));
  initmsg.sinit_num_ostreams = 5;
  initmsg.sinit_max_instreams = 5;
  if (setsockopt(sockFd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
      sizeof(struct sctp_initmsg)) < 0) {
   perror("SCTP_INITMSG");
         return SCTP_ERR_DOWN;
  }

  /* Events to be notified for */
 (void) memset(&events, 0, sizeof (events));
 events.sctp_data_io_event = 1;
 events.sctp_association_event = 1;
 events.sctp_send_failure_event = 1;
 events.sctp_address_event = 1;
 events.sctp_peer_error_event = 1;
 events.sctp_shutdown_event = 1;

  /* Enable ancillary data */
  if (setsockopt(sockFd, IPPROTO_SCTP, SCTP_EVENTS, &events,
      sizeof (events)) < 0) 
  {
      perror("setsockopt SCTP_EVENTS");
         return SCTP_ERR_DOWN;
  }

  /* Set socket to non blocking mode */
  flags = fcntl (sockFd, F_GETFL, 0);
  fcntl(sockFd, F_SETFL, flags | O_NONBLOCK);

  /* Increase RCV_BUFF size current socket options */
  {
     int rcvbuf;
     socklen_t siz = sizeof(int);
  
     if (getsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, &siz) < 0)
       SOL_SCTP_DEBUG(0,"getsockopt for RCVBUF failed. errno = %d\n", errno);
     else
       SOL_SCTP_DEBUG(3,"getsockopt for RCVBUF b4 modification returned bytes = %d\n", rcvbuf);

    if(getenv("SOLARIS_SCTP_RCVBUF_SIZE") != NULL)
    {
       rcvbuf = atoi(getenv("SOLARIS_SCTP_RCVBUF_SIZE"));
       if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, siz) < 0)
         SOL_SCTP_DEBUG(0,"setsockopt for RCVBUF failed. errno = %d\n", errno);

       if (getsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, &siz) < 0)
         SOL_SCTP_DEBUG(0,"getsockopt for RCVBUF failed. errno = %d\n", errno);
       else
         SOL_SCTP_DEBUG(3,"getsockopt for RCVBUF after modification returned bytes = %d\n", rcvbuf);
    }
  }

  if (listen(sockFd, 1) == -1)
  {
     perror("listen");
     return SCTP_ERR_DOWN;
  }

 SOL_SCTP_DEBUG(1,"Solaris SCTP: initialized successfully\n");
 *fd = sockFd;
 return SUCCESS;

}

Int solSctpAssociate(int sockFd, int16_t port,in_addr_t address)
{
  struct sctp_initmsg  initmsg;
  int addr_len = sizeof(struct sockaddr_in);
  int flags;
  Int ret;
  struct sockaddr_in dst_addr ;

  SOL_SCTP_DEBUG(1,"Intitiating connection \n");

  (void) memset(&initmsg, 0, sizeof(struct sctp_initmsg));
  initmsg.sinit_num_ostreams = 5;
  initmsg.sinit_max_instreams = 5;
  if (setsockopt(sockFd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
      sizeof(struct sctp_initmsg)) < 0) 
  {
   perror("SCTP_INITMSG");
         return SCTP_ERR_DOWN;
  }
   dst_addr.sin_family = AF_INET;
   dst_addr.sin_port = htons(port);
   dst_addr.sin_addr.s_addr = address;

   if ((ret = connect(sockFd, (struct sockaddr *)&dst_addr, sizeof (struct sockaddr_in))) == -1) 
   {
      if((errno == EINPROGRESS)|| (errno ==  EALREADY) || (errno == EADDRINUSE) )
         SOL_SCTP_DEBUG(1,"Connection attempt successful errno = %d\n", errno);
      else
      {
        SOL_SCTP_DEBUG(0,"Connection attempt failed errno = %d\n", errno);
        perror("connect");
        fcntl (sockFd, F_SETFL, flags);
        return SCTP_ERR_DOWN;
      }
    }

   SOL_SCTP_DEBUG(1,"Connection attempt successful returning value %d\n", SCTP_ERR_ASSOC_IN_PROGRESS);

   return SUCCESS;
}

void handleSolSctpCommUp(int sockFd, struct sctp_assoc_change *sac, struct sockaddr_in * fromAddr)
{
  struct sockaddr_in *addrs;
  Int    numAddrs = 0;

  if(SCTP_COMM_UP == sac->sac_state)
  {
    /* Get IP addresses of peer */
    numAddrs =  sctp_getpaddrs(sockFd, sac->sac_assoc_id, (void **)&addrs);

    /* Set sctp parameters for this association*/
    solSctpSetParameters(sockFd,sac->sac_assoc_id);

    SOL_SCTP_DEBUG(1,"Solaris SCTP: Received COM UP for association id %d \n", sac->sac_assoc_id);
    if(numAddrs > 0)
    {
         SOL_SCTP_DEBUG(1,"Address 1 of peer is 0x%x and port = %d \n", 
		ntohl(addrs[0].sin_addr.s_addr), ntohs(addrs[0].sin_port));

         numAddrs--;
         if(SCTP_SIZE_MAX_IP_ADDR < (numAddrs-1))
             numAddrs = SCTP_SIZE_MAX_IP_ADDR -1;
         while(numAddrs)
         {
            SOL_SCTP_DEBUG(1,"Address %d of peer is 0x%x and port = %d \n",
		numAddrs+1, ntohl(addrs[numAddrs].sin_addr.s_addr),
		ntohs(addrs[numAddrs].sin_port));
            numAddrs--;
         }
    }
    else /* Use address returned in recvmsg call */
    {
        SOL_SCTP_DEBUG(1,"Received some error on  %d association while reading addresses errno = %d\n", sac->sac_assoc_id, errno);
    }
    sctp_freepaddrs(addrs);
  } /* END OF COMM UP LOOP */
  else /* Every thing other than COM UP is treated as COM LOST */
  {
    gConnect = 0;
    SOL_SCTP_DEBUG(1,"Received COM Lost/Termination of association %d state %d fromAddress 0x%x\n", sac->sac_assoc_id, sac->sac_state, fromAddr->sin_addr.s_addr);

    SOL_SCTP_DEBUG(1,"Posting COM Lost/Termination of association %d state %d fromAddress 0x%x \n", sac->sac_assoc_id, sac->sac_state, fromAddr->sin_addr.s_addr );
  } /* COMM LOST */
}

void solSctpEvents(int sockFd, char *buff, struct sockaddr_in * fromAddr)
{
 struct sctp_assoc_change *sac;
 struct sctp_send_failed  *ssf;
 struct sctp_paddr_change *spc;
 struct sctp_remote_error *sre;
 struct sctp_shutdown_event *sse;
 union sctp_notification  *snp;
 char    addrbuf[INET6_ADDRSTRLEN];
 const char   *ap;
 struct sockaddr_in  *sin;
 struct sockaddr_in6  *sin6;
 struct sockaddr_in * sockAddr;
 int flags;
 int ret;

 snp = (union sctp_notification *) buff;

 switch (snp->sn_header.sn_type) {
 case SCTP_ASSOC_CHANGE:
  sac = &snp->sn_assoc_change;
  SOL_SCTP_DEBUG(1,"assoc_change: state=%hu, error=%hu, instr=%hu "
         "outstr=%hu\n", sac->sac_state, sac->sac_error,
            sac->sac_inbound_streams, sac->sac_outbound_streams);
  handleSolSctpCommUp(sockFd, sac, fromAddr);
  break;

  case SCTP_PEER_ADDR_CHANGE:
    spc = &snp->sn_paddr_change;
    sockAddr = (struct sockaddr_in *)&(spc->spc_aaddr);

    SOL_SCTP_DEBUG(1,"postNetStatChange: assoc id %d, state %d address 0x%x",
                   spc->spc_assoc_id, spc->spc_state, sockAddr->sin_addr.s_addr);
    if(spc->spc_state == SCTP_ADDR_AVAILABLE)
    {
        SOL_SCTP_DEBUG(1,"Address 0x%x now reachable \n",sockAddr->sin_addr.s_addr);
    }

    if(spc->spc_state == SCTP_ADDR_UNREACHABLE)
    {
        SOL_SCTP_DEBUG(1,"Address 0x%x ureachable \n",sockAddr->sin_addr.s_addr);
    }
    
  break;

 case SCTP_SEND_FAILED:
  ssf = &snp->sn_send_failed;
  SOL_SCTP_DEBUG(1," sendfailed: len=%hu err=%d\n", ssf->ssf_length,
      ssf->ssf_error);
  break;

 case SCTP_REMOTE_ERROR:
  sre = &snp->sn_remote_error;
  SOL_SCTP_DEBUG(1," remote_error: err=%hu len=%hu\n",
      ntohs(sre->sre_error), ntohs(sre->sre_length));
  break;

 case SCTP_SHUTDOWN_EVENT:
  sse = &snp->sn_shutdown_event;
  SOL_SCTP_DEBUG(1," shutdown event\n");
  break;

 default:
  SOL_SCTP_DEBUG(0,"Solaris SCTP: unknown event received from solaris sctp: %hu\n", snp->sn_header.sn_type);
  break;
 }
}

Int solSctpReceive(int sockFd)
{
 struct msghdr  msg[1];
 struct iovec  iov[1];
 struct cmsghdr  *cmsg;
 struct sctp_sndrcvinfo *sri;
 char   cbuf[sizeof (*cmsg) + sizeof (*sri)];
 size_t cmsglen = sizeof(*cmsg) + sizeof (*sri) ;
 ssize_t ret = 0;
 struct sockaddr_in fromAddr;
 fd_set fdset;
 char data_buf[SCTP_MAX_USR_DATA_SIZE];


   memset(msg, 0, sizeof(*msg));
   memset(cbuf, 0, cmsglen);
   memset(&fromAddr, 0, sizeof(struct sockaddr_in));
   msg->msg_name = &fromAddr;
   msg->msg_namelen = sizeof(struct sockaddr_in);
   msg->msg_control = cbuf;
   msg->msg_controllen = cmsglen;
   msg->msg_flags = MSG_XPG4_2;
   cmsg = (struct cmsghdr *)cbuf;
   sri = (struct sctp_sndrcvinfo *) (cmsg + 1);

   iov->iov_base = data_buf;
   iov->iov_len = SCTP_MAX_USR_DATA_SIZE;
   msg->msg_iov = iov;
   msg->msg_iovlen = 1;

   msg->msg_flags = MSG_XPG4_2;
   msg->msg_controllen = cmsglen;


/* First wait till socket is ready with data. 
   Socket is non blocking, so calling receive 
   without select will result into immediate return.
*/

    FD_ZERO( &fdset );
    FD_SET( sockFd, &fdset );

    SOL_SCTP_DEBUG(2,"Going into select loop\n");

    while(1)
    {
       ret = select ( (sockFd+1), &fdset, NULL, NULL, NULL );
       if ( 0 > ret )
       {
           if(errno == EINTR)
                 continue;
           else
           {
             SOL_SCTP_DEBUG(0,"select failed. errno(%d)\n",errno);
             return SCTP_ERR_DOWN;
           }
       }
       if(0 == ret)
       {
         SOL_SCTP_DEBUG(0,"select returned 0. errno(%d)\n",errno);
         continue;
       }
       if ( FD_ISSET( sockFd, &fdset ) )
          break;
    }

   SOL_SCTP_DEBUG(2,"Got some thing on socket and going to read it\n");

   ret = recvmsg(sockFd, msg, 0);
   if(ret < 0)
   {
      SOL_SCTP_DEBUG(0,"Solaris SCTP:Error while reading data from Socket. errno(%d)\n",errno);
      return SCTP_ERR_DOWN;
   }
   if(ret == 0)
   {
     SOL_SCTP_DEBUG(1,"Solaris SCTP:Receive retrun 0 bytes\n");
     return SCTP_ERR_DOWN;
   }

   if ( ( msg->msg_flags &  MSG_EOR) != 0 )
      SOL_SCTP_DEBUG(3, "Full data has been read in single call \n");

   if ( msg->msg_flags &  MSG_NOTIFICATION)
   {
      SOL_SCTP_DEBUG(1, "Solaris SCTP: Received event from address 0x%x on association id %d \n",fromAddr.sin_addr.s_addr, sri->sinfo_assoc_id);
      solSctpEvents(sockFd, data_buf, &fromAddr);
   }
   else
   {
      SOL_SCTP_DEBUG(2, "Solaris SCTP: Received on socketid %d data size %d on association id %d on stream id %d\n",sockFd, ret, sri->sinfo_assoc_id, sri->sinfo_stream );
   }
   return SUCCESS;
}

Int  solSctpSend(int sockFd, SctpAssocId assocId, Char *data, int size)
{
  struct sctp_sndrcvinfo sinfo;
  ssize_t ret;
  size_t len;

  memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));

  sinfo.sinfo_assoc_id = assocId;
  sinfo.sinfo_stream = 0;
  sinfo.sinfo_ppid = 5;
  sinfo.sinfo_context = 0;

  SOL_SCTP_DEBUG(2, "Solaris SCTP: Sending data of size %d on association id %d\n", size, assocId);
  ret = sctp_send(sockFd, data, size, (struct sctp_sndrcvinfo *)&sinfo, 0);

  if(ret == -1)
  {
    if(errno == EAGAIN) 
      SOL_SCTP_DEBUG(1, "Send failed for data of size %d on association id %d errno = %d\n", size, assocId, errno);
    else
    {
      SOL_SCTP_DEBUG(0, "Send failed for data of size %d on association id %d errno = %d\n", size, assocId, errno);
      return SCTP_ERR_DOWN;
    }
  }

  return SUCCESS;

}
Int  solSctpAbort(int sockFd, SctpAssocId assocId, Int cause)
{
  struct sctp_sndrcvinfo sinfo;
  ssize_t ret;
  size_t len;
  char data[1000];

  memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));

  sinfo.sinfo_assoc_id = assocId;
  if(cause)
    sinfo.sinfo_flags = MSG_EOF;
  else
    sinfo.sinfo_flags = MSG_ABORT;

  SOL_SCTP_DEBUG(1,"Sending SCTP Shutdown on %d association \n", assocId);
  ret = sctp_send(sockFd, data, 0, (struct sctp_sndrcvinfo *)&sinfo, 0);

  if(ret == -1)
   perror("sctp_abort");

  return SUCCESS;
}

void SOL_SCTP_DEBUG(char debuglevel,char *fmt, ...)
{
    struct tm cur_tm;
    struct timeval cur_time;
    int dp_len = 0;
    char buf[1024];

    if(gVerbose < debuglevel)
       return;

    gettimeofday(&cur_time, NULL);
    localtime_r( &(cur_time.tv_sec), &cur_tm);

    /* Prepare the header */
    sprintf(buf, "[ %02d%02d%04d %02d:%02d:%02d.%03d ] ",
            cur_tm.tm_mday, (cur_tm.tm_mon +1), (cur_tm.tm_year+1900),
            cur_tm.tm_hour, cur_tm.tm_min, cur_tm.tm_sec,
            (int)(cur_time.tv_usec / 1000));

    dp_len = strlen(buf);

    /* Prepare the user provided debug string */
    {
        va_list arg;

        va_start (arg, fmt);
        vsprintf (buf + dp_len, fmt, arg);
        va_end (arg);
    }

    fprintf(stdout,buf);
    fflush(stdout);
}
Int solSctpSetParameters(int sock, sctp_assoc_t id)
{
  Int ret;
  struct sctp_paddrparams sctp_parm;
  struct sctp_rtoinfo sctp_rto;
  struct sctp_assocparams sctp_asso;
  socklen_t len;

  /* Modify HB interval */
  if(getenv("SOLARIS_SCTP_HB_INTERVAL") != NULL)
      sctp_parm.spp_hbinterval = atoi(getenv("SOLARIS_SCTP_HB_INTERVAL"));
  else
      sctp_parm.spp_hbinterval = 1000; /* 1 sec */
  if(getenv("SOLARIS_SCTP_RETRY_COUNT") != NULL)
      sctp_parm.spp_pathmaxrxt = atoi(getenv("SOLARIS_SCTP_RETRY_COUNT"));
  else
      sctp_parm.spp_pathmaxrxt = 3; 
      
  len = sizeof(struct sctp_assocparams);
  sctp_asso.sasoc_assoc_id = id;
  sctp_asso.sasoc_asocmaxrxt = sctp_parm.spp_pathmaxrxt;
  ret = setsockopt(sock, IPPROTO_SCTP, SCTP_ASSOCINFO, &sctp_asso,len);
  if(ret < 0)
         SOL_SCTP_DEBUG(0,"setsockopt for setting SCTP_ASSOCINFO setting failed. errno = %d\n", errno);

  len = sizeof(struct sctp_paddrparams);
  sctp_parm.spp_assoc_id = id;
  ret = setsockopt(sock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &sctp_parm,len);
  if(ret < 0)
         SOL_SCTP_DEBUG(0,"setsockopt for HB setting failed. errno = %d\n", errno);

  ret = sctp_opt_info(sock, id, SCTP_PEER_ADDR_PARAMS, (void*)&sctp_parm,&len);
  if(ret < 0)
    SOL_SCTP_DEBUG(1,"Error in retrieving current sctp settings for association(%d) error(%d)\n",id, errno);
  else
  {
    SOL_SCTP_DEBUG(1,"HB interval(%d) Max Rtxt(%d)\n",sctp_parm.spp_hbinterval,sctp_parm.spp_pathmaxrxt);
  }
}

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

        if( argc < 4 )
        {
                fprintf(stdout, "Usage : <port> <local ip> <remote ip> \n");
                exit(-1);
        }

        if( argc > 1)
        {
                port = atoi( argv[1] );
        }
        if ( argc > 2 )
        {
                localIp[0] = inet_addr( argv[2] );
        }
        if ( argc > 3 )
        {
                remoteIp = inet_addr( argv[3] );
        }
        /* Bind with SCTP */
        if( SUCCESS != solSctpInitialize( port, localIp, 1, &sctpFd) )
        {
            fprintf(stdout, " solSctpInitialize failed.\n");
            exit(-2);
        }
        /* starts receiving from SCTP */
       while(1)
       {
           if(gConnect == 0)
           {
             fprintf(stdout, "^^^^Wait for some time and make another connection attempt ^^^^\n");
             usleep(1000000);
             if( SUCCESS != solSctpAssociate( sctpFd, port, remoteIp) )
             {
                  fprintf(stdout, " connect failed.\n");
                  exit(-2);
             }
             else
                gConnect = 1; 
           }
           solSctpReceive(sctpFd );
       }
}
_______________________________________________
networking-discuss mailing list
[email protected]

Reply via email to