Hi,

I've implemented a test program for server and client using the existing
example of gnu-tls. This program emulates DTLS handshake over SCTP.
There are several messages starting from client hello then hello verify
request etc.
All i want to know is that whether is it mandatory for server to verify the
cookie for DTLS because if its case of SCTP the same is already done while
complete SCTP Handshake.
The example which i've is originally derived from DTLS over UDP and hence
that part of code is inherited from there itself.
If i comment the cookie verify part of DTLS then gnutls_handshake(session);
of server does not entertain Client Hello request at all.
Is it because prestate not being set properly?
PFA the code of both client and server for your reference. I'm more
concerned about code starting from line 238 till 286 in
stream_sctp_server.c.
How to take out this piece of code because that's an optional part in
standard DTLS handshake.



Regards,
Sandeep
/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>
#include <netinet/sctp.h>

/* A very basic Datagram TLS client, over UDP with X.509 authentication.
 */

#define MAX_BUF 1024
#define CAFILE "/etc/ssl/certs/ca-bundle.crt"
#define MSG "GET / HTTP/1.0\r\n\r\n"

//extern int udp_connect(void);
//extern void udp_close(int sd);
extern int verify_certificate_callback(gnutls_session_t session);
static void tls_log_func(int level, const char *str)
{
   printf("  |<%d>| %s", level, str);
}

int main(int argc, char ** argv)
{
    int ret, sd, ii;
    gnutls_session_t session;
    char buffer[MAX_BUF + 1];
    const char *err;
    gnutls_certificate_credentials_t xcred;
    struct sockaddr_in servaddr;

    if (argc<2)
    {
        printf("Usage is : <exe-name> <server-ip> \n");
        exit(-1) ;
    }

    if (gnutls_check_version("3.1.4") == NULL) 
    {
        fprintf(stderr, "GnuTLS 3.1.4 is required for this example\n");
        exit(1);
    }

   gnutls_global_set_log_function(tls_log_func);
   gnutls_global_set_log_level(10);


    gnutls_global_init();

    /* X509 stuff */
    gnutls_certificate_allocate_credentials(&xcred);

    /* sets the trusted cas file */
    gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM);
    gnutls_certificate_set_verify_function(xcred, verify_certificate_callback);

    /* Initialize TLS session */
    gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);

    /* Use default priorities */
    ret = gnutls_priority_set_direct(session, "NORMAL", &err);
    if (ret < 0) 
    {
        if (ret == GNUTLS_E_INVALID_REQUEST) 
        {
            fprintf(stderr, "Syntax error at: %s\n", err);
        }
        exit(1);
    }

    /* put the x509 credentials to the current session */
    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
    gnutls_server_name_set(session, GNUTLS_NAME_DNS, "lxc-logQpjLrM", strlen("lxc-logQpjLrM"));

    /* connect to the peer */
    // sd = udp_connect();
    //sd = socket( AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP );
    sd = socket( AF_INET, SOCK_STREAM , IPPROTO_SCTP );
/*
        struct sctp_authchunk auth;
        auth.sauth_chunk = 0; // send auth packets for all data messages
        ret = setsockopt(sd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
*/
	//struct sctp_authchunk sac;
	//if (setsockopt(sd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &sac, (socklen_t)sizeof(struct sctp_authchunk)) < 0)
//			perror("setsockopt");

	
	servaddr.sin_family = AF_INET;
	printf ("Connecting to %s\n", argv[1]);
	servaddr.sin_addr.s_addr = inet_addr(argv[1]);
	servaddr.sin_port = htons(2905);

	ret = connect( sd, (struct sockaddr *)&servaddr,sizeof(servaddr));

	if (ret == -1)
	{
		perror("Error:");
		fprintf(stderr,"connect to server failed\n");
		exit(1);
	}
	printf("SCTP-Connect Done\n");

    gnutls_transport_set_int(session, sd);

    /* set the connection MTU */
    gnutls_dtls_set_mtu(session, 1500);
    gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

    printf("perform dtls handshake\n");

    /* Perform the TLS handshake */
    do 
    {
            ret = gnutls_handshake(session);
    }
    while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
    /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET */

    printf("dtls handshake ret value:%d\n",ret);

    if (ret < 0) 
    {
        fprintf(stderr, "*** Handshake failed\n");
        gnutls_perror(ret);
        goto end;
    } 
    else 
    {
        char *desc;

        desc = gnutls_session_get_desc(session);
        printf("- Session info: %s\n", desc);
        gnutls_free(desc);
    }

    gnutls_record_send(session, MSG, strlen(MSG));

//    gnutls_record_send(session, MSG, strlen(MSG));

//    gnutls_record_send(session, MSG, strlen(MSG));

    ret = gnutls_record_recv(session, buffer, MAX_BUF);
    if (ret == 0) 
    {
        printf("- Peer has closed the TLS connection\n");
        goto end;
    } 
    else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) 
    {
        fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
    } 
    else if (ret < 0) 
    {
        fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
        goto end;
    }

    if (ret > 0) 
    {
        printf("- Received %d bytes: \n", ret);
        for (ii = 0; ii < ret; ii++) 
        {
            fputc(buffer[ii], stdout);
        }
        fputs("\n", stdout);
    }

        /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS
         * connections because the peer's closure message might
         * be lost */
    gnutls_bye(session, GNUTLS_SHUT_WR);

    end:


	close(sd);

    gnutls_deinit(session);

    gnutls_certificate_free_credentials(xcred);

    gnutls_global_deinit();

    return 0;
}
/*
 * =====================================================================================
 *
 *       Filename:  sctp_server.c
 *
 *    Description:  this is a one-to-one socket implementation of dtls over sctp
 *
 *        Version:  1.0
 *        Created:  Sunday 15 June 2014 06:34:50 PM IST 
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Daniel Raj	
 *   Organization:  Mobileum
 *
 * =====================================================================================
 */
/* This example code is placed in the public domain. */


/* To enable socket features used for Solaris SCTP socket. */
#ifdef __sun
#define _XPG4_2
#define __EXTENSIONS__
#endif


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/dtls.h>
#include <netinet/sctp.h>

#include <errno.h>

#include <netinet/in.h>
#include <sys/select.h>
#include <netdb.h>

#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
#define CAFILE "/etc/ssl/certs/ca-bundle.crt"
#define CRLFILE "crl.pem"

/* This is a sample DTLS echo server, using X.509 authentication.
 * Note that error checking is minimal to simplify the example.
 */

#define MAX_BUFFER 2048
#define PORT 2905

typedef struct {
   gnutls_session_t session;
   int fd;
   struct sockaddr *cli_addr;
   socklen_t cli_addr_size;
} priv_data_st;

static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms);
static ssize_t push_func(gnutls_transport_ptr_t p, const void *data, size_t size);
static ssize_t pull_func(gnutls_transport_ptr_t p, void *data, size_t size);
static const char *human_addr(const struct sockaddr *sa, socklen_t salen,char *buf, size_t buflen);
static int wait_for_connection(int fd);
static int generate_dh_params(void);

/* Use global credentials and parameters to simplify
 * the example. */
static gnutls_certificate_credentials_t x509_cred;
static gnutls_priority_t priority_cache;
static gnutls_dh_params_t dh_params;

static void tls_log_func(int level, const char *str)
{
   printf("  |<%d>| %s", level, str);
}
void handle_sctp_event(struct msghdr *str);

static void tls_audit_log_func(gnutls_session_t session, const char * str)
{
   printf(" | %s", str);
   return;
}

int main(void)
{
   int listen_sd;
   int sock, ret;
   struct sockaddr_in sa_serv;
   struct sockaddr_in cli_addr;
   socklen_t cli_addr_size;
   gnutls_session_t session;
   priv_data_st priv;
   gnutls_datum_t cookie_key;
   gnutls_dtls_prestate_st prestate;
   int mtu = 1400;
   int on = 0;
   unsigned char buffer[MAX_BUFFER];
   unsigned char sequence[18];
   const char * err;

   /* this must be called once in the program
   */

   gnutls_global_set_log_function(tls_log_func);
   gnutls_global_set_log_level(10);

   gnutls_global_set_audit_log_function(tls_audit_log_func);


   gnutls_global_init();

   gnutls_certificate_allocate_credentials(&x509_cred);
   gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, GNUTLS_X509_FMT_PEM);
   gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM);

   ret = gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM);
   
   if (ret < 0) 
   {
	  printf(" No certificate or key were found\n");
	  exit(1);
   }

   generate_dh_params();

   gnutls_certificate_set_dh_params(x509_cred, dh_params);

   gnutls_priority_init(&priority_cache, "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE", NULL);

   gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE);


   /* Socket operations
   */

   listen_sd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
   if (listen_sd < 0 )
   {
	  perror("Socket Error::");
	  exit (-5);
   }

   memset(&sa_serv, '\0', sizeof(sa_serv));
   sa_serv.sin_family = PF_INET;
   sa_serv.sin_addr.s_addr = inet_addr("172.16.130.65");
   sa_serv.sin_port = htons(PORT);


   {                       /* DTLS requires the IP don't fragment (DF) bit to be set */
#if defined(IP_DONTFRAG)
	  int optval = 1;
	  setsockopt(listen_sd, IPPROTO_IP, IP_DONTFRAG,
			(const void *) &optval, sizeof(optval));
	  printf(" Dont Fragment :)\n");
#elif defined(IP_MTU_DISCOVER)
	  int optval = IP_PMTUDISC_DO;
	  setsockopt(listen_sd, IPPROTO_IP, IP_MTU_DISCOVER,
			(const void *) &optval, sizeof(optval));
	  printf(" IP_MTU_DISCOVER set\n");
#endif
   }


    if ( bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)) < 0 ) 
    {
        fprintf(stderr, "Bind failed [ %s ]\n", strerror(errno));
        perror (" Bind Error:");
        exit (-1);
    }
    printf(" Socket number is %d\n",listen_sd);
    printf(" SCTP server ready. Listening to port '%d'.\n\n", PORT);

    ret=listen(listen_sd,100);
    if(ret <0) 
    {
        printf(" listen failed\n");
        exit(-1);
    }
   
    printf(" Waiting for connection...\n");
    while(1) 
    {
        sock=accept(listen_sd,NULL,0);
        if(sock>0) 
        {
	         printf(" **Connection accepted\n");
	         break; // come out of the loop
        }
    }

  
    printf(" SCTP Connection Established\n");

    struct sctp_event_subscribe events;

    /* Events to be notified for */
    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;

    setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events));      

    struct sctp_status st;
    socklen_t st_len;
    st_len=sizeof(st);
    memset(&st,'\0',sizeof(st));
    //st.sstat_assoc_id =0;
    if(getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &st,&st_len) < 0)
    {
          perror(" getsockopt");
    } 
    int cookie_sent = 0 ;
    for (;;) 
    {
   
      struct sctp_sndrcvinfo srinfo;
      memset(&srinfo, 0, sizeof(struct sctp_sndrcvinfo)) ;
      int flags = 0 ;
      //If its message of Cookie verify and Client Hello message then just peek in socket and provide
      //the buffer to verify the cookie and leave it for DTLS Handshake otherwise standard Handshake procedure
      //will wait for one more Client Hello message.

      if (on)
        flags = MSG_PEEK ;
      
	  cli_addr_size = sizeof(cli_addr);

	  ret = sctp_recvmsg(sock,buffer, MAX_BUFFER,(struct sockaddr *) &cli_addr, &cli_addr_size, &srinfo, &flags);
	  struct msghdr* msg = (struct msghdr *)buffer; 
      
	  printf (" Size of message %d\n", ret) ;
      printf (" TSN=%u, SN=%d, SSN=%u\n", srinfo.sinfo_tsn, srinfo.sinfo_stream, srinfo.sinfo_ssn) ;
	  
	  if (flags & MSG_NOTIFICATION) 
	  { 
        printf("  sctp event\n") ;
        handle_sctp_event(msg) ;
        continue;
	  }

    if (ret > 0)
    {
        memset(&prestate, 0, sizeof(prestate));
        if (on)
        {
            ret = gnutls_dtls_cookie_verify(&cookie_key, &cli_addr, sizeof(cli_addr), buffer, ret, &prestate);
            printf ("Cookie verified from %s, code returend %d\n", 
                    human_addr((struct sockaddr *)&cli_addr,sizeof(cli_addr), buffer, sizeof(buffer)), ret);            
            on = 0 ;
        }
        else
        {  //This part of code is analogus to SCTP cookie echo message. Hence after sending verify request
           //This stub verifies the state of DTLS cookie received in next Client Hello method.
            priv_data_st s;
            memset(&s, '\0', sizeof(s));
            s.fd = sock;
            s.cli_addr = (void *) &cli_addr;
            s.cli_addr_size = sizeof(cli_addr);
            on = 1 ;
            printf ("Sending hello verify request to %s\n", human_addr((struct sockaddr *)&cli_addr,sizeof(cli_addr), buffer, sizeof(buffer)));
            gnutls_dtls_cookie_send(&cookie_key,&cli_addr,sizeof(cli_addr),&prestate,(gnutls_transport_ptr_t)&s, push_func);
            continue;
        }
        printf(" Accepted DTLS connection from %s\n", human_addr((struct sockaddr *)&cli_addr, sizeof(cli_addr),buffer, sizeof(buffer)));
    }
    else
    {
        printf (" Recvfrom failed \n");
        perror(" recvfrom");
        goto end;
    }

	  gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
	  gnutls_priority_set(session, priority_cache);
	  gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);

	  gnutls_dtls_prestate_set(session, &prestate);
	  gnutls_dtls_set_mtu(session, mtu);

	  priv.session = session;
	  priv.fd = sock;
	  priv.cli_addr = (struct sockaddr *) &cli_addr;
	  priv.cli_addr_size = sizeof(cli_addr);

	  gnutls_transport_set_ptr(session, &priv);
	  gnutls_transport_set_push_function(session, push_func);
	  gnutls_transport_set_pull_function(session, pull_func);
	  gnutls_transport_set_pull_timeout_function(session, pull_timeout_func);

	  do 
	  {
		 ret = gnutls_handshake(session);
	  }
	  while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
	  /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET.
	   * In that case the MTU should be adjusted.
	   */

	  if (ret < 0) 
	  {
		 fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret));
		 gnutls_deinit(session);
		 continue;
	  }

	  printf(" - DTLS Handshake was completed\n");

	  for (;;) 
	  {
		 do 
		 {
			ret = gnutls_record_recv_seq(session, buffer,MAX_BUFFER, sequence);
		 }
		 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);

		 if (ret < 0 && gnutls_error_is_fatal(ret) == 0) 
		 {
			fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
			continue;
		 } 
		 else if (ret < 0) 
		 {
			fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret));
			break;
		 }

		 if (ret == 0) 
		 {
			printf(" EOF\n\n");
			break;
		 }

		 buffer[ret] = 0;
		 //This is sequence number present in DTLS header. Its a byte number 
		 //and used to detect out-of-order packet. In case API gnutls_record_recv is
		 //used then it won't even come in highlight.
		 //Over SCTP such mechanisms are not needed but becuse DTLS is immune of its 
		 //lower level transport protocol hence it provides the support of this API.
		 printf (" received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n",
    			 sequence[0], sequence[1], sequence[2],
    			 sequence[3], sequence[4], sequence[5],
    			 sequence[6], sequence[7], buffer);

		 /* reply back */
		 ret = gnutls_record_send(session, buffer, ret);
		 if (ret < 0) 
		 {
			fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret));
			break;
		 }
	  }

	  gnutls_bye(session, GNUTLS_SHUT_WR);
	  gnutls_deinit(session);

   }
end:
   close(listen_sd);

   gnutls_certificate_free_credentials(x509_cred);
   gnutls_priority_deinit(priority_cache);

   gnutls_global_deinit();

   return 0;

}

static int wait_for_connection(int fd)
{
   fd_set rd, wr;
   int n;

   FD_ZERO(&rd);
   FD_ZERO(&wr);

   FD_SET(fd, &rd);

   /* waiting part */
   n = select(fd + 1, &rd, &wr, NULL, NULL);

   if (n == -1 && errno == EINTR)
	  return -1;

   if (n < 0) 
   {
	  perror(" select()");
	  exit(1);
   }

   return fd;
}

/* Wait for data to be received within a timeout period in milliseconds
*/
static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms)
{
   fd_set rfds;
   struct timeval tv;
   priv_data_st *priv = ptr;
   struct sockaddr_in cli_addr;
   socklen_t cli_addr_size;
   int ret;
   char c;

   FD_ZERO(&rfds);
   FD_SET(priv->fd, &rfds);

   tv.tv_sec = 0;
   tv.tv_usec = ms * 1000;

   while (tv.tv_usec >= 1000000) 
   {
	  tv.tv_usec -= 1000000;
	  tv.tv_sec++;
   }

   ret = select(priv->fd + 1, &rfds, NULL, NULL, &tv);
   if (ret <= 0)
	  return ret;

   /* only report ok if the next message is from the peer we expect
	* from 
	*/
   cli_addr_size = sizeof(cli_addr);
   ret = recvfrom(priv->fd, &c, 1, MSG_PEEK, (struct sockaddr *) &cli_addr, &cli_addr_size);
   if (ret > 0) 
   {
	  if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0)
		 return 1;
   }
   return 0;
}

static ssize_t push_func(gnutls_transport_ptr_t p, const void *data, size_t size)
{
    int ret;
    priv_data_st *priv = p;

    ret = sendto(priv->fd, data, size, 0, priv->cli_addr, priv->cli_addr_size);
    if(ret<0) 
    {
	    printf(" sendto failed for fd: with return value:\n",priv->fd,ret);
    }
    return ret;
}

static ssize_t pull_func(gnutls_transport_ptr_t p, void *data, size_t size)
{
   priv_data_st *priv = p;
   struct sockaddr_in cli_addr;
   socklen_t cli_addr_size;
   char buffer[64];
   int ret;

   cli_addr_size = sizeof(cli_addr);
   ret = recvfrom(priv->fd, data, size, 0, (struct sockaddr *) &cli_addr, &cli_addr_size);

   if (ret == -1)
	  return ret;

   if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0)
	  return ret;

   printf(" Denied connection from %s\n", human_addr((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer)));

   gnutls_transport_set_errno(priv->session, EAGAIN);
   return -1;
}

static const char *human_addr(const struct sockaddr *sa, socklen_t salen, char *buf, size_t buflen)
{
   const char *save_buf = buf;
   size_t l;

   if (!buf || !buflen)
	  return NULL;

   *buf = '\0';

   switch (sa->sa_family) 
   {
#if HAVE_IPV6
	  case AF_INET6:
		 snprintf(buf, buflen, "IPv6 ");
		 break;
#endif

	  case AF_INET:
		 snprintf(buf, buflen, "IPv4 ");
		 break;
   }

   l = strlen(buf);
   buf += l;
   buflen -= l;

   if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
	  return NULL;

   l = strlen(buf);
   buf += l;
   buflen -= l;

   strncat(buf, " port ", buflen);

   l = strlen(buf);
   buf += l;
   buflen -= l;

   if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
	  return NULL;

   return save_buf;
}

static int generate_dh_params(void)
{
   int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
		 GNUTLS_SEC_PARAM_LEGACY);

   /* Generate Diffie-Hellman parameters - for use with DHE
	* kx algorithms. When short bit length is used, it might
	* be wise to regenerate parameters often.
	*/
   gnutls_dh_params_init(&dh_params);
   gnutls_dh_params_generate2(dh_params, bits);

   return 0;
}

void handle_sctp_event (struct msghdr *buf)
{
	
	struct sctp_assoc_change *sac;
	struct sctp_send_failed *ssf;
	struct sctp_paddr_change *spc;
	struct sctp_remote_error *sre;
	union sctp_notification *snp;	
	struct sockaddr_in *sin;
	const char *ap;
	char addrbuf[INET6_ADDRSTRLEN];
	struct sockaddr_in6 *sin6;
	
	
	snp=(union sctp_notification*)buf;
	
    switch (snp->sn_header.sn_type) 
    {
    case SCTP_ASSOC_CHANGE:
        sac = &snp->sn_assoc_change;
        printf(" ^^^ 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);
        break;
    case SCTP_SEND_FAILED:
        ssf = &snp->sn_send_failed;
        printf(" ^^^ sendfailed: len=%hu err=%d\n", ssf->ssf_length, ssf->ssf_error);
        break;
    case SCTP_PEER_ADDR_CHANGE:
        spc = &snp->sn_paddr_change;
        if (spc->spc_aaddr.ss_family == AF_INET) 
        {
            sin = (struct sockaddr_in *)&spc->spc_aaddr;
            ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET6_ADDRSTRLEN);
        } 
        else 
        {
            sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
            ap = inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN);
        }
        printf(" ^^^ intf_change: %s state=%d, error=%d\n", ap, spc->spc_state, spc->spc_error);
        break;
    case SCTP_REMOTE_ERROR:
        sre = &snp->sn_remote_error;
        printf(" ^^^ remote_error: err=%hu len=%hu\n", ntohs(sre->sre_error), ntohs(sre->sre_length));
        break;
    case SCTP_SHUTDOWN_EVENT:
        printf(" ^^^ shutdown event\n");
        break;
    default:
        printf(" unknown type: %hu\n", snp->sn_header.sn_type);
        break;
    }
    
}

_______________________________________________
Gnutls-help mailing list
[email protected]
http://lists.gnupg.org/mailman/listinfo/gnutls-help

Reply via email to