Commit 99dedd6d authored by Elemer Lelik's avatar Elemer Lelik
Browse files

performance test code added

parent 1c66e366
#!/bin/bash
##############################################################################
# Copyright (c) 2000-2018 Ericsson Telecom 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:
##############################################################################
# This script is made for Jenkins test
LOG_FILE="test.xml"
STARTDIR=`pwd`
WORKING_DIR="build"
if [ ! -d "$WORKING_DIR" ]
then
mkdir -p ${WORKING_DIR}
cp src/* ${WORKING_DIR}
fi
if [ -d "$WORKING_DIR" ]
then
cd ${WORKING_DIR}
make clean
rm *.xml
make
XML_NAME="sip_basic_call_result.xml"
ttcn3_start EPTF_SIP_PerfTest EPTF_SIP_PerfTest.cfg
# filter out the useful info:
CPS_RESULT=`grep "final max CPS result" ${XML_NAME} | sed -e 's!.*<tq0001:result name=.final max CPS result. unit=.-.>\([0-9]*\).*</tq0001:result>.*!\1!g'`
echo "cps result:$CPS_RESULT<<"
echo "<report>" > ${LOG_FILE}
echo " <cps_result>${CPS_RESULT}</cps_result>" >> ${LOG_FILE}
echo "</report>" >> ${LOG_FILE}
cd ..
else
echo "The working directory is not exist, test cannot be run"
fi
/******************************************************************************
* Copyright (c) 2000-2018 Ericsson Telecom 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
******************************************************************************/
//
// File: Abstract_Socket.cc
// Description: Abstract_Socket implementation file
// Rev: <RnXnn>
// Prodnr: CNL 113 384
// Updated: 2012-08-07
// Contact: http://ttcn.ericsson.se
//
#include "Abstract_Socket.hh"
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <poll.h>
#if defined SOLARIS8
# include <signal.h>
#endif
#define AS_TCP_CHUNCK_SIZE 4096
#define AS_SSL_CHUNCK_SIZE 16384
// Used for the 'address already in use' bug workaround
#define AS_DEADLOCK_COUNTER 16
// character buffer length to store temporary SSL informations, 256 is usually enough
#define SSL_CHARBUF_LENGTH 256
// number of bytes to read from the random devices
#define SSL_PRNG_LENGTH 1024
#ifndef NI_MAXHOST
#define NI_MAXHOST 1024
#endif
#ifndef NI_MAXSERV
#define NI_MAXSERV 32
#endif
/********************************
** PacketHeaderDescr
** used for fragmentation and concatenation
** of fixed format messages
*********************************/
unsigned long PacketHeaderDescr::Get_Message_Length(const unsigned char* buff) const
{
unsigned long m_length = 0;
for (unsigned long i = 0; i < nr_bytes_in_length; i++) {
unsigned long shift_count =
byte_order == Header_MSB ? nr_bytes_in_length - 1 - i : i;
m_length |= buff[length_offset + i] << (8 * shift_count);
}
m_length *= length_multiplier;
if (value_offset < 0 && (long)m_length < -value_offset) return 0;
else return m_length + value_offset;
}
////////////////////////////////////////////////////////////////////////
///// Default log functions
////////////////////////////////////////////////////////////////////////
void Abstract_Socket::log_debug(const char *fmt, ...) const
{
if (socket_debugging) {
TTCN_Logger::begin_event(TTCN_DEBUG);
if (test_port_type != NULL && test_port_name != NULL)
TTCN_Logger::log_event("%s test port (%s): ", test_port_type,
test_port_name);
else TTCN_Logger::log_event_str("Abstract socket: ");
va_list args;
va_start(args, fmt);
TTCN_Logger::log_event_va_list(fmt, args);
va_end(args);
TTCN_Logger::end_event();
}
}
void Abstract_Socket::log_warning(const char *fmt, ...) const
{
TTCN_Logger::begin_event(TTCN_WARNING);
if (test_port_type != NULL && test_port_name != NULL)
TTCN_Logger::log_event("%s test port (%s): warning: ", test_port_type,
test_port_name);
else TTCN_Logger::log_event_str("Abstract socket: warning: ");
va_list args;
va_start(args, fmt);
TTCN_Logger::log_event_va_list(fmt, args);
va_end(args);
TTCN_Logger::end_event();
}
void Abstract_Socket::log_error(const char *fmt, ...) const
{
va_list args;
va_start(args, fmt);
char *error_str = mprintf_va_list(fmt, args);
va_end(args);
try {
if (test_port_type != NULL && test_port_name != NULL)
TTCN_error("%s test port (%s): %s", test_port_type, test_port_name,
error_str);
else TTCN_error("Abstract socket: %s", error_str);
} catch (...) {
Free(error_str);
throw;
}
Free(error_str);
}
void Abstract_Socket::log_hex(const char *prompt, const unsigned char *msg,
size_t length) const
{
if (socket_debugging) {
TTCN_Logger::begin_event(TTCN_DEBUG);
if (test_port_type != NULL && test_port_name != NULL)
TTCN_Logger::log_event("%s test port (%s): ", test_port_type,
test_port_name);
else TTCN_Logger::log_event_str("Abstract socket: ");
if (prompt != NULL) TTCN_Logger::log_event_str(prompt);
TTCN_Logger::log_event("Size: %lu, Msg:", (unsigned long)length);
for (size_t i = 0; i < length; i++) TTCN_Logger::log_event(" %02x", msg[i]);
TTCN_Logger::end_event();
}
}
/********************************
** Abstract_Socket
** abstract base type for TCP socket handling
*********************************/
Abstract_Socket::Abstract_Socket() {
server_mode=false;
socket_debugging=false;
nagling=false;
use_non_blocking_socket=false;
halt_on_connection_reset=true;
halt_on_connection_reset_set=false;
client_TCP_reconnect=false;
TCP_reconnect_attempts=5;
TCP_reconnect_delay=1;
listen_fd=-1;
memset(&remoteAddr, 0, sizeof(remoteAddr));
memset(&localAddr, 0, sizeof(localAddr));
server_backlog=1;
peer_list_length=0;
local_host_name = NULL;
local_port_number = 0;
remote_host_name = NULL;
remote_port_number = 0;
ai_family = AF_UNSPEC; // default: Auto
test_port_type=NULL;
test_port_name=NULL;
ttcn_buffer_usercontrol=false;
use_connection_ASPs=false;
handle_half_close = false;
}
Abstract_Socket::Abstract_Socket(const char *tp_type, const char *tp_name) {
server_mode=false;
socket_debugging=false;
nagling=false;
use_non_blocking_socket=false;
halt_on_connection_reset=true;
halt_on_connection_reset_set=false;
client_TCP_reconnect=false;
TCP_reconnect_attempts=5;
TCP_reconnect_delay=1;
listen_fd=-1;
memset(&remoteAddr, 0, sizeof(remoteAddr));
memset(&localAddr, 0, sizeof(localAddr));
server_backlog=1;
peer_list_length=0;
local_host_name = NULL;
local_port_number = 0;
remote_host_name = NULL;
remote_port_number = 0;
ai_family = AF_UNSPEC; // default: Auto
test_port_type=tp_type;
test_port_name=tp_name;
ttcn_buffer_usercontrol=false;
use_connection_ASPs=false;
handle_half_close = false;
}
Abstract_Socket::~Abstract_Socket() {
peer_list_reset_peer();
Free(local_host_name);
Free(remote_host_name);
}
bool Abstract_Socket::parameter_set(const char *parameter_name,
const char *parameter_value)
{
log_debug("entering Abstract_Socket::parameter_set(%s, %s)", parameter_name, parameter_value);
if (strcmp(parameter_name, socket_debugging_name()) == 0) {
if (strcasecmp(parameter_value,"yes")==0) socket_debugging = true;
else if (strcasecmp(parameter_value,"no")==0) socket_debugging = false;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, socket_debugging_name());
} else if (strcmp(parameter_name, server_mode_name()) == 0) {
if (strcasecmp(parameter_value,"yes")==0) server_mode = true;
else if (strcasecmp(parameter_value,"no")==0) server_mode = false;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, server_mode_name());
} else if (strcmp(parameter_name, use_connection_ASPs_name()) == 0) {
if (strcasecmp(parameter_value,"yes")==0) use_connection_ASPs = true;
else if (strcasecmp(parameter_value,"no")==0) use_connection_ASPs = false;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, use_connection_ASPs_name());
} else if (strcmp(parameter_name, halt_on_connection_reset_name()) == 0) {
halt_on_connection_reset_set=true;
if (strcasecmp(parameter_value,"yes")==0) halt_on_connection_reset = true;
else if (strcasecmp(parameter_value,"no")==0) halt_on_connection_reset = false;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, halt_on_connection_reset_name());
} else if (strcmp(parameter_name, client_TCP_reconnect_name()) == 0) {
if (strcasecmp(parameter_value,"yes")==0) client_TCP_reconnect = true;
else if (strcasecmp(parameter_value,"no")==0) client_TCP_reconnect = false;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, client_TCP_reconnect_name());
} else if (strcmp(parameter_name, TCP_reconnect_attempts_name()) == 0) {
if (sscanf(parameter_value, "%d", &TCP_reconnect_attempts)!=1) log_error("Invalid input as TCP_reconnect_attempts counter given: %s", parameter_value);
if (TCP_reconnect_attempts<=0) log_error("TCP_reconnect_attempts must be greater than 0, %d is given", TCP_reconnect_attempts);
} else if (strcmp(parameter_name, TCP_reconnect_delay_name()) == 0) {
if (sscanf(parameter_value, "%d", &TCP_reconnect_delay)!=1) log_error("Invalid input as TCP_reconnect_delay given: %s", parameter_value);
if (TCP_reconnect_delay<0) log_error("TCP_reconnect_delay must not be less than 0, %d is given", TCP_reconnect_delay);
} else if(strcmp(parameter_name, remote_address_name()) == 0){
Free(remote_host_name);
remote_host_name = mcopystr(parameter_value);
} else if(strcmp(parameter_name, local_address_name()) == 0){ // only for backward compatibility
Free(local_host_name);
local_host_name = mcopystr(parameter_value);
} else if(strcmp(parameter_name, remote_port_name()) == 0){
if (sscanf(parameter_value, "%d", &remote_port_number)!=1) log_error("Invalid input as port number given: %s", parameter_value);
if (remote_port_number>65535 || remote_port_number<0) log_error("Port number must be between 0 and 65535, %d is given", remote_port_number);
} else if(strcmp(parameter_name, ai_family_name()) == 0){
if (strcasecmp(parameter_value,"IPv6")==0 || strcasecmp(parameter_value,"AF_INET6")==0) ai_family = AF_INET6;
else if (strcasecmp(parameter_value,"IPv4")==0 || strcasecmp(parameter_value,"AF_INET")==0) ai_family = AF_INET;
else if (strcasecmp(parameter_value,"UNSPEC")==0 || strcasecmp(parameter_value,"AF_UNSPEC")==0) ai_family = AF_UNSPEC;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, ai_family_name());
} else if(strcmp(parameter_name, local_port_name()) == 0){
if (sscanf(parameter_value, "%d", &local_port_number)!=1) log_error("Invalid input as port number given: %s", parameter_value);
if (local_port_number>65535 || local_port_number<0) log_error("Port number must be between 0 and 65535, %d is given", local_port_number);
} else if (strcmp(parameter_name, nagling_name()) == 0) {
if (strcasecmp(parameter_value,"yes")==0) nagling = true;
else if (strcasecmp(parameter_value,"no")==0) nagling = false;
else log_error("Parameter value '%s' not recognized for parameter '%s'", parameter_value, nagling_name());
} else if (strcmp(parameter_name, use_non_blocking_socket_name()) == 0){
if (strcasecmp(parameter_value, "yes") == 0) use_non_blocking_socket = true;
else if (strcasecmp(parameter_value, "no") == 0) use_non_blocking_socket = false;
} else if (strcmp(parameter_name, server_backlog_name()) == 0) {
if (sscanf(parameter_value, "%d", &server_backlog)!=1) log_error("Invalid input as server backlog given: %s", parameter_value);
} else {
log_debug("leaving Abstract_Socket::parameter_set(%s, %s)", parameter_name, parameter_value);
return false;
}
log_debug("leaving Abstract_Socket::parameter_set(%s, %s)", parameter_name, parameter_value);
return true;
}
void Abstract_Socket::Handle_Socket_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error)
{
log_debug("entering Abstract_Socket::Handle_Socket_Event(): fd: %d%s%s%s", fd,
is_readable ? " readable" : "", is_writable ? " writable" : "", is_error ? " error" : "");
if (fd != listen_fd /* on server the connection requests are handled after the user messages */
&& peer_list_root[fd] != NULL && (is_readable || is_writable)
&& get_peer(fd)->reading_state != STATE_DONT_RECEIVE) {
log_debug("receiving data");
int messageLength = receive_message_on_fd(fd);
if (messageLength == 0) { // peer disconnected
as_client_struct * client_data = get_peer(fd);
log_debug("Abstract_Socket::Handle_Socket_Event(). Client %d closed connection.", fd);
switch (client_data->reading_state) {
case STATE_BLOCK_FOR_SENDING:
log_debug("Abstract_Socket::Handle_Socket_Event(): state is STATE_BLOCK_FOR_SENDING, don't close connection.");
Remove_Fd_Read_Handler(fd);
client_data->reading_state = STATE_DONT_CLOSE;
log_debug("Abstract_Socket::Handle_Socket_Event(): setting socket state to STATE_DONT_CLOSE");
break;
case STATE_DONT_CLOSE:
log_debug("Abstract_Socket::Handle_Socket_Event(): state is STATE_DONT_CLOSE, don't close connection.");
break;
default:
if((client_data->tcp_state == CLOSE_WAIT) || (client_data->tcp_state == FIN_WAIT)) {
remove_client(fd);
peer_disconnected(fd);
} else {
if(shutdown(fd, SHUT_RD) != 0) {
if(errno == ENOTCONN) {
remove_client(fd);
peer_disconnected(fd);
errno = 0;
} else
log_error("shutdown(SHUT_RD) system call failed");
} else {
client_data->tcp_state = CLOSE_WAIT;
Remove_Fd_Read_Handler(fd);
peer_half_closed(fd);
}
}
} // switch (client_data->reading_state)
} else if (messageLength > 0) {
as_client_struct *client_data=get_peer(fd);
if (socket_debugging) {
struct sockaddr_storage clientAddr = client_data->clientAddr;
#ifdef WIN32
log_debug("Message received from address %s:%d", inet_ntoa(((struct sockaddr_in*)&clientAddr)->sin_addr), ntohs(((struct sockaddr_in *)&clientAddr)->sin_port));
#else
char hname[NI_MAXHOST];
char sname[NI_MAXSERV];
#if defined LINUX || defined FREEBSD || defined SOLARIS8
socklen_t
#else /* SOLARIS or WIN32 */
int
#endif
clientAddrlen = client_data->clientAddrlen;
int error = getnameinfo((struct sockaddr *)&clientAddr, clientAddrlen,
hname, sizeof (hname), sname, sizeof (sname), NI_NUMERICHOST|NI_NUMERICSERV);
if (error) log_error("AbstractSocket: getnameinfo 2: %s\n", gai_strerror(error));
log_debug("Message received from address (addr) %s/%s", hname, sname);
#endif
}
log_hex("Message received, buffer content: ", get_buffer(fd)->get_data(), get_buffer(fd)->get_len());
handle_message(fd);
} /* else if (messageLength == -2) =>
used in case of SSL: means that reading would bloc.
in this case I stop receiving message on the file descriptor */
} // if ... (not new connection request)
if (fd == listen_fd && is_readable) {
// new connection request arrived
log_debug("waiting for accept");
// receiving new connection on the TCP server
struct sockaddr_storage clientAddr;
#if defined LINUX || defined FREEBSD || defined SOLARIS8
socklen_t
#else /* SOLARIS or WIN32 */
int
#endif
clientAddrlen = sizeof(clientAddr);
#if defined LINUX || defined FREEBSD || defined SOLARIS8
int newclient_fd = accept(listen_fd, (struct sockaddr *) &clientAddr, (socklen_t*)&clientAddrlen);
#else
int newclient_fd = accept(listen_fd, (struct sockaddr *) &clientAddr, (int*)&clientAddrlen);
#endif
if(newclient_fd < 0) log_error("Cannot accept connection at port");
as_client_struct *client_data=peer_list_add_peer(newclient_fd);
Add_Fd_Read_Handler(newclient_fd); // Done here - as in case of error: remove_client expects the handler as added
log_debug("Abstract_Socket::Handle_Socket_Event(). Handler set to other fd %d", newclient_fd);
client_data->fd_buff = new TTCN_Buffer;
client_data->clientAddr = clientAddr;
client_data->clientAddrlen = clientAddrlen;
client_data->tcp_state = ESTABLISHED;
client_data->reading_state = STATE_NORMAL;
if (add_user_data(newclient_fd)) {
char hname[NI_MAXHOST];
int clientPort = 0;
#ifdef WIN32
clientPort=ntohs(((struct sockaddr_in *)&clientAddr)->sin_port);
char* tmp=inet_ntoa(((struct sockaddr_in*)&clientAddr)->sin_addr);
strcpy(hname,tmp);
#else
int error;
char sname[NI_MAXSERV];
error = getnameinfo((struct sockaddr *)&clientAddr, clientAddrlen,
hname, sizeof (hname), sname, sizeof (sname), NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
log_error("AbstractSocket: getnameinfo: %s\n",
gai_strerror(error));
}
clientPort = atoi(sname);
#endif
log_debug("Client %d connected from address %s/%d", newclient_fd, hname, clientPort);
peer_connected(newclient_fd, hname, clientPort);
peer_connected(newclient_fd, *((struct sockaddr_in *)&clientAddr)); /* calling deprecated function also */
log_debug("Handle_Socket_Event updated with client %d ", newclient_fd);
if (set_non_block_mode(newclient_fd, use_non_blocking_socket) < 0) {
log_error("Set blocking mode failed.");
}
} else {
remove_client(newclient_fd);
peer_disconnected(newclient_fd);
}
} // if (fd == listen_fd && is_readable)
log_debug("leaving Abstract_Socket::Handle_Socket_Event()");
}
int Abstract_Socket::receive_message_on_fd(int client_id)
{
as_client_struct * client_data = get_peer(client_id);
TTCN_Buffer* recv_tb = client_data->fd_buff;
unsigned char *end_ptr;
size_t end_len=AS_TCP_CHUNCK_SIZE;
recv_tb->get_end(end_ptr, end_len);
int messageLength = recv(client_id, (char *)end_ptr, end_len, 0);
if (messageLength==0) return messageLength; // peer disconnected
else if (messageLength < 0) {
log_warning("Error when reading the received TCP PDU: %s", strerror(errno));
errno = 0;
return 0;
}
recv_tb->increase_length(messageLength);
return messageLength;
}
int Abstract_Socket::send_message_on_fd(int client_id, const unsigned char* send_par, int message_length)
{
get_peer(client_id);
return send(client_id, (const char *)send_par, message_length, 0);
}
//Tthe EAGAIN errno value set by the send operation means that
//the sending operation would block.
//First I try to increase the length of the sending buffer (increase_send_buffer()).
//If the outgoing buffer cannot be increased, the block_for_sending function will
//be called. This function will block until the file descriptor given as its argument
//is ready to write. While the block for sending operation calls the Event_Handler,
//states must be used to indicate that the Event_Handler is called when the
//execution is blocking.
//STATE_BLOCK_FOR_SENDING: the block for sending operation has been called
//STATE_DONT_CLOSE: if the other side close the connection before the block_for_sending
// operation returns, in the Event_Handler the connection
// must not be closed and the block_for_sending must return before we can
// close the connection. This state means that the other side closed the connection
// during the block_for_sending operation
//STATE_NORMAL: normal state
int Abstract_Socket::send_message_on_nonblocking_fd(int client_id,
const unsigned char* send_par,
int length){
log_debug("entering Abstract_Socket::"
"send_message_on_nonblocking_fd(id: %d)", client_id);
as_client_struct * client_data;
int sent_len = 0;
while(sent_len < length){
int ret;
log_debug("Abstract_Socket::send_message_on_nonblocking_fd(id: %d): new iteration", client_id);
client_data = get_peer(client_id);
if (client_data->reading_state == STATE_DONT_CLOSE){
goto client_closed_connection;
} else ret = send(client_id, send_par + sent_len, length - sent_len, 0);
if (ret > 0) sent_len+=ret;
else{
switch(errno){
case EINTR:{ //signal: do nothing, try again
errno = 0;
break;
}
case EPIPE:{ //client closed connection
goto client_closed_connection;
}
case EAGAIN:{ // the output buffer is full:
//try to increase it if possible
errno = 0;
int old_bufsize, new_bufsize;
if (increase_send_buffer(
client_id, old_bufsize, new_bufsize)) {
log_warning("Sending data on on file descriptor %d",
client_id);
log_warning("The sending operation would"
"block execution. The size of the "
"outgoing buffer was increased from %d to "
"%d bytes.",old_bufsize,
new_bufsize);
} else {
log_warning("Sending data on file descriptor %d",
client_id);
log_warning("The sending operation would block "
"execution and it is not possible to "
"further increase the size of the "
"outgoing buffer. Trying to process incoming"
"data to avoid deadlock.");
log_debug("Abstract_Socket::"
"send_message_on_nonblocking_fd():"
" setting socket state to "
"STATE_BLOCK_FOR_SENDING");
client_data->reading_state = STATE_BLOCK_FOR_SENDING;
TTCN_Snapshot::block_for_sending(client_id);
}
break;
}
default:{
log_debug("Abstract_Socket::"
"send_message_on_nonblocking_fd(): "
"setting socket state to STATE_NORMAL");
client_data->reading_state = STATE_NORMAL;
log_debug("leaving Abstract_Socket::"
"send_message_on_nonblocking_fd(id: %d)"
" with error", client_id);
return -1;
}
} //end of switch
}//end of else
} //end of while
log_debug("Abstract_Socket::send_message_on_nonblocking_fd():"
"setting socket state to STATE_NORMAL");
client_data->reading_state = STATE_NORMAL;
log_debug("leaving Abstract_Socket::"
"send_message_on_nonblocking_fd(id: %d)", client_id);
return sent_len;
client_closed_connection:
log_debug("Abstract_Socket::send_message_on_nonblocking_fd(): setting socket state to STATE_NORMAL");
client_data->reading_state = STATE_NORMAL;
log_debug("leaving Abstract_Socket::"
"send_message_on_nonblocking_fd(id: %d)", client_id);
errno = EPIPE;
return -1;
}
const PacketHeaderDescr* Abstract_Socket::Get_Header_Descriptor() const
{
return NULL;
}
void Abstract_Socket::peer_connected(int client_id, sockaddr_in& remote_addr)
{