Skip to content

Commit

Permalink
Add SCTP proto as module/proto_sctp
Browse files Browse the repository at this point in the history
  • Loading branch information
bogdan-iancu committed Feb 19, 2015
1 parent 5e5aec4 commit 3c1043b
Show file tree
Hide file tree
Showing 4 changed files with 398 additions and 0 deletions.
11 changes: 11 additions & 0 deletions modules/proto_sctp/Makefile
@@ -0,0 +1,11 @@
#
# WARNING: do not run this directly, it should be run by the master Makefile

include ../../Makefile.defs
auto_gen=
NAME=proto_sctp.so

LIBS += -lsctp

include ../../Makefile.modules

80 changes: 80 additions & 0 deletions modules/proto_sctp/proto_sctp.c
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2015 OpenSIPS Foundation
*
* This file is part of opensips, a free SIP server.
*
* opensips is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* opensips is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* History:
* -------
* 2015-02-12 first version (bogdan)
*/


#include "../../dprint.h"
#include "../../net/trans.h"
#include "../../sr_module.h"


#include "sctp_server.h"

static int proto_sctp_init(struct proto_info *pi);

static cmd_export_t cmds[] = {
{"proto_init", (cmd_function)proto_sctp_init, 0, 0, 0, 0},
{0,0,0,0,0,0}
};


static param_export_t params[] = {
{0, 0, 0}
};

struct module_exports exports = {
PROTO_PREFIX "sctp", /* module name*/
MOD_TYPE_DEFAULT, /* class of this module */
MODULE_VERSION,
DEFAULT_DLFLAGS, /* dlopen flags */
NULL, /* OpenSIPS module dependencies */
cmds, /* exported functions */
0, /* exported async functions */
params, /* module parameters */
0, /* exported statistics */
0, /* exported MI functions */
0, /* exported pseudo-variables */
0, /* extra processes */
0, /* module initialization function */
0, /* response function */
0, /* destroy function */
0, /* per-child init function */
};


static int proto_sctp_init(struct proto_info *pi)
{
pi->default_port = SIP_PORT;

pi->tran.init_listener = proto_sctp_init_listener;
pi->tran.send = proto_sctp_send;

pi->net.flags = PROTO_NET_USE_UDP;
pi->net.read = (proto_net_read_f)proto_sctp_read;

return 0;
}



260 changes: 260 additions & 0 deletions modules/proto_sctp/sctp_server.c
@@ -0,0 +1,260 @@
/*
* Copyright (C) 2001-2003 FhG Fokus
*
* This file is part of opensips, a free SIP server.
*
* opensips is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* opensips is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* History
* --------
* 2007-06-22 sctp_server.c created, using udp_server.c as template -gmarmon
*
*/

/*!
* \file
* \brief SCTP support
*/

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <errno.h>
#include <arpa/inet.h>
#ifdef __linux__
#include <linux/types.h>
#include <linux/errqueue.h>
#endif

#include "../../mem/shm_mem.h"
#include "../../sr_module.h"
#include "../../net/net_udp.h"
#include "../../socket_info.h"
#include "../../receive.h"
#include "sctp_server.h"

#define LISTEN_BACKLOG 5

int proto_sctp_init_listener(struct socket_info* si)
{
union sockaddr_union* addr;
int optval;

addr=&sock_info->su;
sock_info->proto=PROTO_SCTP;
if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
LM_ERR("could not init sockaddr_union\n");
goto error;
}

sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET,
IPPROTO_SCTP);
if (sock_info->socket==-1){
LM_ERR("socket failed with %s [%d]\n", strerror(errno), errno);
goto error;
}

optval=1;
if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR ,
(void*)&optval, sizeof(optval)) ==-1){
LM_ERR("setsockopt: %s\n", strerror(errno));
goto error;
}

#ifdef DISABLE_NAGLE
/* turns of Nagle-like algorithm/chunk-bundling.*/
optval=1;
if (setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_NODELAY,
(void*)&optval, sizeof(optval))==-1){
LM_WARN("setsockopt %s\n", strerror(errno));
/* continues since this is not critical */
}
#endif

/* tos */

/* this sockopt causes a kernel panic in some sctp implementations.
* commenting it out. -gmarmon */

/*
optval=tos;
if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval,
sizeof(optval)) ==-1){
LM_WARN("setsockopt tos: %s\n", strerror(errno));
}
*/

#if defined (__linux__) && defined(SCTP_ERRORS)
/* will SCTP_ERRORS ever be defined? -gmarmon */
optval=1;
/* enable error receiving on unconnected sockets */
if(setsockopt(sock_info->socket, SOL_IP, IP_RECVERR,
(void*)&optval, sizeof(optval)) ==-1){
LM_ERR("setsockopt: %s\n", strerror(errno));
goto error;
}
#endif

/*if ( probe_max_receive_buffer(sock_info->socket)==-1) goto error;
*/

if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
LM_ERR("bind(%x, %p, %d) on %s: %s\n",
sock_info->socket, &addr->s,
(unsigned)sockaddru_len(*addr),
sock_info->address_str.s,
strerror(errno));
if (addr->s.sa_family==AF_INET6)
LM_ERR("might be caused by using a link "
" local address, try site local or global\n");
goto error;
}
if(listen(sock_info->socket, LISTEN_BACKLOG)<0){
LM_ERR("listen(%x, %d) on %s: %s\n",
sock_info->socket,
LISTEN_BACKLOG,
sock_info->address_str.s,
strerror(errno));
goto error;
}
return 0;

error:
return -1;
}



int sctp_server_rcv_loop(void)
{
int len;
#ifdef DYN_BUF
char* buf;
#else
static char buf [BUF_SIZE+1];
#endif
char *tmp;
union sockaddr_union* from;
unsigned int fromlen;
struct receive_info ri;
struct sctp_sndrcvinfo sinfo;


from=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union));
if (from==0){
LM_ERR("out of pkg memory\n");
goto error;
}
memset(&sinfo, 0 , sizeof(sinfo));
ri.bind_address=bind_address; /* this will not change, we do it only once*/
ri.dst_port=bind_address->port_no;
ri.dst_ip=bind_address->address;
ri.proto=PROTO_SCTP;
ri.proto_reserved1=ri.proto_reserved2=0;
for(;;){
#ifdef DYN_BUF
buf=pkg_malloc(BUF_SIZE+1);
if (buf==0){
LM_ERR(" could not allocate receive buffer in pkg memory\n");
goto error;
}
#endif
fromlen=sockaddru_len(bind_address->su);
len = sctp_recvmsg(bind_address->socket, buf, BUF_SIZE, &from->s, &fromlen, &sinfo, 0);

if (len==-1){
if (errno==EAGAIN){
LM_DBG("packet with bad checksum received\n");
continue;
}
LM_ERR("sctp_recvmsg:[%d] %s\n", errno, strerror(errno));
if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
continue; /* goto skip;*/
else goto error;
}
/* we must 0-term the messages, receive_msg expects it */
buf[len]=0; /* no need to save the previous char */

ri.src_su=*from;
su2ip_addr(&ri.src_ip, from);
ri.src_port=su_getport(from);

#ifndef NO_ZERO_CHECKS
if (buf[len-1]==0) {
tmp=ip_addr2a(&ri.src_ip);
LM_WARN("upstream bug - 0-terminated packet from %s %d\n",
tmp, htons(ri.src_port));
len--;
}
#endif
if (ri.src_port==0){
tmp=ip_addr2a(&ri.src_ip);
LM_INFO("dropping 0 port packet from %s\n", tmp);
continue;
}


/* receive_msg must free buf too!*/
receive_msg(buf, len, &ri);

/* skip: do other stuff */

}
/*
if (from) pkg_free(from);
return 0;
*/

error:
if (from) pkg_free(from);
return -1;
}




/*! \brief which socket to use? main socket or new one? */
int sctp_server_send(struct socket_info *source, char *buf, unsigned len,
union sockaddr_union* to)
{
int n;
int tolen;

tolen=sockaddru_len(*to);
again:
n=sctp_sendmsg(source->socket, buf, len, &to->s, tolen, 0, 0, 0, 0, 0);
#ifdef XL_DEBUG
LM_INFO("send status: %d\n", n);
#endif
if (n==-1){
LM_ERR("sctp_sendmsg(sock,%p,%d,%p,%d,0,0,0,0,0): %s(%d)\n",
buf,len,&to->s,tolen, strerror(errno),errno);

if (errno==EINTR) goto again;
if (errno==EINVAL) {
LM_CRIT("invalid sendtoparameters\n"
"one possible reason is the server is bound to localhost and\n"
"attempts to send to the net\n");
}
}
return n;
}

#endif

0 comments on commit 3c1043b

Please sign in to comment.