Commit 92fdb242 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Completed connection context files

parent 146fe937
......@@ -48,9 +48,9 @@ EXTENSION_ENTRY("monitor", monitor_main);
/* Function called on receipt of SIGUSR1 */
static void got_sig(int signal)
{
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, 0, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, 0, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, 0, NULL), /* continue */);
}
/* Thread to display periodical debug information */
static pthread_t thr;
......@@ -76,8 +76,9 @@ static void * mn_thr(void * arg)
sleep(3600); /* 1 hour */
#endif /* DEBUG */
TRACE_DEBUG(NONE, "Monitor information");
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, 0, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_SERV, 0, NULL), /* continue */);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, 0, NULL), /* continue */);
pthread_testcancel();
}
......
......@@ -9,6 +9,7 @@ SET_SOURCE_FILES_PROPERTIES(lex.fdd.c fdd.tab.c PROPERTIES COMPILE_FLAGS "-I ${C
# List of source files
SET(FD_COMMON_SRC
fD.h
cnxctx.h
config.c
cnxctx.c
dispatch.c
......@@ -25,7 +26,7 @@ SET(FD_COMMON_SRC
)
IF(NOT DISABLE_SCTP)
SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c)
SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c sctps.c)
ENDIF(NOT DISABLE_SCTP)
SET(FD_COMMON_GEN_SRC
......
This diff is collapsed.
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@nict.go.jp> *
* *
* Copyright (c) 2009, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *
* *
* * Neither the name of the WIDE Project or NICT nor the *
* names of its contributors may be used to endorse or *
* promote products derived from this software without *
* specific prior written permission of WIDE Project and *
* NICT. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
/* This file contains the definitions for internal use in the connection context files */
#ifndef _CNXCTX_H
#define _CNXCTX_H
/* The connection context structure */
struct cnxctx {
char cc_id[60]; /* The name of this connection */
char cc_remid[60]; /* Id of remote peer */
int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */
int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */
int cc_tls; /* Is TLS already started ? */
pthread_t cc_rcvthr; /* thread for receiving messages on the connection */
int cc_loop; /* tell the thread if it loops or stops after the first message is received */
struct fifo * cc_incoming; /* FIFO queue of events received on the connection, FDEVP_CNX_* */
struct fifo * cc_alt; /* alternate fifo to send FDEVP_CNX_* events to. */
#define Target_Queue(cnx) ((cnx)->cc_alt ?: (cnx)->cc_incoming)
/* If cc_tls == true */
struct {
int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */
gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */
} cc_tls_para;
/* If cc_proto == SCTP */
struct {
uint16_t str_out; /* Out streams */
uint16_t str_in; /* In streams */
uint16_t pairs; /* max number of pairs ( = min(in, out)) */
uint16_t next; /* # of stream the next message will be sent to */
} cc_sctp_para;
/* If both conditions */
struct {
struct sctps_ctx *array; /* an array of cc_sctp_para.pairs elements -- the #0 is special (session is outside)*/
struct sr_store *sess_store; /* Session data of the master session, to resume the children sessions */
} cc_sctps_data;
};
/* TLS */
int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session);
int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority);
/* TCP */
int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );
int fd_tcp_listen( int sock );
int fd_tcp_client( int *sock, sSA * sa, socklen_t salen );
int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl);
int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);
#ifndef DISABLE_SCTP
/* SCTP */
int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port );
int fd_sctp_listen( int sock );
int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );
int fd_sctp_get_local_ep(int sock, struct fd_list * list);
int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary );
int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len);
int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event);
/* TLS over SCTP (multi-stream) */
struct sctps_ctx {
struct cnxctx *parent; /* for info such as socket, conn name, event list */
uint16_t strid; /* Stream # of this session */
struct fifo *raw_recv; /* Raw data received on this stream, for demux */
struct {
uint8_t *buf;
size_t bufsz;
size_t offset;
} partial; /* If the pull function did not read the full content of first message in raw, it stores it here for next read call. */
pthread_t thr; /* Thread to decrypt raw data in this pair of streams */
gnutls_session_t session; /* TLS context using this pair of streams -- except if strid == 0, in that case session is outside the array */
};
int fd_sctps_init(struct cnxctx * conn);
int fd_sctps_handshake_others(struct cnxctx * conn, char * priority);
int fd_sctps_startthreads(struct cnxctx * conn);
void fd_sctps_stopthreads(struct cnxctx * conn);
void fd_sctps_destroy(struct cnxctx * conn);
#endif /* DISABLE_SCTP */
#endif /* _CNXCTX_H */
......@@ -151,13 +151,19 @@ struct fd_peer { /* The "real" definition of the peer structure */
/* Events codespace for struct fd_peer->p_events */
enum {
/* Dump all info about this peer in the debug log */
FDEVP_DUMP_ALL = 2000
FDEVP_DUMP_ALL = 1500
/* request to terminate this peer : disconnect, requeue all messages */
,FDEVP_TERMINATE
/* A connection object has received a message -- stored in event->data */
/* A connection object has received a message. */
,FDEVP_CNX_MSG_RECV
/* A connection object has encountered an error (disconnected). */
,FDEVP_CNX_ERROR
/* Endpoints of a connection have been changed (multihomed SCTP). */
,FDEVP_CNX_EP_CHANGE
/* A message was received in the peer */
,FDEVP_MSG_INCOMING
......@@ -209,7 +215,7 @@ struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
char * fd_cnx_getid(struct cnxctx * conn);
int fd_cnx_start_clear(struct cnxctx * conn);
int fd_cnx_start_clear(struct cnxctx * conn, int loop);
int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority);
int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote);
......@@ -219,24 +225,5 @@ int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* sen
int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len);
void fd_cnx_destroy(struct cnxctx * conn);
/* TCP */
int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );
int fd_tcp_listen( int sock );
int fd_tcp_client( int *sock, sSA * sa, socklen_t salen );
int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl);
int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);
/* SCTP */
#ifndef DISABLE_SCTP
int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port );
int fd_sctp_listen( int sock );
int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );
int fd_sctp_get_local_ep(int sock, struct fd_list * list);
int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary );
#endif /* DISABLE_SCTP */
#endif /* _FD_H */
......@@ -116,8 +116,8 @@ int main(int argc, char * argv[])
/* Now, just wait for events */
TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
while (1) {
int code;
CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, NULL), break );
int code; size_t sz; void * data;
CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break );
switch (code) {
case FDEV_DUMP_DICT:
fd_dict_dump(fd_g_config->cnf_dict);
......@@ -338,7 +338,7 @@ static void * sig_hdl(void * arg)
CHECK_SYS_DO( sigwait(&sig_main, &sig), TRACE_DEBUG(INFO, "Error in sigwait function") );
TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig);
CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) );
CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) );
return NULL;
}
......@@ -86,7 +86,7 @@ static void * gc_th_fct(void * arg)
error:
TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating...");
ASSERT(0);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
return NULL;
}
......@@ -131,7 +131,7 @@ static void * exp_th_fct(void * arg)
/* Now, the first peer in the list is expired; signal it */
fd_list_unlink( &first->p_expiry );
CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, NULL), goto error );
CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, NULL), goto error );
} while (1);
......@@ -139,7 +139,7 @@ static void * exp_th_fct(void * arg)
error:
TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating...");
ASSERT(0);
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
return NULL;
}
......
......@@ -57,6 +57,8 @@ const char * fd_pev_str(int event)
case_str(FDEVP_DUMP_ALL);
case_str(FDEVP_TERMINATE);
case_str(FDEVP_CNX_MSG_RECV);
case_str(FDEVP_CNX_ERROR);
case_str(FDEVP_CNX_EP_CHANGE);
case_str(FDEVP_MSG_INCOMING);
case_str(FDEVP_PSM_TIMEOUT);
......@@ -125,34 +127,13 @@ static void psm_next_timeout(struct fd_peer * peer, int add_random, int delay)
#endif
}
/* Wait for the next event in the PSM, or timeout */
static int psm_ev_timedget(struct fd_peer * peer, int *code, void ** data)
{
struct fd_event * ev;
int ret = 0;
TRACE_ENTRY("%p %p %p", peer, code, data);
ret = fd_fifo_timedget(peer->p_events, &ev, &peer->p_psm_timer);
if (ret == ETIMEDOUT) {
*code = FDEVP_PSM_TIMEOUT;
*data = NULL;
} else {
CHECK_FCT( ret );
*code = ev->code;
*data = ev->data;
free(ev);
}
return 0;
}
/* The state machine thread (controler) */
static void * p_psm_th( void * arg )
{
struct fd_peer * peer = (struct fd_peer *)arg;
int created_started = started;
int event;
size_t ev_sz;
void * ev_data;
CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
......@@ -181,10 +162,10 @@ static void * p_psm_th( void * arg )
psm_loop:
/* Get next event */
CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto psm_end );
TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p)\t'%s'",
CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%g)\t'%s'",
STATE_STR(peer->p_hdr.info.pi_state),
fd_pev_str(event), ev_data,
fd_pev_str(event), ev_data, ev_sz,
peer->p_hdr.info.pi_diamid);
/* Now, the action depends on the current state and the incoming event */
......@@ -271,7 +252,7 @@ int fd_psm_terminate(struct fd_peer * peer )
CHECK_PARAMS( CHECK_PEER(peer) );
if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) {
CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );
CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
} else {
TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
}
......
......@@ -34,9 +34,16 @@
*********************************************************************************************************/
#include "fD.h"
#include "cnxctx.h"
#include <netinet/sctp.h>
#include <sys/uio.h>
/* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */
#ifndef CMSG_BUF_LEN
#define CMSG_BUF_LEN 1024
#endif /* CMSG_BUF_LEN */
/* Pre-binding socket options -- # streams read in config */
static int fd_setsockopt_prebind(int sk)
{
......@@ -743,7 +750,7 @@ fail:
}
/* Retrieve streams information from a connected association -- optionaly provide the primary address */
int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary )
int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )
{
struct sctp_status status;
socklen_t sz = sizeof(status);
......@@ -775,8 +782,8 @@ int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary )
TRACE_DEBUG(FULL, " sstat_primary.spinfo_mtu : %u" , status.sstat_primary.spinfo_mtu);
#endif /* DEBUG_SCTP */
*in = (int)status.sstat_instrms;
*out = (int)status.sstat_outstrms;
*in = status.sstat_instrms;
*out = status.sstat_outstrms;
if (primary)
memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS));
......@@ -892,3 +899,218 @@ int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
return 0;
}
/* Send a buffer over a specified stream */
int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len)
{
struct msghdr mhdr;
struct iovec iov;
struct {
struct cmsghdr hdr;
struct sctp_sndrcvinfo sndrcv;
} anci;
ssize_t ret;
TRACE_ENTRY("%d %hu %p %g", sock, strid, buf, len);
memset(&mhdr, 0, sizeof(mhdr));
memset(&iov, 0, sizeof(iov));
memset(&anci, 0, sizeof(anci));
/* IO Vector: message data */
iov.iov_base = buf;
iov.iov_len = len;
/* Anciliary data: specify SCTP stream */
anci.hdr.cmsg_len = sizeof(anci);
anci.hdr.cmsg_level = IPPROTO_SCTP;
anci.hdr.cmsg_type = SCTP_SNDRCV;
anci.sndrcv.sinfo_stream = strid;
/* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */
/* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */
mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1;
mhdr.msg_control = &anci;
mhdr.msg_controllen = sizeof(anci);
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock);
#endif /* DEBUG_SCTP */
CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) );
ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */
return 0;
}
/* Receive the next data from the socket, or next notification */
int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event)
{
ssize_t ret = 0;
struct msghdr mhdr;
char ancidata[ CMSG_BUF_LEN ];
struct iovec iov;
uint8_t *data = NULL;
size_t bufsz = 0, datasize = 0;
size_t mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event);
CHECK_PARAMS( (sock > 0) && buf && len && event );
/* Cleanup out parameters */
*buf = NULL;
*len = 0;
*event = 0;
/* Prepare header for receiving message */
memset(&mhdr, 0, sizeof(mhdr));
mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1;
mhdr.msg_control = &ancidata;
mhdr.msg_controllen = sizeof(ancidata);
/* We will loop while all data is not received. */
incomplete:
if (datasize == bufsz) {
/* The buffer is full, enlarge it */
bufsz += mempagesz;
CHECK_MALLOC( data = realloc(data, bufsz) );
}
/* the new data will be received following the preceding */
memset(&iov, 0, sizeof(iov));
iov.iov_base = data + datasize ;
iov.iov_len = bufsz - datasize;
/* Receive data from the socket */
pthread_cleanup_push(free, data);
ret = recvmsg(sock, &mhdr, 0);
pthread_cleanup_pop(0);
/* Handle errors */
if (ret <= 0) { /* Socket is closed, or an error occurred */
CHECK_SYS_DO(ret, /* to log in case of error */);
free(data);
*event = FDEVP_CNX_ERROR;
return 0;
}
/* Update the size of data we received */
datasize += ret;
/* SCTP provides an indication when we received a full record; loop if it is not the case */
if ( ! (mhdr.msg_flags & MSG_EOR) ) {
goto incomplete;
}
/* Handle the case where the data received is a notification */
if (mhdr.msg_flags & MSG_NOTIFICATION) {
union sctp_notification * notif = (union sctp_notification *) data;
switch (notif->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification");
TRACE_DEBUG(FULL, " state : %hu", notif->sn_assoc_change.sac_state);
TRACE_DEBUG(FULL, " error : %hu", notif->sn_assoc_change.sac_error);
TRACE_DEBUG(FULL, " instr : %hu", notif->sn_assoc_change.sac_inbound_streams);
TRACE_DEBUG(FULL, " outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);
#endif /* DEBUG_SCTP */
*event = FDEVP_CNX_EP_CHANGE;
break;
case SCTP_PEER_ADDR_CHANGE:
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");
TRACE_DEBUG_sSA(FULL, " intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" );
TRACE_DEBUG(FULL, " state : %d", notif->sn_paddr_change.spc_state);
TRACE_DEBUG(FULL, " error : %d", notif->sn_paddr_change.spc_error);
#endif /* DEBUG_SCTP */
*event = FDEVP_CNX_EP_CHANGE;
break;
case SCTP_SEND_FAILED:
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification");
TRACE_DEBUG(FULL, " len : %hu", notif->sn_send_failed.ssf_length);
TRACE_DEBUG(FULL, " err : %d", notif->sn_send_failed.ssf_error);
#endif /* DEBUG_SCTP */
*event = FDEVP_CNX_ERROR;
break;
case SCTP_REMOTE_ERROR:
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification");
TRACE_DEBUG(FULL, " err : %hu", ntohs(notif->sn_remote_error.sre_error));
TRACE_DEBUG(FULL, " len : %hu", ntohs(notif->sn_remote_error.sre_length));
#endif /* DEBUG_SCTP */
*event = FDEVP_CNX_ERROR;
break;
case SCTP_SHUTDOWN_EVENT:
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification");
#endif /* DEBUG_SCTP */
*event = FDEVP_CNX_ERROR;
break;
default:
TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type);
*event = FDEVP_CNX_ERROR;
}
free(data);
return 0;
}
/* From this point, we have received a message */
*event = FDEVP_CNX_MSG_RECV;
*buf = data;
*len = datasize;
if (strid) {
struct cmsghdr *hdr;
struct sctp_sndrcvinfo *sndrcv;
/* Handle the anciliary data */
for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) {
/* We deal only with anciliary data at SCTP level */
if (hdr->cmsg_level != IPPROTO_SCTP) {
TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level);
continue;
}
/* Also only interested in SCTP_SNDRCV message for the moment */
if (hdr->cmsg_type != SCTP_SNDRCV) {
TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type);
continue;
}
sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr);
#ifdef DEBUG_SCTP
TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV");
TRACE_DEBUG(FULL, " sinfo_stream : %hu", sndrcv->sinfo_stream);
TRACE_DEBUG(FULL, " sinfo_ssn : %hu", sndrcv->sinfo_ssn);
TRACE_DEBUG(FULL, " sinfo_flags : %hu", sndrcv->sinfo_flags);
/* TRACE_DEBUG(FULL, " sinfo_pr_policy : %hu", sndrcv->sinfo_pr_policy); */
TRACE_DEBUG(FULL, " sinfo_ppid : %u" , sndrcv->sinfo_ppid);
TRACE_DEBUG(FULL, " sinfo_context : %u" , sndrcv->sinfo_context);
/* TRACE_DEBUG(FULL, " sinfo_pr_value : %u" , sndrcv->sinfo_pr_value); */
TRACE_DEBUG(FULL, " sinfo_tsn : %u" , sndrcv->sinfo_tsn);
TRACE_DEBUG(FULL, " sinfo_cumtsn : %u" , sndrcv->sinfo_cumtsn);
#endif /* DEBUG_SCTP */
*strid = sndrcv->sinfo_stream;
}
}
return 0;
}
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@nict.go.jp> *
* *
* Copyright (c) 2009, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *