1550 lines
50 KiB
C++
1550 lines
50 KiB
C++
/******************************************************************************
|
|
* Copyright (c) 2005, 2014 Ericsson AB
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* Peter Dimitrov- initial implementation and initial documentation
|
|
* Adam Delic
|
|
* Eduard Czimbalmos
|
|
* Endre Kulcsar
|
|
* Gabor Bettesch
|
|
* Gabor Szalai
|
|
* Tamas Buti
|
|
* Zoltan Medve
|
|
******************************************************************************/
|
|
//
|
|
// File: SCTPasp_PT.cc
|
|
// Description: SCTPasp test port source
|
|
// Rev: R11A
|
|
// Prodnr: CNL 113 469
|
|
//
|
|
|
|
|
|
#include "SCTPasp_PT.hh"
|
|
|
|
#include <sys/types.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
#include <stdarg.h>
|
|
#include <memory.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
|
|
#define BUFLEN 1024
|
|
#define MAP_LENGTH 10
|
|
#ifdef SCTP_ADAPTION_LAYER
|
|
#ifdef LKSCTP_1_0_7
|
|
#undef LKSCTP_1_0_7
|
|
#error LKSCTP_1_0_7 defined but the lksctp older than 1.0.7. Use only -DUSE_SCTP, version is automatically selected
|
|
#endif
|
|
#ifdef LKSCTP_1_0_9
|
|
#error LKSCTP_1_0_9 defined but the lksctp older than 1.0.7. Use only -DUSE_SCTP, version is automatically selected
|
|
#undef LKSCTP_1_0_9
|
|
#endif
|
|
#else
|
|
// 1.0.7 or newer
|
|
#ifdef SCTP_AUTH_CHUNK
|
|
// 1.0.9 or newer
|
|
#ifdef LKSCTP_1_0_7
|
|
#undef LKSCTP_1_0_7
|
|
#error LKSCTP_1_0_7 defined but the lksctp newer than 1.0.7. Use only -DUSE_SCTP, version is automatically selected
|
|
#endif
|
|
#ifndef LKSCTP_1_0_9
|
|
#define LKSCTP_1_0_9
|
|
#endif
|
|
#else
|
|
// 1.0.7
|
|
#ifdef LKSCTP_1_0_9
|
|
#undef LKSCTP_1_0_9
|
|
#error LKSCTP_1_0_9 defined but the lksctp older than 1.0.9. Use only -DUSE_SCTP, version is automatically selected
|
|
#endif
|
|
#ifndef LKSCTP_1_0_7
|
|
#define LKSCTP_1_0_7
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
namespace SCTPasp__PortType {
|
|
|
|
struct SCTPasp__PT_PROVIDER::fd_map_item
|
|
{ // used by map operations
|
|
int fd; // socket descriptor
|
|
boolean erased;
|
|
boolean processing_message; // if true only part of the message is received
|
|
boolean einprogress; // connection establishment is in progress
|
|
void * buf; // buffer
|
|
ssize_t buflen; // length of the buffer
|
|
ssize_t nr; // number of received bytes
|
|
struct sockaddr_in sin; // storing remote address
|
|
};
|
|
|
|
|
|
struct SCTPasp__PT_PROVIDER::fd_map_server_item // server item
|
|
{ // used by map operations
|
|
int fd; // socket descriptor
|
|
boolean erased;
|
|
struct in_addr local_IP_address;
|
|
unsigned short local_port;
|
|
};
|
|
|
|
|
|
SCTPasp__PT_PROVIDER::SCTPasp__PT_PROVIDER(const char *par_port_name)
|
|
: PORT(par_port_name)
|
|
{
|
|
simple_mode = FALSE;
|
|
reconnect = FALSE;
|
|
reconnect_max_attempts = 6;
|
|
server_mode = FALSE;
|
|
debug = FALSE;
|
|
server_backlog = 1;
|
|
local_IP_address.s_addr = INADDR_ANY;
|
|
(void) memset(&initmsg, 0, sizeof(struct sctp_initmsg));
|
|
initmsg.sinit_num_ostreams = 64;
|
|
initmsg.sinit_max_instreams = 64;
|
|
initmsg.sinit_max_attempts = 0;
|
|
initmsg.sinit_max_init_timeo = 0;
|
|
(void) memset(&events, 0, sizeof (events));
|
|
events.sctp_data_io_event = TRUE;
|
|
events.sctp_association_event = TRUE;
|
|
events.sctp_address_event = TRUE;
|
|
events.sctp_send_failure_event = TRUE;
|
|
events.sctp_peer_error_event = TRUE;
|
|
events.sctp_shutdown_event = TRUE;
|
|
events.sctp_partial_delivery_event = TRUE;
|
|
#if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9)
|
|
events.sctp_adaptation_layer_event = TRUE;
|
|
#else
|
|
events.sctp_adaption_layer_event = TRUE;
|
|
#endif
|
|
local_port_is_present = FALSE;
|
|
peer_IP_address_is_present = FALSE;
|
|
peer_port_is_present = FALSE;
|
|
|
|
fd_map=NULL;
|
|
list_len=0;
|
|
|
|
fd_map_server=NULL;
|
|
list_len_server=0;
|
|
|
|
fd = -1;
|
|
FD_ZERO(&readfds);
|
|
FD_ZERO(&writefds);
|
|
local_port=-1;
|
|
peer_port=-1;
|
|
receiving_fd=-1;
|
|
}
|
|
|
|
|
|
SCTPasp__PT_PROVIDER::~SCTPasp__PT_PROVIDER()
|
|
{
|
|
for(int i=0;i<list_len;i++) map_delete_item(i);
|
|
Free(fd_map);
|
|
|
|
if(!simple_mode)
|
|
{
|
|
for(int i=0;i<list_len_server;i++) map_delete_item_server(i);
|
|
Free(fd_map_server);
|
|
}
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::set_parameter(const char *parameter_name,
|
|
const char *parameter_value)
|
|
{
|
|
|
|
if(strcmp(parameter_name, "simple_mode") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"yes") == 0)
|
|
simple_mode = TRUE;
|
|
else if(strcasecmp(parameter_value,"no") == 0)
|
|
simple_mode = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. Only yes and no can be used!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "reconnect") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"yes") == 0)
|
|
reconnect = TRUE;
|
|
else if(strcasecmp(parameter_value,"no") == 0)
|
|
reconnect = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. Only yes and no can be used!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "reconnect_max_attempts") == 0)
|
|
{
|
|
int value;
|
|
if ( (sscanf(parameter_value, "%d", &value) == 1) && (value>=0) )
|
|
reconnect_max_attempts = value;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "server_mode") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"yes") == 0)
|
|
server_mode = TRUE;
|
|
else if(strcasecmp(parameter_value,"no") == 0)
|
|
server_mode = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. Only yes and no can be used!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "debug") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"yes") == 0)
|
|
debug = TRUE;
|
|
else if(strcasecmp(parameter_value,"no") == 0)
|
|
debug = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. Only yes and no can be used!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "server_backlog") == 0)
|
|
{
|
|
int value;
|
|
if ( (sscanf(parameter_value, "%d", &value) == 1) && (value>=0) )
|
|
server_backlog = value;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "local_IP_address") == 0)
|
|
{
|
|
local_IP_address = get_in_addr((const char *) parameter_value);
|
|
}
|
|
else if(strcmp(parameter_name, "local_port") == 0)
|
|
{
|
|
unsigned short value;
|
|
if (sscanf(parameter_value, "%hu", &value) == 1)
|
|
{
|
|
local_port = value;
|
|
local_port_is_present = TRUE;
|
|
}
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "peer_IP_address") == 0)
|
|
{
|
|
peer_IP_address = get_in_addr((const char *) parameter_value);
|
|
peer_IP_address_is_present = TRUE;
|
|
}
|
|
else if(strcmp(parameter_name, "peer_port") == 0)
|
|
{
|
|
unsigned short value;
|
|
if (sscanf(parameter_value, "%hu", &value) == 1)
|
|
{
|
|
peer_port = value;
|
|
peer_port_is_present = TRUE;
|
|
}
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sinit_num_ostreams") == 0)
|
|
{
|
|
long value;
|
|
if ( (sscanf(parameter_value, "%ld", &value) == 1) && (value>=0) )
|
|
initmsg.sinit_num_ostreams = value;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sinit_max_instreams") == 0)
|
|
{
|
|
long value;
|
|
if ( (sscanf(parameter_value, "%ld", &value) == 1) && (value>=0) )
|
|
initmsg.sinit_max_instreams = value;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sinit_max_attempts") == 0)
|
|
{
|
|
long value;
|
|
if ( (sscanf(parameter_value, "%ld", &value) == 1) && (value>=0) )
|
|
initmsg.sinit_max_attempts = value;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sinit_max_init_timeo") == 0)
|
|
{
|
|
long value;
|
|
if ( (sscanf(parameter_value, "%ld", &value) == 1) && (value>=0) )
|
|
initmsg.sinit_max_init_timeo = value;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be positive integer!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_association_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
events.sctp_association_event = TRUE;
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
events.sctp_association_event = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_address_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
events.sctp_address_event = TRUE;
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
events.sctp_address_event = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_send_failure_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
events.sctp_send_failure_event = TRUE;
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
events.sctp_send_failure_event = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_peer_error_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
events.sctp_peer_error_event = TRUE;
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
events.sctp_peer_error_event = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_shutdown_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
events.sctp_shutdown_event = TRUE;
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
events.sctp_shutdown_event = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_partial_delivery_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
events.sctp_partial_delivery_event = TRUE;
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
events.sctp_partial_delivery_event = FALSE;
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else if(strcmp(parameter_name, "sctp_adaption_layer_event") == 0)
|
|
{
|
|
if (strcasecmp(parameter_value,"enabled") == 0)
|
|
#if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9)
|
|
events.sctp_adaptation_layer_event = TRUE;
|
|
#else
|
|
events.sctp_adaption_layer_event = TRUE;
|
|
#endif
|
|
else if(strcasecmp(parameter_value,"disabled") == 0)
|
|
#if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9)
|
|
events.sctp_adaptation_layer_event = FALSE;
|
|
#else
|
|
events.sctp_adaption_layer_event = FALSE;
|
|
#endif
|
|
else
|
|
error("set_parameter(): Invalid parameter value: %s for parameter %s. It should be enabled or disabled!" ,
|
|
parameter_value, parameter_name);
|
|
}
|
|
else
|
|
TTCN_warning("%s: unknown & unhandled parameter: %s",
|
|
get_name(), parameter_name);
|
|
errno = 0;
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::Event_Handler(const fd_set *read_fds,
|
|
const fd_set *write_fds, const fd_set */*error_fds*/,
|
|
double /*time_since_last_call*/)
|
|
{
|
|
// Accepting new client
|
|
if(!simple_mode)
|
|
{
|
|
for(int i=0;i<list_len_server;i++)
|
|
{
|
|
if(!fd_map_server[i].erased && FD_ISSET(fd_map_server[i].fd, read_fds))
|
|
{
|
|
int newclient_fd;
|
|
struct sockaddr_in peer_address;
|
|
socklen_t addrlen = sizeof(peer_address);
|
|
if ((newclient_fd = accept(fd_map_server[i].fd, (struct sockaddr *)&peer_address, &addrlen)) == -1)
|
|
error("Event handler: accept error (server mode)!");
|
|
else
|
|
{
|
|
map_put_item(newclient_fd);
|
|
setNonBlocking(newclient_fd);
|
|
FD_SET(newclient_fd, &readfds);
|
|
incoming_message(SCTPasp__Types::ASP__SCTP__Connected(
|
|
INTEGER(newclient_fd),
|
|
CHARSTRING(inet_ntoa(fd_map_server[i].local_IP_address)),
|
|
INTEGER(fd_map_server[i].local_port),
|
|
CHARSTRING(inet_ntoa(peer_address.sin_addr)),
|
|
INTEGER(ntohs(peer_address.sin_port))));
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(server_mode && FD_ISSET(fd, read_fds))
|
|
{
|
|
int newclient_fd;
|
|
struct sockaddr_in peer_address;
|
|
socklen_t addrlen = sizeof(peer_address);
|
|
if ((newclient_fd = accept(fd, (struct sockaddr *)&peer_address, &addrlen)) == -1)
|
|
error("Event handler: accept error (server mode)!");
|
|
else
|
|
{
|
|
map_put_item(newclient_fd);
|
|
setNonBlocking(newclient_fd);
|
|
FD_SET(newclient_fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
}
|
|
}
|
|
}
|
|
// Receiving data
|
|
for(int i=0;i<list_len;i++)
|
|
{
|
|
if(!simple_mode && !fd_map[i].erased && fd_map[i].einprogress &&
|
|
FD_ISSET(fd_map[i].fd, write_fds))
|
|
{
|
|
if (connect(fd_map[i].fd, (struct sockaddr *)&fd_map[i].sin,
|
|
sizeof (fd_map[i].sin)) == -1)
|
|
{
|
|
if(errno == EISCONN)
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd_map[i].fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
fd_map[i].einprogress = FALSE;
|
|
FD_CLR(fd_map[i].fd, &writefds);
|
|
FD_SET(fd_map[i].fd, &readfds);
|
|
Install_Handler(&readfds, &writefds, NULL, 0.0);
|
|
errno = 0;
|
|
log("Connection successfully established to (%s):(%d)",
|
|
inet_ntoa(peer_IP_address), peer_port);
|
|
}
|
|
else
|
|
{
|
|
close(fd_map[i].fd);
|
|
fd = -1;
|
|
TTCN_warning("Connect error!");
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd_map[i].fd;
|
|
asp_sctp_result.error__status() = TRUE;
|
|
asp_sctp_result.error__message() = strerror(errno);
|
|
incoming_message(asp_sctp_result);
|
|
FD_CLR(fd_map[i].fd, &writefds);
|
|
map_delete_item_fd(fd_map[i].fd);
|
|
Install_Handler(&readfds, &writefds, NULL, 0.0);
|
|
errno = 0;
|
|
log("Connection establishment to (%s):(%d) failed !",
|
|
inet_ntoa(peer_IP_address), peer_port);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!fd_map[i].erased && FD_ISSET(fd_map[i].fd, read_fds))
|
|
{
|
|
log("Calling Event_Handler.");
|
|
receiving_fd = fd_map[i].fd;
|
|
|
|
struct cmsghdr *cmsg;
|
|
struct sctp_sndrcvinfo *sri;
|
|
char cbuf[sizeof (*cmsg) + sizeof (*sri)];
|
|
struct msghdr msg;
|
|
struct iovec iov;
|
|
size_t cmsglen = sizeof (*cmsg) + sizeof (*sri);
|
|
|
|
if ( !fd_map[i].processing_message )
|
|
{
|
|
fd_map[i].buf = Malloc(BUFLEN);
|
|
fd_map[i].buflen = BUFLEN;
|
|
iov.iov_base = fd_map[i].buf;
|
|
iov.iov_len = fd_map[i].buflen;
|
|
}
|
|
else
|
|
{
|
|
// Set the next read offset
|
|
log("Event_Handler: setting the next read offset.");
|
|
iov.iov_base = (char *)fd_map[i].buf + fd_map[i].nr;
|
|
iov.iov_len = fd_map[i].buflen - fd_map[i].nr;
|
|
}
|
|
|
|
// Set up the msghdr structure for receiving
|
|
memset(&msg, 0, sizeof (msg));
|
|
msg.msg_iov = &iov;
|
|
msg.msg_iovlen = 1;
|
|
msg.msg_control = cbuf;
|
|
msg.msg_controllen = cmsglen;
|
|
|
|
memset(cbuf, 0, sizeof (*cmsg) + sizeof (*sri));
|
|
cmsg = (struct cmsghdr *)cbuf;
|
|
sri = (struct sctp_sndrcvinfo *)(cmsg + 1);
|
|
|
|
return_value_t value = getmsg(receiving_fd, &msg);
|
|
switch(value)
|
|
{
|
|
case WHOLE_MESSAGE_RECEIVED:
|
|
fd_map[i].processing_message = FALSE;
|
|
// Intercept notifications here
|
|
if (msg.msg_flags & MSG_NOTIFICATION)
|
|
{
|
|
log("Calling event_handler for an incoming notification.");
|
|
handle_event(fd_map[i].buf);
|
|
}
|
|
else
|
|
{
|
|
log("Incoming data.");
|
|
unsigned int ui = ntohl(sri->sinfo_ppid);
|
|
INTEGER i_ppid;
|
|
if (ui <= (unsigned long)INT_MAX)
|
|
i_ppid = ui;
|
|
else {
|
|
char sbuf[16];
|
|
sprintf(sbuf, "%u", ui);
|
|
i_ppid = INTEGER(sbuf);
|
|
}
|
|
incoming_message(SCTPasp__Types::ASP__SCTP(
|
|
INTEGER(receiving_fd),
|
|
INTEGER(sri->sinfo_stream),
|
|
i_ppid,
|
|
OCTETSTRING(fd_map[i].nr,(const unsigned char *)fd_map[i].buf)));
|
|
}
|
|
Free(fd_map[i].buf);
|
|
fd_map[i].buf = NULL;
|
|
break;
|
|
case PARTIAL_RECEIVE:
|
|
fd_map[i].processing_message = TRUE;
|
|
break;
|
|
case EOF_OR_ERROR:
|
|
if (!server_mode) fd = -1; // setting closed socket to -1 in client mode (and reconnect mode)
|
|
FD_CLR(receiving_fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
map_delete_item(i);
|
|
if (events.sctp_association_event) incoming_message(SCTPasp__Types::ASP__SCTP__ASSOC__CHANGE(
|
|
INTEGER(receiving_fd),
|
|
SCTPasp__Types::SAC__STATE(SCTP_COMM_LOST)));
|
|
log("getmsg() returned with NULL. Socket is closed.");
|
|
if (reconnect) forced_reconnect(reconnect_max_attempts);
|
|
|
|
break;
|
|
}//endswitch
|
|
}// endif
|
|
}// endfor
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::user_map(const char *system_port)
|
|
{
|
|
log("Calling user_map(%s).",system_port);
|
|
if(simple_mode)
|
|
{
|
|
if ( server_mode && reconnect )
|
|
{
|
|
error("user_map(): server mode and reconnect mode are mutually exclusive!");
|
|
}
|
|
if ( server_mode && !local_port_is_present )
|
|
{
|
|
error("user_map(): in server mode local_port must be defined!");
|
|
}
|
|
|
|
// Server mode: turns on listening
|
|
if (server_mode)
|
|
{
|
|
log("Running in SERVER_MODE.");
|
|
create_socket();
|
|
if (listen(fd, server_backlog) == -1) error("Listen error!");
|
|
log("Listening @ (%s):(%d)", inet_ntoa(local_IP_address), local_port);
|
|
FD_SET(fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
} else if (reconnect) {
|
|
log("Running in RECONNECT MODE.");
|
|
forced_reconnect(reconnect_max_attempts+1);
|
|
} else {
|
|
log("Running in CLIENT MODE.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log("Running in NORMAL MODE.");
|
|
}
|
|
log("Leaving user_map().");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::user_unmap(const char *system_port)
|
|
{
|
|
log("Calling user_unmap(%s).",system_port);
|
|
Uninstall_Handler();
|
|
FD_ZERO(&readfds);
|
|
FD_ZERO(&writefds);
|
|
if(!simple_mode)
|
|
{
|
|
for(int i=0;i<list_len;i++) map_delete_item(i);
|
|
for(int i=0;i<list_len_server;i++) map_delete_item_server(i);
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<list_len;i++) map_delete_item(i);
|
|
if(server_mode) close(fd);
|
|
}
|
|
log("Leaving user_unmap().");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::user_start()
|
|
{
|
|
log("Calling user_start().");
|
|
log("Leaving user_start().");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::user_stop()
|
|
{
|
|
log("Calling user_stop().");
|
|
log("Leaving user_stop().");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::outgoing_send(const SCTPasp__Types::ASP__SCTP__Connect& send_par)
|
|
{
|
|
log("Calling outgoing_send (ASP_SCTP_CONNECT).");
|
|
if(simple_mode)
|
|
{
|
|
if (server_mode)
|
|
error("ASP_SCTP_CONNECT is not allowed in server mode!");
|
|
}
|
|
if( !peer_IP_address_is_present && !send_par.peer__hostname().ispresent() )
|
|
error("Peer IP address should be defined!");
|
|
|
|
if( !peer_port_is_present && !send_par.peer__portnumber().ispresent() )
|
|
error("Peer port should be defined!");
|
|
if(!simple_mode)
|
|
{
|
|
boolean temp_bool = local_port_is_present;
|
|
local_port_is_present = FALSE;
|
|
create_socket(); // creating client socket
|
|
local_port_is_present = temp_bool;
|
|
}
|
|
else
|
|
{
|
|
if (fd == -1) create_socket(); // checking if there is an open socket
|
|
else if(FD_ISSET(fd, &readfds)) // Active connection
|
|
error("ASP_SCTP_CONNECT called during active connection.");
|
|
}
|
|
struct sockaddr_in sin;
|
|
if(send_par.peer__hostname().ispresent())
|
|
{
|
|
peer_IP_address = get_in_addr((const char *)(const CHARSTRING&)send_par.peer__hostname());
|
|
}
|
|
if(send_par.peer__portnumber().ispresent())
|
|
peer_port = (int) (const INTEGER&) send_par.peer__portnumber();
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(peer_port);
|
|
sin.sin_addr.s_addr = peer_IP_address.s_addr;
|
|
log("Connecting to (%s):(%d)", inet_ntoa(peer_IP_address), peer_port);
|
|
// setting non-blocking mode
|
|
if(!simple_mode) setNonBlocking(fd);
|
|
if (connect(fd, (struct sockaddr *)&sin, sizeof (sin)) == -1)
|
|
{
|
|
if(errno == EINPROGRESS && !simple_mode)
|
|
{
|
|
map_put_item(fd);
|
|
int i = map_get_item(fd);
|
|
fd_map[i].einprogress = TRUE;
|
|
fd_map[i].sin.sin_family = AF_INET;
|
|
fd_map[i].sin.sin_port = htons(peer_port);;
|
|
fd_map[i].sin.sin_addr.s_addr= peer_IP_address.s_addr;
|
|
FD_SET(fd, &writefds);
|
|
Install_Handler(&readfds, &writefds, NULL, 0.0);
|
|
log("Connection in progress to (%s):(%d)", inet_ntoa(peer_IP_address),
|
|
peer_port);
|
|
}
|
|
else
|
|
{
|
|
close(fd);
|
|
fd = -1;
|
|
TTCN_warning("Connect error!");
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = OMIT_VALUE;
|
|
asp_sctp_result.error__status() = TRUE;
|
|
asp_sctp_result.error__message() = strerror(errno);
|
|
incoming_message(asp_sctp_result);
|
|
}
|
|
errno = 0;
|
|
}
|
|
else
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
map_put_item(fd);
|
|
if(simple_mode) setNonBlocking(fd);
|
|
FD_SET(fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
log("Connection successfully established to (%s):(%d)", inet_ntoa(peer_IP_address), peer_port);
|
|
}
|
|
log("Leaving outgoing_send (ASP_SCTP_CONNECT).");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::outgoing_send(const SCTPasp__Types::ASP__SCTP__ConnectFrom& send_par)
|
|
{
|
|
log("Calling outgoing_send (ASP_SCTP_CONNECTFROM).");
|
|
if(!simple_mode)
|
|
{
|
|
if( !peer_IP_address_is_present && !send_par.peer__hostname().ispresent() )
|
|
error("Peer IP address should be defined!");
|
|
if( !peer_port_is_present && !send_par.peer__portnumber().ispresent() )
|
|
error("Peer port should be defined!");
|
|
// work around for create_socket()
|
|
unsigned short temp = local_port; // saving global variables
|
|
boolean temp_bool = local_port_is_present;
|
|
struct in_addr temp_local_IP_address = local_IP_address;
|
|
local_port = (int) (const INTEGER&) send_par.local__portnumber();
|
|
local_port_is_present = TRUE;
|
|
if(send_par.local__hostname().ispresent())
|
|
{
|
|
local_IP_address = get_in_addr((const char *)(const CHARSTRING&)send_par.local__hostname());
|
|
}
|
|
create_socket(); // creating client socket
|
|
|
|
struct sockaddr_in sin;
|
|
if(send_par.peer__hostname().ispresent())
|
|
{
|
|
peer_IP_address = get_in_addr((const char *)(const CHARSTRING&)send_par.peer__hostname());
|
|
}
|
|
if(send_par.peer__portnumber().ispresent())
|
|
peer_port = (int) (const INTEGER&) send_par.peer__portnumber();
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(peer_port);
|
|
sin.sin_addr.s_addr = peer_IP_address.s_addr;
|
|
log("Connecting to (%s):(%d)", inet_ntoa(peer_IP_address), peer_port);
|
|
// setting non-blocking mode
|
|
setNonBlocking(fd);
|
|
if (connect(fd, (struct sockaddr *)&sin, sizeof (sin)) == -1)
|
|
{
|
|
if(errno == EINPROGRESS)
|
|
{
|
|
map_put_item(fd);
|
|
int i = map_get_item(fd);
|
|
fd_map[i].einprogress = TRUE;
|
|
fd_map[i].sin.sin_family = AF_INET;
|
|
fd_map[i].sin.sin_port = htons(peer_port);;
|
|
fd_map[i].sin.sin_addr.s_addr= peer_IP_address.s_addr;
|
|
FD_SET(fd, &writefds);
|
|
Install_Handler(&readfds, &writefds, NULL, 0.0);
|
|
log("Connection in progress to (%s):(%d)", inet_ntoa(peer_IP_address),
|
|
peer_port);
|
|
}
|
|
else
|
|
{
|
|
close(fd);
|
|
fd = -1;
|
|
TTCN_warning("Connect error!");
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = OMIT_VALUE;
|
|
asp_sctp_result.error__status() = TRUE;
|
|
asp_sctp_result.error__message() = strerror(errno);
|
|
incoming_message(asp_sctp_result);
|
|
}
|
|
errno = 0;
|
|
}
|
|
else
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
map_put_item(fd);
|
|
FD_SET(fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
log("Connection successfully established to (%s):(%d)", inet_ntoa(peer_IP_address), peer_port);
|
|
}
|
|
local_port = temp; // restoring global variables
|
|
local_port_is_present = temp_bool;
|
|
local_IP_address = temp_local_IP_address;
|
|
}
|
|
log("Leaving outgoing_send (ASP_SCTP_CONNECTFROM).");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::outgoing_send(const SCTPasp__Types::ASP__SCTP__Listen& send_par)
|
|
{
|
|
log("Calling outgoing_send (ASP_SCTP_LISTEN).");
|
|
if(!simple_mode)
|
|
{
|
|
// work around for create_socket()
|
|
unsigned short temp = local_port; // saving global variables
|
|
boolean temp_bool = local_port_is_present;
|
|
struct in_addr temp_local_IP_address = local_IP_address;
|
|
local_port = (int) (const INTEGER&) send_par.local__portnumber();
|
|
local_port_is_present = TRUE;
|
|
if(send_par.local__hostname().ispresent())
|
|
{
|
|
local_IP_address = get_in_addr((const char *)(const CHARSTRING&)send_par.local__hostname());
|
|
}
|
|
create_socket();
|
|
if (listen(fd, server_backlog) == -1) error("Listen error!");
|
|
map_put_item_server(fd, local_IP_address, local_port);
|
|
log("Listening @ (%s):(%d)", inet_ntoa(local_IP_address), local_port);
|
|
local_port = temp; // restoring global variables
|
|
local_port_is_present = temp_bool;
|
|
local_IP_address = temp_local_IP_address;
|
|
FD_SET(fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
#ifdef SCTP_REPORT_LISTEN_RESULT
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
#endif
|
|
}
|
|
log("Leaving outgoing_send (ASP_SCTP_LISTEN).");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::outgoing_send(const SCTPasp__Types::ASP__SCTP__SetSocketOptions& send_par)
|
|
{
|
|
log("Calling outgoing_send (ASP_SCTP_SETSOCKETOPTIONS).");
|
|
if(simple_mode)
|
|
{
|
|
if (fd == -1) create_socket(); // checking if there is an open socket
|
|
}
|
|
switch (send_par.get_selection())
|
|
{
|
|
case SCTPasp__Types::ASP__SCTP__SetSocketOptions::ALT_Sctp__init:
|
|
{
|
|
(void) memset(&initmsg, 0, sizeof(struct sctp_initmsg));
|
|
const SCTPasp__Types::SCTP__INIT& init = send_par.Sctp__init();
|
|
initmsg.sinit_num_ostreams = (int) init.sinit__num__ostreams();
|
|
initmsg.sinit_max_instreams = (int) init.sinit__max__instreams();
|
|
initmsg.sinit_max_attempts = (int) init.sinit__max__attempts();
|
|
initmsg.sinit_max_init_timeo = (int) init.sinit__max__init__timeo();
|
|
log("Setting SCTP socket options (initmsg).");
|
|
if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
|
|
sizeof(struct sctp_initmsg)) < 0)
|
|
{
|
|
TTCN_warning("Setsockopt error!");
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = TRUE;
|
|
asp_sctp_result.error__message() = strerror(errno);
|
|
incoming_message(asp_sctp_result);
|
|
errno = 0;
|
|
}
|
|
else
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
}
|
|
break;
|
|
}
|
|
case SCTPasp__Types::ASP__SCTP__SetSocketOptions::ALT_Sctp__events:
|
|
{
|
|
const SCTPasp__Types::SCTP__EVENTS& event = send_par.Sctp__events();
|
|
events.sctp_data_io_event = (boolean) event.sctp__data__io__event();
|
|
events.sctp_association_event = (boolean) event.sctp__association__event();
|
|
events.sctp_address_event = (boolean) event.sctp__address__event();
|
|
events.sctp_send_failure_event = (boolean) event.sctp__send__failure__event();
|
|
events.sctp_peer_error_event = (boolean) event.sctp__peer__error__event();
|
|
events.sctp_shutdown_event = (boolean) event.sctp__shutdown__event();
|
|
events.sctp_partial_delivery_event = (boolean) event.sctp__partial__delivery__event();
|
|
#if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9)
|
|
events.sctp_adaptation_layer_event = (boolean) event.sctp__adaption__layer__event();
|
|
#else
|
|
events.sctp_adaption_layer_event = (boolean) event.sctp__adaption__layer__event();
|
|
#endif
|
|
break;
|
|
}
|
|
case SCTPasp__Types::ASP__SCTP__SetSocketOptions::ALT_So__linger:
|
|
{
|
|
struct linger so_linger;
|
|
(void) memset(&so_linger, 0, sizeof (so_linger));
|
|
const SCTPasp__Types::SO__LINGER& so = send_par.So__linger();
|
|
so_linger.l_onoff = (int) so.l__onoff();
|
|
so_linger.l_linger = (int) so.l__linger();
|
|
// Setting a socket level option
|
|
log("Setting SCTP socket options (so_linger).");
|
|
if (setsockopt(fd, SOL_SOCKET, SCTP_EVENTS, &so_linger, sizeof (so_linger)) < 0)
|
|
{
|
|
TTCN_warning("Setsockopt error!");
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = TRUE;
|
|
asp_sctp_result.error__message() = strerror(errno);
|
|
incoming_message(asp_sctp_result);
|
|
errno = 0;
|
|
}
|
|
else
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
}
|
|
break;
|
|
}
|
|
case SCTPasp__Types::ASP__SCTP__SetSocketOptions::ALT_Sctp__rtoinfo:
|
|
{
|
|
struct sctp_rtoinfo sctp_rtoinfo;
|
|
(void) memset(&sctp_rtoinfo, 0, sizeof (sctp_rtoinfo));
|
|
const SCTPasp__Types::SCTP__RTOINFO& rto = send_par.Sctp__rtoinfo();
|
|
int local_fd = (int) rto.client__id();
|
|
sctp_rtoinfo.srto_initial = (int) rto.srto__initial();
|
|
sctp_rtoinfo.srto_max = (int) rto.srto__max();
|
|
sctp_rtoinfo.srto_min = (int) rto.srto__min();
|
|
// Setting a SCTP level socket option
|
|
log("Setting SCTP socket options (sctp_rtoinfo).");
|
|
if (setsockopt(local_fd, IPPROTO_SCTP, SCTP_RTOINFO, &sctp_rtoinfo,
|
|
sizeof (sctp_rtoinfo)) < 0)
|
|
{
|
|
TTCN_warning("Setsockopt error!");
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = local_fd;
|
|
asp_sctp_result.error__status() = TRUE;
|
|
asp_sctp_result.error__message() = strerror(errno);
|
|
incoming_message(asp_sctp_result);
|
|
errno = 0;
|
|
}
|
|
else
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__RESULT asp_sctp_result;
|
|
asp_sctp_result.client__id() = local_fd;
|
|
asp_sctp_result.error__status() = FALSE;
|
|
asp_sctp_result.error__message() = OMIT_VALUE;
|
|
incoming_message(asp_sctp_result);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
error("Setsocketoptions error: UNBOUND value!");
|
|
break;
|
|
}
|
|
log("Leaving outgoing_send (ASP_SCTP_SETSOCKETOPTIONS).");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::outgoing_send(const SCTPasp__Types::ASP__SCTP__Close& send_par)
|
|
{
|
|
log("Calling outgoing_send (ASP_SCTP_CLOSE).");
|
|
if(!simple_mode)
|
|
{
|
|
if(send_par.client__id().ispresent())
|
|
{
|
|
int local_fd = (int) (const INTEGER&) send_par.client__id();
|
|
log("NORMAL MODE: closing client/server socket (fd = %d).", local_fd);
|
|
map_delete_item_fd(local_fd);
|
|
map_delete_item_fd_server(local_fd);
|
|
FD_CLR(local_fd, &readfds);
|
|
Install_Handler(&readfds, &writefds, NULL, 0.0);
|
|
}
|
|
else
|
|
{ // if OMIT is given then all sockets will be closed
|
|
log("NORMAL MODE: closing all sockets.");
|
|
for(int i=0;i<list_len;i++) map_delete_item(i);
|
|
for(int i=0;i<list_len_server;i++) map_delete_item_server(i);
|
|
FD_ZERO(&readfds);
|
|
FD_ZERO(&writefds);
|
|
Install_Handler(&readfds, &writefds, NULL, 0.0); // ???
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (server_mode)
|
|
{ // closing the given connection
|
|
if(send_par.client__id().ispresent())
|
|
{
|
|
int local_fd = (int) (const INTEGER&) send_par.client__id();
|
|
log("SERVER MODE: closing client socket (fd = %d).", local_fd);
|
|
map_delete_item_fd(local_fd);
|
|
FD_CLR(local_fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
}
|
|
else
|
|
{ // if OMIT is given in server mode then all clients will be closed
|
|
log("SERVER MODE: closing all client sockets.");
|
|
for(int i=0;i<list_len;i++) map_delete_item(i);
|
|
FD_ZERO(&readfds);
|
|
FD_SET(fd, &readfds); // leaving only the listening socket in the fdset
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
}
|
|
}
|
|
else
|
|
{ // closing the connection to the server
|
|
if ( send_par.client__id().ispresent() )
|
|
error("In client mode the client_id field of ASP_SCTP_Close should be set to OMIT!");
|
|
log("CLIENT MODE: closing socket (fd = %d).", fd);
|
|
map_delete_item_fd(fd);
|
|
FD_CLR(fd, &readfds);
|
|
fd=-1;
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
}
|
|
}
|
|
log("Leaving outgoing_send (ASP_SCTP_CLOSE).");
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::outgoing_send(const SCTPasp__Types::ASP__SCTP& send_par)
|
|
{
|
|
log("Calling outgoing_send (ASP_SCTP).");
|
|
struct cmsghdr *cmsg;
|
|
struct sctp_sndrcvinfo *sri;
|
|
char cbuf[sizeof (*cmsg) + sizeof (*sri)];
|
|
struct msghdr msg;
|
|
struct iovec iov;
|
|
const unsigned char *buf;
|
|
|
|
buf = (const unsigned char *)send_par.data();
|
|
iov.iov_len = send_par.data().lengthof();
|
|
|
|
memset(&msg, 0, sizeof (msg));
|
|
iov.iov_base = (char *)buf;
|
|
msg.msg_iov = &iov;
|
|
msg.msg_iovlen = 1;
|
|
msg.msg_control = cbuf;
|
|
msg.msg_controllen = sizeof (*cmsg) + sizeof (*sri);
|
|
|
|
memset(cbuf, 0, sizeof (*cmsg) + sizeof (*sri));
|
|
cmsg = (struct cmsghdr *)cbuf;
|
|
sri = (struct sctp_sndrcvinfo *)(cmsg + 1);
|
|
|
|
cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sri);
|
|
cmsg->cmsg_level = IPPROTO_SCTP;
|
|
cmsg->cmsg_type = SCTP_SNDRCV;
|
|
|
|
sri->sinfo_stream = (int) send_par.sinfo__stream();
|
|
|
|
int target;
|
|
if(!simple_mode)
|
|
{
|
|
if (!send_par.client__id().ispresent())
|
|
error("In NORMAL mode the client_id field of ASP_SCTP should be set to a valid value and not to omit!");
|
|
target = (int) (const INTEGER&) send_par.client__id();
|
|
if ( (map_get_item(target)==-1) && (map_get_item_server(target)==-1)) error("Bad client id! %d",target);
|
|
}
|
|
else
|
|
{
|
|
if (server_mode)
|
|
{
|
|
if (!send_par.client__id().ispresent())
|
|
error("In server mode the client_id field of ASP_SCTP should be set to a valid value and not to omit!");
|
|
}
|
|
else // client mode
|
|
{
|
|
if (send_par.client__id().ispresent())
|
|
error("In client mode the client_id field of ASP_SCTP should be set to OMIT!");
|
|
}
|
|
target = fd;
|
|
if (server_mode)
|
|
target = (int) (const INTEGER&) send_par.client__id();
|
|
if (map_get_item(target)==-1) error("Bad client id! %d",target);
|
|
}
|
|
|
|
uint32_t ui;
|
|
if (send_par.sinfo__ppid().get_val().is_native() && send_par.sinfo__ppid() > 0)
|
|
ui = (int)send_par.sinfo__ppid();
|
|
else {
|
|
OCTETSTRING os = int2oct(send_par.sinfo__ppid(), 4);
|
|
unsigned char* p = (unsigned char*)&ui;
|
|
*(p++) = os[3].get_octet();
|
|
*(p++) = os[2].get_octet();
|
|
*(p++) = os[1].get_octet();
|
|
*(p++) = os[0].get_octet();
|
|
}
|
|
sri->sinfo_ppid = htonl(ui);
|
|
|
|
log("Sending SCTP message to file descriptor %d.", target);
|
|
if (sendmsg(target, &msg, 0) < 0)
|
|
{
|
|
SCTPasp__Types::ASP__SCTP__SENDMSG__ERROR asp_sctp_sendmsg_error;
|
|
if (server_mode) asp_sctp_sendmsg_error.client__id() = target;
|
|
else asp_sctp_sendmsg_error.client__id() = OMIT_VALUE;
|
|
asp_sctp_sendmsg_error.sinfo__stream() = send_par.sinfo__stream();
|
|
asp_sctp_sendmsg_error.sinfo__ppid() = send_par.sinfo__ppid();
|
|
asp_sctp_sendmsg_error.data() = send_par.data();
|
|
incoming_message(asp_sctp_sendmsg_error);
|
|
TTCN_warning("Sendmsg error! Strerror=%s", strerror(errno));
|
|
|
|
errno = 0;
|
|
}
|
|
log("Leaving outgoing_send (ASP_SCTP).");
|
|
}
|
|
|
|
|
|
SCTPasp__PT_PROVIDER::return_value_t SCTPasp__PT_PROVIDER::getmsg(int fd, struct msghdr *msg)
|
|
{
|
|
log("Calling getmsg().");
|
|
int index = map_get_item(fd);
|
|
if ( !fd_map[index].processing_message ) fd_map[index].nr = 0;
|
|
|
|
ssize_t value = recvmsg(fd, msg, 0);
|
|
if (value <= 0) // EOF or error
|
|
{
|
|
log("Leaving getmsg(): EOF or error.");
|
|
errno = 0;
|
|
return EOF_OR_ERROR;
|
|
}
|
|
fd_map[index].nr += value;
|
|
log("getmsg(): [%d] bytes received. Receiving buffer now has [%d] bytes.", value, fd_map[index].nr);
|
|
// Whole message is received, return it.
|
|
if (msg->msg_flags & MSG_EOR)
|
|
{
|
|
log("Leaving getmsg(): whole message is received.");
|
|
return WHOLE_MESSAGE_RECEIVED;
|
|
}
|
|
|
|
// Maybe we need a bigger buffer, do realloc().
|
|
if (fd_map[index].buflen == fd_map[index].nr)
|
|
{
|
|
log("getmsg(): resizing receiving buffer: [%d] bytes -> [%d] bytes",
|
|
fd_map[index].buflen, (fd_map[index].buflen * 2));
|
|
fd_map[index].buf = Realloc(fd_map[index].buf, fd_map[index].buflen * 2);
|
|
fd_map[index].buflen *= 2;
|
|
}
|
|
log("Leaving getmsg(): part of the message is received.");
|
|
return PARTIAL_RECEIVE;
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::handle_event(void *buf)
|
|
{
|
|
union sctp_notification *snp;
|
|
snp = (sctp_notification *)buf;
|
|
switch (snp->sn_header.sn_type)
|
|
{
|
|
case SCTP_ASSOC_CHANGE:
|
|
{
|
|
log("incoming SCTP_ASSOC_CHANGE event.");
|
|
struct sctp_assoc_change *sac;
|
|
sac = &snp->sn_assoc_change;
|
|
|
|
// #ifdef LKSCTP_1_0_7
|
|
SCTPasp__Types::SAC__STATE sac_state_ttcn;
|
|
switch(sac->sac_state)
|
|
{
|
|
case SCTP_COMM_UP:
|
|
sac_state_ttcn = SCTPasp__Types::SAC__STATE::SCTP__COMM__UP;
|
|
break;
|
|
|
|
case SCTP_COMM_LOST:
|
|
sac_state_ttcn = SCTPasp__Types::SAC__STATE::SCTP__COMM__LOST;
|
|
break;
|
|
|
|
case SCTP_RESTART:
|
|
sac_state_ttcn = SCTPasp__Types::SAC__STATE::SCTP__RESTART;
|
|
break;
|
|
|
|
case SCTP_SHUTDOWN_COMP:
|
|
sac_state_ttcn = SCTPasp__Types::SAC__STATE::SCTP__SHUTDOWN__COMP;
|
|
break;
|
|
|
|
case SCTP_CANT_STR_ASSOC:
|
|
sac_state_ttcn = SCTPasp__Types::SAC__STATE::SCTP__CANT__STR__ASSOC;
|
|
break;
|
|
|
|
default:
|
|
sac_state_ttcn = SCTPasp__Types::SAC__STATE::SCTP__UNKNOWN__SAC__STATE;
|
|
TTCN_warning("Unexpected sac_state value received %d", sac->sac_state);
|
|
break;
|
|
}
|
|
// #endif
|
|
|
|
if(sac->sac_state == SCTP_COMM_LOST)
|
|
{
|
|
if(simple_mode)
|
|
{
|
|
if (!server_mode) fd = -1; // setting closed socket to -1 in client mode (and reconnect mode)
|
|
FD_CLR(receiving_fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
map_delete_item_fd(receiving_fd);
|
|
}
|
|
else
|
|
{
|
|
FD_CLR(receiving_fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
map_delete_item_fd(receiving_fd);
|
|
map_delete_item_fd_server(receiving_fd);
|
|
}
|
|
}
|
|
if (events.sctp_association_event) incoming_message(SCTPasp__Types::ASP__SCTP__ASSOC__CHANGE(
|
|
INTEGER(receiving_fd),
|
|
sac_state_ttcn
|
|
));
|
|
|
|
if(simple_mode)
|
|
{
|
|
if (reconnect && (sac->sac_state == SCTP_COMM_LOST) ) forced_reconnect(reconnect_max_attempts);
|
|
}
|
|
break;
|
|
}
|
|
case SCTP_PEER_ADDR_CHANGE:{
|
|
log("incoming SCTP_PEER_ADDR_CHANGE event.");
|
|
struct sctp_paddr_change *spc;
|
|
spc = &snp->sn_paddr_change;
|
|
// #ifdef LKSCTP_1_0_7
|
|
SCTPasp__Types::SPC__STATE spc_state_ttcn;
|
|
switch(spc->spc_state)
|
|
{
|
|
case SCTP_ADDR_AVAILABLE:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__ADDR__AVAILABLE;
|
|
break;
|
|
|
|
case SCTP_ADDR_UNREACHABLE:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__ADDR__UNREACHABLE;
|
|
break;
|
|
|
|
case SCTP_ADDR_REMOVED:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__ADDR__REMOVED;
|
|
break;
|
|
|
|
case SCTP_ADDR_ADDED:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__ADDR__ADDED;
|
|
break;
|
|
|
|
case SCTP_ADDR_MADE_PRIM:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__ADDR__MADE__PRIM;
|
|
break;
|
|
#if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9)
|
|
case SCTP_ADDR_CONFIRMED:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__ADDR__CONFIRMED;
|
|
break;
|
|
#endif
|
|
default:
|
|
spc_state_ttcn = SCTPasp__Types::SPC__STATE::SCTP__UNKNOWN__SPC__STATE;
|
|
TTCN_warning("Unexpected spc_state value received %d", spc->spc_state);
|
|
break;
|
|
}
|
|
// #endif
|
|
if (events.sctp_address_event) incoming_message(SCTPasp__Types::ASP__SCTP__PEER__ADDR__CHANGE(
|
|
INTEGER(receiving_fd),
|
|
spc_state_ttcn
|
|
));
|
|
break;
|
|
}
|
|
case SCTP_REMOTE_ERROR:
|
|
log("incoming SCTP_REMOTE_ERROR event.");
|
|
//struct sctp_remote_error *sre;
|
|
//sre = &snp->sn_remote_error;
|
|
if (events.sctp_peer_error_event) incoming_message(SCTPasp__Types::ASP__SCTP__REMOTE__ERROR(INTEGER(receiving_fd)));
|
|
break;
|
|
case SCTP_SEND_FAILED:
|
|
log("incoming SCTP_SEND_FAILED event.");
|
|
//struct sctp_send_failed *ssf;
|
|
//ssf = &snp->sn_send_failed;
|
|
if (events.sctp_send_failure_event) incoming_message(SCTPasp__Types::ASP__SCTP__SEND__FAILED(INTEGER(receiving_fd)));
|
|
break;
|
|
case SCTP_SHUTDOWN_EVENT:
|
|
log("incoming SCTP_SHUTDOWN_EVENT event.");
|
|
//struct sctp_shutdown_event *sse;
|
|
//sse = &snp->sn_shutdown_event;
|
|
if (events.sctp_shutdown_event) incoming_message(SCTPasp__Types::ASP__SCTP__SHUTDOWN__EVENT(INTEGER(receiving_fd)));
|
|
break;
|
|
#if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9)
|
|
case SCTP_ADAPTATION_INDICATION:
|
|
log("incoming SCTP_ADAPTION_INDICATION event.");
|
|
//struct sctp_adaptation_event *sai;
|
|
//sai = &snp->sn_adaptation_event;
|
|
if (events.sctp_adaptation_layer_event) incoming_message(SCTPasp__Types::ASP__SCTP__ADAPTION__INDICATION(INTEGER(receiving_fd)));
|
|
break;
|
|
#else
|
|
case SCTP_ADAPTION_INDICATION:
|
|
log("incoming SCTP_ADAPTION_INDICATION event.");
|
|
//struct sctp_adaption_event *sai;
|
|
//sai = &snp->sn_adaption_event;
|
|
if (events.sctp_adaption_layer_event) incoming_message(SCTPasp__Types::ASP__SCTP__ADAPTION__INDICATION(INTEGER(receiving_fd)));
|
|
break;
|
|
#endif
|
|
case SCTP_PARTIAL_DELIVERY_EVENT:
|
|
log("incoming SCTP_PARTIAL_DELIVERY_EVENT event.");
|
|
//struct sctp_pdapi_event *pdapi;
|
|
//pdapi = &snp->sn_pdapi_event;
|
|
if (events.sctp_partial_delivery_event) incoming_message(SCTPasp__Types::ASP__SCTP__PARTIAL__DELIVERY__EVENT(INTEGER(receiving_fd)));
|
|
break;
|
|
default:
|
|
TTCN_warning("Unknown notification type!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::log(const char *fmt, ...)
|
|
{
|
|
if(debug)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
TTCN_Logger::begin_event(TTCN_DEBUG);
|
|
TTCN_Logger::log_event("SCTPasp Test Port (%s): ", get_name());
|
|
TTCN_Logger::log_event_va_list(fmt, ap);
|
|
TTCN_Logger::end_event();
|
|
va_end(ap);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::error(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
TTCN_Logger::begin_event(TTCN_ERROR);
|
|
TTCN_Logger::log_event("SCTPasp Test Port (%s): ", get_name());
|
|
TTCN_Logger::log_event_va_list(fmt, ap);
|
|
TTCN_Logger::end_event();
|
|
va_end(ap);
|
|
TTCN_error("Fatal error in SCTPasp Test Port %s (see above).", get_name());
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::forced_reconnect(int attempts)
|
|
{
|
|
struct sockaddr_in sin;
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(peer_port);
|
|
sin.sin_addr.s_addr = peer_IP_address.s_addr;
|
|
log("[reconnect] Connecting to (%s):(%d)", inet_ntoa(peer_IP_address), peer_port);
|
|
unsigned int sleep_interval = 1;
|
|
int i;
|
|
for(i = 0; i < attempts; i++)
|
|
{
|
|
create_socket();
|
|
if (connect(fd, (struct sockaddr *)&sin, sizeof (sin)) == -1)
|
|
{
|
|
close(fd);
|
|
fd = -1;
|
|
TTCN_warning("Connect error!");
|
|
errno = 0;
|
|
if( ((i % 2 ) == 0) && (i != 0)) sleep_interval *= 2;
|
|
sleep(sleep_interval);
|
|
|
|
}
|
|
else
|
|
{
|
|
map_put_item(fd);
|
|
setNonBlocking(fd);
|
|
FD_SET(fd, &readfds);
|
|
Install_Handler(&readfds, NULL, NULL, 0.0);
|
|
log("[reconnect] Connection successfully established to (%s):(%d)", inet_ntoa(peer_IP_address), peer_port);
|
|
break;
|
|
}
|
|
}
|
|
if (i == attempts) error("Forced reconnect failed! Remote end is unreachable!");
|
|
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::map_put_item(int fd)
|
|
{
|
|
int i=0;
|
|
while((i<list_len) && !fd_map[i].erased) i++; // searching for the free item
|
|
if(i==list_len)
|
|
{ // list is full add new elemnts
|
|
list_len+=MAP_LENGTH;
|
|
fd_map=(fd_map_item *)Realloc(fd_map,(list_len)*sizeof(fd_map_item));
|
|
for(int k=i;k<list_len;k++)
|
|
{ // init new elements
|
|
fd_map[k].fd=-1;
|
|
fd_map[k].erased=TRUE;
|
|
fd_map[k].einprogress=FALSE;
|
|
fd_map[k].buf=NULL;
|
|
fd_map[k].buflen=0;
|
|
fd_map[k].processing_message=FALSE;
|
|
fd_map[k].nr=0;
|
|
fd_map[k].sin.sin_family=AF_INET;
|
|
fd_map[k].sin.sin_port=0;
|
|
fd_map[k].sin.sin_addr.s_addr=0;
|
|
}
|
|
}
|
|
fd_map[i].fd=fd; // adding new connection
|
|
fd_map[i].erased=FALSE;
|
|
}
|
|
|
|
|
|
int SCTPasp__PT_PROVIDER::map_get_item(int fd)
|
|
{
|
|
for(int i = 0; i < list_len; i++)
|
|
if( !(fd_map[i].erased) && (fd_map[i].fd == fd) ) return i;
|
|
return(-1);
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::map_delete_item_fd(int fd)
|
|
{
|
|
if(fd!=-1)
|
|
for(int i = 0; i < list_len; i++)
|
|
if( fd_map[i].fd == fd )
|
|
{
|
|
map_delete_item(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::map_delete_item(int index)
|
|
{
|
|
if((index>=list_len) || (index<0)) error("map_delete_item: index out of range (0-%d): %d",list_len-1,index);
|
|
|
|
if(fd_map[index].fd!=-1) close(fd_map[index].fd);
|
|
fd_map[index].fd=-1;
|
|
fd_map[index].erased=TRUE;
|
|
fd_map[index].einprogress=FALSE;
|
|
if(fd_map[index].buf) Free(fd_map[index].buf);
|
|
fd_map[index].buf=NULL;
|
|
fd_map[index].buflen=0;
|
|
fd_map[index].processing_message=FALSE;
|
|
fd_map[index].nr=0;
|
|
fd_map[index].sin.sin_family=AF_INET;
|
|
fd_map[index].sin.sin_port=0;
|
|
fd_map[index].sin.sin_addr.s_addr=0;
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::map_put_item_server(int fd, struct in_addr local_IP_address, unsigned short local_port)
|
|
{
|
|
int i=0;
|
|
while((i<list_len_server) && !fd_map_server[i].erased) i++; // searching for the free item
|
|
if(i==list_len_server)
|
|
{ // list is full add new elemnts
|
|
list_len_server+=MAP_LENGTH;
|
|
fd_map_server=(fd_map_server_item *)Realloc(fd_map_server,(list_len_server)*sizeof(fd_map_server_item));
|
|
for(int k=i;k<list_len_server;k++)
|
|
{ // init new elements
|
|
fd_map_server[k].fd=-1;
|
|
fd_map_server[k].erased=TRUE;
|
|
fd_map_server[k].local_IP_address.s_addr = INADDR_ANY;
|
|
fd_map_server[k].local_port = 0;
|
|
}
|
|
}
|
|
fd_map_server[i].fd=fd; // adding new connection
|
|
fd_map_server[i].erased=FALSE;
|
|
fd_map_server[i].local_IP_address = local_IP_address;
|
|
fd_map_server[i].local_port = local_port;
|
|
|
|
}
|
|
|
|
|
|
int SCTPasp__PT_PROVIDER::map_get_item_server(int fd)
|
|
{
|
|
for(int i = 0; i < list_len_server; i++)
|
|
if( !(fd_map_server[i].erased) && (fd_map_server[i].fd == fd) ) return i;
|
|
return(-1);
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::map_delete_item_fd_server(int fd)
|
|
{
|
|
if(fd!=-1)
|
|
for(int i = 0; i < list_len_server; i++)
|
|
if( fd_map_server[i].fd == fd )
|
|
{
|
|
map_delete_item_server(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::map_delete_item_server(int index)
|
|
{
|
|
if((index>=list_len_server) || (index<0)) error("map_delete_item: index out of range (0-%d): %d",list_len_server-1,index);
|
|
|
|
if(fd_map_server[index].fd!=-1) close(fd_map_server[index].fd);
|
|
fd_map_server[index].fd=-1;
|
|
fd_map_server[index].erased=TRUE;
|
|
fd_map_server[index].local_IP_address.s_addr = INADDR_ANY;
|
|
fd_map_server[index].local_port = 0;
|
|
}
|
|
|
|
|
|
void SCTPasp__PT_PROVIDER::create_socket()
|
|
{
|
|
struct sockaddr_in sin;
|
|
|
|
log("Creating SCTP socket.");
|
|
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1)
|
|
error("Socket error: cannot create socket!");
|
|
|
|
if ( local_port_is_present ) {
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(local_port);
|
|
sin.sin_addr.s_addr = local_IP_address.s_addr;
|
|
log("Binding SCTP socket: bind address (%s):(%d)",
|
|
inet_ntoa(local_IP_address),local_port);
|
|
if (bind(fd, (struct sockaddr *)&sin, sizeof (sin)) == -1)
|
|
{
|
|
close(fd);
|
|
fd = -1;
|
|
error("Bind error!");
|
|
}
|
|
}
|
|
|
|
log("Setting SCTP socket options (initmsg).");
|
|
if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
|
|
sizeof(struct sctp_initmsg)) < 0)
|
|
{
|
|
TTCN_warning("Setsockopt error!");
|
|
errno = 0;
|
|
}
|
|
|
|
log("Setting SCTP socket options (events).");
|
|
if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof (events)) < 0)
|
|
{
|
|
TTCN_warning("Setsockopt error!");
|
|
errno = 0;
|
|
}
|
|
}
|
|
|
|
|
|
in_addr SCTPasp__PT_PROVIDER::get_in_addr(const char *hostname)
|
|
{
|
|
struct hostent *h;
|
|
if ((h=gethostbyname(hostname)) == NULL)
|
|
error("Gethostbyname error!");
|
|
if(h->h_addr == NULL) error("Gethostbyname error! h->h_addr is NULL!");
|
|
return *((struct in_addr *)h->h_addr);
|
|
}
|
|
|
|
void SCTPasp__PT_PROVIDER::setNonBlocking(int fd)
|
|
{
|
|
int flags = fcntl(fd, F_GETFL);
|
|
flags |= O_NONBLOCK;
|
|
int result = fcntl(fd, F_SETFL, flags);
|
|
if (result==-1) error("SCTPasp__PT::setNonBlocking(): Fcntl() error!");
|
|
}
|
|
|
|
|
|
}
|