2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
* Author : Richard GAYRAUD - 04 Nov 2003
18
* From Hewlett Packard Company.
30
#define KEYWORD_SIZE 64
34
/************** Call map and management routines **************/
36
call_map * get_calls()
41
static unsigned int next_number = 1;
43
call * add_call(char * call_id, bool ipv6)
47
new_call = new call(call_id, ipv6);
50
ERROR("Memory Overflow");
53
calls[std::string(call_id)] = new_call;
55
if(!next_number) { next_number ++; }
56
new_call -> number = next_number;
58
/* Vital counters update */
62
/* Statistics update */
63
calls_since_last_rate_change++;
66
if(open_calls > open_calls_peak) {
67
open_calls_peak = open_calls;
68
open_calls_peak_time = clock_tick / 1000;
73
call * add_call(bool ipv6)
75
static char call_id[MAX_HEADER_LEN];
79
if(!next_number) { next_number ++; }
83
next_number, pid, local_ip);
85
return add_call(call_id, ipv6);
88
call * get_call(char * call_id)
92
call_ptr = calls[std::string(call_id)];
95
calls.erase(std::string(call_id));
101
void delete_call(char * call_id)
103
call * call_ptr = calls[std::string(call_id)];
105
if(!calls.erase(std::string(call_id))) {
106
ERROR("Call not erased from map");
113
ERROR("Call not found");
117
/******* Very simple hash for retransmission detection *******/
119
unsigned long hash(char * msg) {
120
unsigned long rv = 0;
121
int len = strlen(msg);
125
rv = msg[0] + msg[1] + msg[2] + msg[3];
129
rv += msg[9] + msg[10] + msg[11] + msg[12];
136
for (index = 0; index < len; index ++) {
137
rv += + msg[index] * index;
143
/******************* Call class implementation ****************/
145
call::InputFileUsage call::m_usage = call::InputFileSequentialOrder;
146
int call::m_counter = 0;
148
call::call(char * p_id, bool ipv6) : use_ipv6(ipv6)
150
memset(this, 0, sizeof(call));
152
start_time = clock_tick;
153
call_established=false ;
154
count_in_stats=true ;
155
ack_is_pending=false ;
156
last_recv_msg = NULL;
158
call_remote_socket = 0;
160
// initialising the CallVariable with the Scenario variable
161
for(int i=0; i<SCEN_VARIABLE_SIZE; i++)
163
if(scenVariableTable[i] != NULL) {
164
M_callVariableTable[i] = new CCallVariable();
165
if (M_callVariableTable[i] == NULL) {
166
ERROR ("call variable allocation failed");
169
M_callVariableTable[i] = NULL;
173
// If not updated by a message we use the start time
174
// information to compute rtd information
175
start_time_rtd = clock_tick;
177
// by default, last action result is NO_ERROR
178
last_action_result = call::E_AR_NO_ERROR;
180
if (InputFileRandomOrder == m_usage) {
181
m_localLineNumber = rand() % numLinesInFile;
183
m_localLineNumber = m_counter++;
184
if (m_counter >= numLinesInFile) {
197
if(comp_state) { comp_free(&comp_state); }
200
CStat::instance()->computeStat(CStat::E_ADD_CALL_DURATION,
201
clock_tick - start_time);
204
call_duration_sum += clock_tick - start_time;
208
pollset_remove(pollset_index);
209
shutdown(call_socket, SHUT_RDWR);
213
/* Deletion of the call variable */
214
for(int i=0; i<SCEN_VARIABLE_SIZE; i++) {
215
if(M_callVariableTable[i] != NULL) {
216
delete M_callVariableTable[i] ;
217
M_callVariableTable[i] = NULL;
222
if(last_recv_msg) { free(last_recv_msg); }
223
if(last_send_msg) { free(last_send_msg); }
225
if(dialog_route_set) {
226
free(dialog_route_set);
230
if(dialog_authentication) {
231
free(dialog_authentication);
234
call_established= false ;
237
void call::connect_socket_if_needed()
240
if(call_socket) return;
241
if(!multisocket) return;
243
if(transport == T_UDP) {
244
struct sockaddr_storage saddr;
247
if(toolMode != MODE_CLIENT) return;
249
if((call_socket = socket(use_ipv6 ? AF_INET6 : AF_INET,
252
ERROR_NO("Unable to get an UDP socket");
255
memset(&saddr, 0, sizeof(struct sockaddr_storage));
257
saddr.ss_family = AF_INET;
260
(sockaddr *)(void *)&saddr,
261
use_ipv6 ? sizeof(struct sockaddr_in6) :
262
sizeof(struct sockaddr_in))) {
263
ERROR_NO("Unable to bind UDP socket");
267
len = sizeof(struct sockaddr_in6);
269
len = sizeof(struct sockaddr_in);
272
getsockname(call_socket,
273
(sockaddr *)(void *)&saddr,
278
ntohs((short)((_RCAST(struct sockaddr_in6 *, &saddr))->sin6_port));
281
= ntohs((short)((_RCAST(struct sockaddr_in *, &saddr))->sin_port));
286
if((call_socket= socket(use_ipv6 ? AF_INET6 : AF_INET,
289
ERROR_NO("Unable to get a TCP socket");
292
sipp_customize_socket(call_socket);
295
struct sockaddr_storage *L_dest = &remote_sockaddr;
297
if (use_remote_sending_addr) {
298
L_dest = &remote_sending_sockaddr ;
301
// (struct sockaddr *)(void *)&remote_sockaddr,
302
// (struct sockaddr *)(void *)L_dest,
303
// use_ipv6 ? sizeof(struct sockaddr_in6) :
304
// sizeof(struct sockaddr_in))) {
306
if(connect(call_socket,
307
(struct sockaddr *)(void *)&remote_sockaddr,
308
SOCK_ADDR_SIZE(&remote_sockaddr))) {
311
/* This occurs sometime on HPUX but is not a true INVAL */
312
ERROR("Unable to connect a TCP socket, remote peer error");
314
ERROR_NO("Unable to connect a TCP socket");
319
/* Asks to receive incoming messages */
320
pollset_index = pollset_add(this, call_socket);
323
bool lost(int percent)
325
static int inited = 0;
327
if(!lose_packets) return false;
328
if(!percent) return false;
331
srand((unsigned int) time(NULL));
335
if((rand() % 100) < percent) {
342
int call::send_raw(char * msg, int index)
349
extern SSL *ssl_list[];
351
struct timeval currentTime;
352
GET_TIME (¤tTime);
353
TRACE_MSG((s, "----------------------------------------------- %s\n"
354
"%s message sent:\n\n%s\n",
355
CStat::instance()->formatTime(¤tTime),
356
TRANSPORT_TO_STRING(transport),
359
if(lost(scenario[index] -> lost)) {
360
TRACE_MSG((s, "%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport)));
362
if(comp_state) { comp_free(&comp_state); }
363
scenario[index] -> nb_lost++;
371
if (use_remote_sending_addr) {
372
if (!call_remote_socket) {
373
struct sockaddr_storage *L_dest = &remote_sending_sockaddr;
374
if((call_remote_socket= socket(use_ipv6 ? AF_INET6 : AF_INET,
377
ERROR_NO("Unable to get a TCP socket");
380
sipp_customize_socket(call_remote_socket);
382
if(connect(call_remote_socket,
383
(struct sockaddr *)(void *)L_dest,
384
SOCK_ADDR_SIZE(&remote_sockaddr))) {
386
/* This occurs sometime on HPUX but is not a true INVAL */
387
ERROR("Unable to connect a TCP socket, remote peer error");
389
ERROR_NO("Unable to connect a TCP socket");
393
sock=call_remote_socket ;
397
ssl = ssl_list[sock];
400
state = &monosocket_comp_state;
401
if(transport == T_UDP) {
404
sock = tcp_multiplex;
406
ssl = ssl_tcp_multiplex;
412
if ( transport == T_TLS ) {
413
rc = send_message_tls(ssl, state, msg);
416
rc = send_message(sock, state, msg);
421
if(rc == -1) return -1;
424
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
425
CStat::instance()->computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
432
int call::sendBuffer(char * msg)
438
TRACE_MSG((s, "-----------------------------------------------\n"
439
"%s message send:\n\n%s\n",
440
TRANSPORT_TO_STRING(transport),
447
state = &monosocket_comp_state;
448
if(transport == T_UDP) {
451
sock = tcp_multiplex;
455
rc = send_message(sock, state, msg);
457
if(rc == -1) return -1;
460
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
461
CStat::instance()->computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
469
char * call::compute_cseq(char * src)
472
static char cseq[MAX_HEADER_LEN * 10];
474
if(dest = strstr(src, "CSeq")) {
475
/* If we find a CSeq in incoming msg */
476
char * last_header = get_last_header(dest+4);
479
/* Extract the integer value of the last CSeq */
480
last_header = strstr(last_header, ":");
482
while(isspace(*last_header)) last_header++;
483
sscanf(last_header,"%d", &i);
484
/* Add 1 to the last CSeq value */
485
sprintf(cseq, "%s%d", "CSeq: ", (i+1));
487
sprintf(cseq, "%s", "CSeq: 2");
495
char * call::get_last_header(char * name)
497
static char last_header[MAX_HEADER_LEN * 10];
498
char * src, *dest, *ptr;
499
char src_tmp[1024] = "\n";
501
if((!last_recv_msg) || (!strlen(last_recv_msg))) {
508
strcpy(src_tmp+1,name);
509
while(src = strcasestr2(src, src_tmp)) {
511
ptr = strchr(src, '\n');
513
/* Multiline headers always begin with a tab or a space
514
* on the subsequent lines */
516
((*(ptr+1) == ' ' ) ||
517
(*(ptr+1) == '\t') )) {
518
ptr = strchr(ptr + 1, '\n');
521
if(ptr) { *ptr = 0; }
522
// Add \r\n when several Via header are present (AgM)
523
if (dest != last_header) {
524
dest += sprintf(dest, "\r\n");
526
dest += sprintf(dest, "%s", src);
527
if(ptr) { *ptr = '\n'; }
532
if(dest == last_header) {
538
/* Remove trailing whitespaces, tabs, and CRs */
539
while ((dest > last_header) &&
540
((*dest == ' ') || (*dest == '\r')|| (*dest == '\t'))) {
544
/* remove enclosed CRs in multilines */
545
/* don't remove enclosed CRs for multiple headers (e.g. Via) (Rhys) */
546
while((ptr = strstr(last_header, "\r\n")) != NULL
547
&& ( *(ptr + 2) == ' '
548
|| *(ptr + 2) == '\r'
549
|| *(ptr + 2) == '\t') ) {
550
/* Use strlen(ptr) to include trailing zero */
551
memmove(ptr, ptr+1, strlen(ptr));
553
/* Remove illegal double CR characters */
554
while((ptr = strstr(last_header, "\r\r")) != NULL) {
555
memmove(ptr, ptr+1, strlen(ptr));
557
/* Remove illegal double Newline characters */
558
while((ptr = strstr(last_header, "\n\n")) != NULL) {
559
memmove(ptr, ptr+1, strlen(ptr));
565
char * call::get_header_content(char* message, char * name)
567
/* non reentrant. consider accepting char buffer as param */
568
static char last_header[MAX_HEADER_LEN * 10];
569
char * src, *dest, *ptr;
571
/* returns empty string in case of error */
572
memset(last_header, 0, sizeof(last_header));
574
if((!message) || (!strlen(message))) {
581
/* for safety's sake */
582
if (NULL == name || NULL == strrchr(name, ':')) {
586
while(src = strstr(src, name)) {
588
/* just want the header's content */
591
ptr = strchr(src, '\n');
593
/* Multiline headers always begin with a tab or a space
594
* on the subsequent lines */
596
((*(ptr+1) == ' ' ) ||
597
(*(ptr+1) == '\t') )) {
598
ptr = strchr(ptr + 1, '\n');
601
if(ptr) { *ptr = 0; }
602
// Add "," when several headers are present
603
if (dest != last_header) {
604
dest += sprintf(dest, ",");
606
dest += sprintf(dest, "%s", src);
607
if(ptr) { *ptr = '\n'; }
612
if(dest == last_header) {
618
/* Remove trailing whitespaces, tabs, and CRs */
619
while ((dest > last_header) &&
620
((*dest == ' ') || (*dest == '\r')|| (*dest == '\t'))) {
624
/* remove enclosed CRs in multilines */
625
while(ptr = strchr(last_header, '\r')) {
626
/* Use strlen(ptr) to include trailing zero */
627
memmove(ptr, ptr+1, strlen(ptr));
633
char * call::send_scene(int index, int *send_status)
635
static char msg_buffer[SIPP_MAX_MSG_SIZE];
637
#define MAX_MSG_NAME_SIZE 30
638
static char msg_name[MAX_MSG_NAME_SIZE];
642
/* Socket port must be known before string substitution */
643
connect_socket_if_needed();
645
if(scenario[index] -> send_scheme) {
647
dest = createSendingMessage(scenario[index] -> send_scheme, index);
648
strcpy(msg_buffer, dest);
653
while ((*L_ptr2 != ' ') && (*L_ptr2 != '\n') && (*L_ptr2 != '\t')) {
661
if (strcmp(msg_name,"ACK") == 0) {
662
call_established = true ;
663
ack_is_pending = false ;
668
send_raw(msg_buffer, index);
670
send_raw(msg_buffer, index);
673
ERROR("Unsupported 'send' message in scenario");
681
int test = scenario[msg_index]->test;
682
/* What is the next message index? */
683
if ( scenario[msg_index]->next &&
685
(test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
687
/* For branching, use the 'next' attribute value */
688
msg_index = labelArray[scenario[msg_index]->next];
690
/* Without branching, use the next message */
693
if(msg_index >= scenario_len) {
694
// Call end -> was it successful?
695
if(call::last_action_result != call::E_AR_NO_ERROR) {
696
switch(call::last_action_result) {
697
case call::E_AR_REGEXP_DOESNT_MATCH:
698
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
699
CStat::instance()->computeStat(CStat::E_FAILED_REGEXP_DOESNT_MATCH);
701
case call::E_AR_HDR_NOT_FOUND:
702
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
703
CStat::instance()->computeStat(CStat::E_FAILED_REGEXP_HDR_NOT_FOUND);
707
CStat::instance()->computeStat(CStat::E_CALL_SUCCESSFULLY_ENDED);
718
if(msg_index >= scenario_len) {
719
ERROR_P3("Scenario overrun for call %s (%08x) (index = %d)\n",
720
id, this, msg_index);
723
/* Manages retransmissions or delete if max retrans reached */
724
if(next_retrans && (next_retrans < clock_tick)) {
727
if(nb_retrans > UDP_MAX_RETRANS) {
728
scenario[last_send_index] -> nb_timeout ++;
729
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
730
CStat::instance()->computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
731
if (default_behavior) {
732
// Abort the call by sending proper SIP message
733
WARNING_P1("Aborting call on UDP retransmission timeout for Call-ID '%s'", id);
736
// Just delete existing call
741
unsigned int delay = scenario[last_send_index] -> retrans_delay;
742
unsigned int pow = nb_retrans;
746
if(send_raw(last_send_msg, last_send_index) < -1) {
749
scenario[last_send_index] -> nb_sent_retrans++;
750
next_retrans = clock_tick + delay;
755
/* Process a pending pause instruction until delay expiration */
756
if(paused_until > clock_tick) {
762
} else if(scenario[msg_index] -> pause) {
763
/* Starts a pause instruction */
764
if((scenario[msg_index] -> pause) &&
765
((scenario[msg_index] -> pause) == -1)) {
766
paused_until = clock_tick + duration;
768
paused_until = clock_tick + scenario[msg_index] -> pause;
770
return run(); /* In case delay is 0 */
774
else if(scenario[msg_index] -> M_type == MSG_TYPE_SENDCMD) {
781
send_status = sendCmdMessage(msg_index);
783
if(send_status != 0) { /* Send error */
784
return false; /* call deleted */
786
scenario[msg_index] -> M_nbCmdSent++;
791
else if(scenario[msg_index] -> send_scheme) {
796
/* Do not send a new message until the previous one which had
797
* retransmission enabled is acknowledged */
803
/* If this message can be used to compute RTD, do it now */
805
if(scenario[msg_index] -> start_rtd) {
806
start_time_rtd = clock_tick;
809
if(scenario[msg_index] -> stop_rtd) {
810
rtd_sum += clock_tick - start_time_rtd;
811
CStat::instance()->computeStat(CStat::E_ADD_RESPONSE_TIME_DURATION,
812
clock_tick - start_time_rtd);
818
msg_snd = send_scene(msg_index, &send_status);
820
if(send_status == -1) { /* Would Block on TCP */
821
return true; /* No step, nothing done, retry later */
824
if(send_status <-1) { /* Send error */
825
return false; /* call deleted */
828
last_send_index = msg_index;
829
last_send_msg = (char *) realloc(last_send_msg, strlen(msg_snd) + 1);
830
strcpy(last_send_msg, msg_snd);
833
/* We are sending just after msg reception. There is a great
834
* chance that we will be asked to retransmit this message */
835
recv_retrans_hash = last_recv_hash;
836
recv_retrans_recv_index = last_recv_index;
837
recv_retrans_send_index = msg_index;
839
/* Prevent from detecting the cause relation between send and recv
840
* in the next valid send */
844
/* Update retransmission information */
845
if(scenario[msg_index] -> retrans_delay) {
846
if((transport == T_UDP) && (retrans_enabled)) {
847
next_retrans = clock_tick + scenario[msg_index] -> retrans_delay;
854
/* Update scenario statistics */
855
scenario[msg_index] -> nb_sent++;
862
bool call::process_unexpected(char * msg)
865
static int first = 1;
868
scenario[msg_index] -> nb_unexp++;
870
if (scenario[msg_index] -> recv_request) {
871
if (default_behavior) {
872
WARNING_P3("Aborting call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
873
id, scenario[msg_index] -> recv_request, msg);
875
WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
876
id, scenario[msg_index] -> recv_request, msg);
879
if (default_behavior) {
880
WARNING_P3("Aborting call on unexpected message for Call-ID '%s': while expecting '%d' response, received '%s' ",
881
id, scenario[msg_index] -> recv_response, msg);
883
WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%d' response, received '%s' ",
884
id, scenario[msg_index] -> recv_response, msg);
888
TRACE_MSG((s, "-----------------------------------------------\n"
889
"Unexpected %s message received:\n\n%s\n",
890
TRANSPORT_TO_STRING(transport),
893
if (default_behavior) {
895
// if twin socket call => reset the other part here
896
if (twinSippSocket && (msg_index > 0)) {
897
//WARNING_P2("call-ID '%s', internal-cmd: abort_call %s",id, "");
899
(createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
901
#endif /* __3PCC__ */
903
// usage of last_ keywords => for call aborting
904
last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
905
strcpy(last_recv_msg, msg);
907
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
908
CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
909
return (abortCall());
911
// Do not abort call nor send anything in reply if default behavior is disabled
916
bool call::abortCall()
920
if ((toolMode != MODE_SERVER) && (msg_index > 0)) {
921
if (call_established == false) {
922
char * src = last_recv_msg ;
924
char L_msg_buffer[SIPP_MAX_MSG_SIZE];
925
L_msg_buffer[0] = '\0';
926
char * L_param = L_msg_buffer;
928
// Answer unexpected errors (4XX, 5XX and beyond) with an ACK
929
// Contributed by F. Tarek Rogers
930
if((src) && (get_reply_code(src) > 400)) {
931
sendBuffer(createSendingMessage(
932
(char*)"ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
933
"Via: SIP/2.0/[transport] [local_ip]:[local_port]\n"
934
"From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n"
935
"To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
936
"Call-ID: [call_id]\n"
938
"Contact: sip:sipp@[local_ip]:[local_port]\n"
940
"Subject: Performance Test\n"
941
"Content-Length: 0\n\n"
944
/* Call is not established and the reply is not a 4XX, 5XX */
945
/* And we already received a message. */
946
if (ack_is_pending == true) {
947
/* If an ACK is expected from the other side, send it
948
* and send a BYE afterwards */
949
ack_is_pending = false;
951
strcpy(L_param, "ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
952
sprintf(L_param, "%s%s", L_param, "[last_Via:]\n");
953
sprintf(L_param, "%s%s", L_param, "[last_From:]\n");
954
sprintf(L_param, "%s%s", L_param, "[last_To:]\n");
955
sprintf(L_param, "%s%s", L_param, "[last_Call-ID:]\n");
956
/* The CSeq of an ACK relating to an INVITE must be the same as */
957
/* the one from the INVITE. */
958
/* Let's simplify this by putting 1 (no support for re-invite in */
960
/* FIXME: store CSeq from last INVITE and re-use it */
961
sprintf(L_param, "%sCSeq: 1 ACK\n", L_param);
962
sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
963
sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
964
res = sendBuffer(createSendingMessage((char*)(L_param),-1));
967
strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
968
sprintf(L_param, "%s%s", L_param, "[last_Via:]\n");
969
sprintf(L_param, "%s%s", L_param, "[last_From:]\n");
970
sprintf(L_param, "%s%s", L_param, "[last_To:]\n");
971
sprintf(L_param, "%s%s", L_param, "[last_Call-ID:]\n");
973
cseq = compute_cseq(src);
975
sprintf(L_param, "%s%s BYE\n", L_param, compute_cseq(src));
977
sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
978
sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
979
res = sendBuffer(createSendingMessage((char*)(L_param),-1));
982
strcpy(L_param, "CANCEL sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
983
sprintf(L_param, "%s%s", L_param, "[last_Via:]\n");
984
sprintf(L_param, "%s%s", L_param, "[last_From:]\n");
985
sprintf(L_param, "%s%s", L_param, "[last_To:]\n");
986
sprintf(L_param, "%s%s", L_param, "[last_Call-ID:]\n");
988
cseq = compute_cseq(src);
990
sprintf(L_param, "%s%s CANCEL\n", L_param, compute_cseq(src));
992
sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
993
sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
994
res = sendBuffer(createSendingMessage((char*)(L_param),-1));
997
/* Call is not established and the reply is not a 4XX, 5XX */
998
/* and we didn't received any message. This is the case when */
999
/* we are aborting after having send an INVITE and not received */
1004
/* Call is established */
1005
char * src = last_recv_msg ;
1006
char L_msg_buffer[SIPP_MAX_MSG_SIZE];
1007
L_msg_buffer[0] = '\0';
1008
char * L_param = L_msg_buffer;
1009
strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
1010
sprintf(L_param, "%s%s", L_param, "[last_Via:]\n");
1011
sprintf(L_param, "%s%s", L_param, "[last_From:]\n");
1012
sprintf(L_param, "%s%s", L_param, "[last_To:]\n");
1013
sprintf(L_param, "%s%s", L_param, "[last_Call-ID:]\n");
1015
cseq = compute_cseq(src);
1017
sprintf(L_param, "%s%s BYE\n", L_param, compute_cseq(src));
1019
sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
1020
sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
1021
res = sendBuffer(createSendingMessage((char*)(L_param),-1));
1029
bool call::rejectCall()
1031
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
1032
CStat::instance()->computeStat(CStat::E_FAILED_CALL_REJECTED);
1039
int call::sendCmdMessage(int index)
1046
if(scenario[index] -> M_sendCmdData) {
1047
// WARNING_P1("---PREPARING_TWIN_CMD---%s---", scenario[index] -> M_sendCmdData);
1048
dest = createSendingMessage(scenario[index] -> M_sendCmdData, -2);
1049
strcat(dest, delimitor);
1050
//WARNING_P1("---SEND_TWIN_CMD---%s---", dest);
1054
rc = send(twinSippSocket,
1059
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
1060
CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
1072
int call::sendCmdBuffer(char* cmd)
1083
strcat(dest, delimitor);
1086
rc = send(twinSippSocket,
1091
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
1092
CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
1102
char* call::createSendingMessage(char * src, int P_index)
1104
static char msg_buffer[SIPP_MAX_MSG_SIZE+2];
1107
char * dest = msg_buffer;
1109
char * length_marker = NULL;
1115
char keyword [KEYWORD_SIZE+1];
1117
key = strchr(src, ']');
1118
if((!key) || ((key - src) > KEYWORD_SIZE) || (!(key - src))){
1119
ERROR("Syntax error or invalid [keyword] in scenario");
1121
memcpy(keyword, src, key - src);
1123
keyword[key - src] = 0;
1125
// allow +n for numeric variables
1126
if ((key = strchr(keyword,'+'))) {
1131
if(!strcmp(keyword, "remote_ip")) {
1132
dest += sprintf(dest, "%s", remote_ip_escaped);
1133
} else if(!strcmp(keyword, "remote_port")) {
1134
dest += sprintf(dest, "%u", remote_port + offset);
1135
} else if(!strcmp(keyword, "transport")) {
1136
dest += sprintf(dest, "%s", TRANSPORT_TO_STRING(transport));
1137
} else if(!strcmp(keyword, "local_ip")) {
1138
dest += sprintf(dest, "%s", local_ip_escaped);
1139
} else if(!strcmp(keyword, "local_port")) {
1140
if((transport == T_UDP) && (multisocket)) {
1141
dest += sprintf(dest, "%u", call_port + offset);
1143
dest += sprintf(dest, "%u", local_port + offset);
1145
} else if(!strcmp(keyword, "media_ip")) {
1146
dest += sprintf(dest, "%s", media_ip_escaped);
1147
} else if(!strcmp(keyword, "media_port")) {
1148
dest += sprintf(dest, "%u", media_port + offset);
1149
} else if(!strcmp(keyword, "call_number")) {
1150
dest += sprintf(dest, "%lu", number);
1151
} else if(!strcmp(keyword, "call_id")) {
1152
dest += sprintf(dest, "%s", id);
1153
} else if(!strcmp(keyword, "pid")) {
1154
dest += sprintf(dest, "%u", pid);
1155
} else if(!strcmp(keyword, "service")) {
1156
dest += sprintf(dest, "%s", service);
1157
} else if(!strncmp(keyword, "field", 5)) {
1158
char* local_dest = dest;
1159
getFieldFromInputFile(keyword, m_localLineNumber, dest);
1160
if (dest == local_dest && ('\r' == *(local_dest-1) || '\n' == *(local_dest-1))) {
1161
/* If the line begins with a field value and there
1162
* is nothing to add for this field,
1163
* Jump to the end of line in scenario. SN
1165
while((*src) && (*src != '\n')) {
1172
} else if(!strcmp(keyword, "peer_tag_param")) {
1173
if(peer_tag && strlen(peer_tag)) {
1174
dest += sprintf(dest, ";tag=%s", peer_tag);
1176
} else if(strstr(keyword, "$")) {
1177
int varId = atoi(keyword+1);
1178
if(varId < SCEN_VARIABLE_SIZE) {
1179
if(M_callVariableTable[varId] != NULL) {
1180
if(M_callVariableTable[varId]->isSet()) {
1181
dest += sprintf(dest, "%s",
1182
M_callVariableTable[varId]->
1183
getMatchingValue());
1184
// WARNING_P1("VARIABLE --%s--", M_callVariableTable[varId]->getMatchingValue());
1186
dest += sprintf(dest, "%s", "");
1190
} else if(strstr(keyword, "last_")) {
1191
char * last_header = get_last_header(keyword+5);
1193
dest += sprintf(dest, "%s", last_header);
1195
/* Jump to the end of line in scenario if nothing
1196
* to insert in place of this header. */
1197
while((*src) && (*src != '\n')) {
1204
} else if(strstr(keyword, "routes")) {
1205
if (dialog_route_set) {
1206
dest += sprintf(dest, "Route: %s", dialog_route_set);
1209
} else if(strstr(keyword, "authentication")) {
1210
/* This keyword is substituted below */
1211
dest += sprintf(dest, "[%s]", keyword);
1213
} else if(strstr(keyword, "len")) {
1214
length_marker = dest;
1215
// dest += sprintf(dest, " 0");
1216
dest += sprintf(dest, " ");
1218
ERROR_P1("Unsupported keyword '%s' in xml scenario file",
1221
} else if (*src == '\n') {
1232
* The authentication substitution must be done outside the above
1233
* loop because auth-int will use the body (which must have already
1234
* been keyword substituted) to build the md5 hash
1237
if((src = strstr(msg_buffer, "[authentication")) && dialog_authentication) {
1239
char my_auth_user[KEYWORD_SIZE];
1240
char my_auth_pass[KEYWORD_SIZE];
1243
strcpy(my_auth_user, service);
1244
strcpy(my_auth_pass, auth_password);
1246
/* Look for optional username and password paramaters */
1247
if(tmp = strstr(src, "username=")) {
1248
tmp += strlen("username=");
1251
if (((key - src) > KEYWORD_SIZE) || (!(key - src))) {
1252
ERROR("Syntax error parsing authentication paramaters");
1253
} else if (*key == ']' || *key < 33 || *key > 126) {
1254
memset(my_auth_user, 0, sizeof(my_auth_user));
1255
strncpy(my_auth_user, tmp, key-tmp);
1262
if(tmp = strstr(src, "password=")) {
1263
tmp += strlen("password=");
1266
if (((key - src) > KEYWORD_SIZE) || (!(key - src))) {
1267
ERROR("Syntax error parsing authentication paramaters");
1268
} else if (*key == ']' || *key < 33 || *key > 126) {
1269
memset(my_auth_pass, 0, sizeof(my_auth_pass));
1270
strncpy(my_auth_pass, tmp, key-tmp);
1277
/* Need the Method name from the CSeq of the Challenge */
1278
char method[MAX_HEADER_LEN];
1279
tmp = get_last_header("CSeq") + 5;
1281
ERROR("Could not extract method from cseq of challenge");
1283
while(isspace(*tmp) || isdigit(*tmp)) tmp++;
1284
sscanf(tmp,"%s", &method);
1286
/* Need the body for auth-int calculation */
1287
char body[SIPP_MAX_MSG_SIZE];
1288
memset(body, 0, sizeof(body));
1291
if (*tmp == '\r' && *(tmp + 1) == '\n' &&
1292
*(tmp + 2) == '\r' && *(tmp + 3) == '\n') {
1293
sprintf(body, "%s", tmp+4);
1299
/* Build the auth credenticals */
1300
char result[MAX_HEADER_LEN];
1301
if (createAuthHeader(my_auth_user, my_auth_pass, method, remote_ip,
1302
body, dialog_authentication, result) == 0) {
1303
ERROR_P1("%s", result);
1306
char tmp_buffer[SIPP_MAX_MSG_SIZE];
1307
dest = strncpy(tmp_buffer, msg_buffer, src - msg_buffer);
1308
dest += src - msg_buffer;
1309
key = strchr(src, ']');
1310
src += key - src + 1;
1312
if (dialog_challenge_type == 401) {
1313
/* Registrars use Authorization */
1314
dest += sprintf(dest, "Authorization: %s", result);
1316
/* Proxies use Proxy-Authorization */
1317
dest += sprintf(dest, "Proxy-Authorization: %s", result);
1319
dest += sprintf(dest, "%s", src);
1320
strcpy(msg_buffer, tmp_buffer);
1324
// Remove all \r, \n but 1 at the end of a message to send
1325
int len = strlen(msg_buffer);
1326
while ( (msg_buffer[len-1] == '\n') &&
1327
(msg_buffer[len-2] == '\r') &&
1328
(msg_buffer[len-3] == '\n') &&
1329
(msg_buffer[len-4] == '\r')) {
1330
msg_buffer[len-2] = 0;
1334
int L_flag_crlf = 0 ; // don't need add crlf
1335
int L_content_length = 0;
1337
if(P_index == -1 ) {
1338
L_flag_crlf = 1 ; // Add crlf
1339
} else if(P_index >= 0 ) {
1340
message::ContentLengthFlag L_flag_content = scenario[P_index] -> content_length_flag ;
1341
switch (L_flag_content) {
1342
case message::ContentLengthValueZero :
1345
case message::ContentLengthValueNoZero :
1346
// the msg contains content-length field and his value is greater than 0
1349
// the msg does not contain content-length field
1351
L_content_length = xp_get_content_length(msg_buffer) ;
1352
if( L_content_length == 0) {
1354
} else if (L_content_length == -1 ) {
1363
msg_buffer[len] ='\r';
1364
msg_buffer[len+1] ='\n';
1365
msg_buffer[len+2] =0;
1368
if (length_marker) {
1369
key = strstr(length_marker,"\r\n\r\n");
1370
if (key && dest - key > 4 && dest - key < 10004) {
1371
char tmp = length_marker[4];
1372
sprintf(length_marker, "%4u", dest - key - 4 + offset);
1373
length_marker[4] = tmp;
1377
ERROR("Unsupported 'send' message in scenario");
1384
bool call::process_twinSippCom(char * msg)
1389
T_ActionResult actionResult;
1391
if (checkInternalCmd(msg) == false) {
1393
for(search_index = msg_index;
1394
search_index < scenario_len;
1396
if(scenario[search_index] -> M_type != MSG_TYPE_RECVCMD) {
1397
if(scenario[search_index] -> optional) {
1400
/* The received message is different from the expected one */
1401
return rejectCall();
1409
scenario[search_index]->M_nbCmdRecv ++;
1411
// variable treatment
1412
// WARNING_P1("---RECVD_TWIN_CMD---%s---", msg);
1413
// Remove \r, \n at the end of a received command
1414
// (necessary for transport, to be removed for usage)
1415
while ( (msg[strlen(msg)-1] == '\n') &&
1416
(msg[strlen(msg)-2] == '\r') ) {
1417
msg[strlen(msg)-2] = 0;
1419
// WARNING_P1("---RECVD_TWIN_CMD AFTER---%s---", msg);
1420
actionResult = executeAction(msg, search_index);
1422
if(actionResult != call::E_AR_NO_ERROR) {
1423
// Store last action result if it is an error
1424
// and go on with the scenario
1425
call::last_action_result = actionResult;
1426
if (actionResult == E_AR_STOP_CALL) {
1427
return rejectCall();
1431
return rejectCall();
1440
bool call::checkInternalCmd(char * cmd)
1443
char * L_ptr1, * L_ptr2, L_backup;
1446
L_ptr1 = strstr(cmd, "internal-cmd:");
1447
if (!L_ptr1) {return (false);}
1449
while((*L_ptr1 == ' ') || (*L_ptr1 == '\t')) { L_ptr1++; }
1450
if (!(*L_ptr1)) {return (false);}
1454
(*L_ptr2 != '\t') &&
1455
(*L_ptr2 != '\r') &&
1456
(*L_ptr2 != '\n')) {
1459
if(!*L_ptr2) { return (false); }
1463
if (strcmp(L_ptr1, "abort_call") == 0) {
1466
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
1476
bool call::process_incomming(char * msg)
1479
static char request[65];
1480
unsigned long cookie;
1484
T_ActionResult actionResult;
1488
#define MATCHES_SCENARIO(index) \
1490
((scenario[index] -> recv_response) == reply_code)) || \
1491
((scenario[index] -> recv_request) && \
1492
(!strcmp(scenario[index] -> recv_request, \
1495
if((transport == T_UDP) && (retrans_enabled)) {
1497
/* Detects retransmissions from peer and retransmit the
1498
* message which was sent just after this one was received */
1500
if(recv_retrans_hash == cookie) {
1504
if(lost(scenario[recv_retrans_recv_index] -> lost)) {
1505
TRACE_MSG((s, "%s message (retrans) lost (recv).",
1506
TRANSPORT_TO_STRING(transport)));
1508
if(comp_state) { comp_free(&comp_state); }
1509
scenario[recv_retrans_recv_index] -> nb_lost++;
1513
send_scene(recv_retrans_send_index, &status);
1516
scenario[recv_retrans_recv_index] -> nb_recv_retrans++;
1517
scenario[recv_retrans_send_index] -> nb_sent_retrans++;
1518
} else if(status < -1) {
1525
if(last_recv_hash == cookie) {
1526
/* This one has already been received, but not processed
1527
* yet => (has not triggered something yet) so we can discard.
1529
* This case appears when the UAS has send a 200 but not received
1530
* a ACK yet. Thus, the UAS retransmit the 200 (invite transaction)
1531
* until it receives a ACK. In this case, it nevers sends the 200
1532
* from the BYE, until it has reveiced the previous 200. Thus,
1533
* the UAC retransmit the BYE, and this BYE is considered as an
1536
* This case can also appear in case of message duplication by
1537
* the network. This should not be considered as an unexpected.
1544
/* Catch peer tag if necessary */
1545
if((!strlen(peer_tag)) &&
1546
(ptr = get_peer_tag(msg))) {
1547
if(strlen(ptr) > (MAX_HEADER_LEN - 1)) {
1548
ERROR("Peer tag too long. Change MAX_TAG_LEN and recompile sipp");
1550
strcpy(peer_tag, ptr);
1553
/* Is it a response ? */
1554
if((msg[0] == 'S') &&
1562
reply_code = get_reply_code(msg);
1564
if (!process_unexpected(msg)) {
1565
return false; // Call aborted by unexpected message handling
1569
} else if(ptr = strchr(msg, ' ')) {
1570
if((ptr - msg) < 64) {
1571
memcpy(request, msg, ptr - msg);
1572
request[ptr - msg] = 0;
1573
// Check if we received an ACK => call established
1574
if (strcmp(request,"ACK")==0) {
1575
call_established=true;
1580
ERROR_P1("SIP method too long in received message '%s'",
1584
ERROR_P1("Invalid sip message received '%s'",
1588
/* Try to find it in the expected non mandatory responses
1589
* until the first mandatory response in the scenario */
1590
for(search_index = msg_index;
1591
search_index < scenario_len;
1594
if(!MATCHES_SCENARIO(search_index)) {
1595
if(scenario[search_index] -> optional) {
1598
/* The received message is different for the expected one */
1603
/* TODO : this is a little buggy: If a 100 trying from an INVITE
1604
* is delayed by the network until the BYE is sent, it may
1605
* stop BYE transmission erroneously, if the BYE also expects
1610
/* Try to find it in the old non-mandatory receptions */
1612
for(search_index = msg_index - 1;
1615
if(MATCHES_SCENARIO(search_index) &&
1616
((scenario[search_index] -> optional))) {
1623
int test = (!found) ? -1 : scenario[search_index]->test;
1624
/* test==0: No branching"
1625
* test==-1 branching without testing"
1626
* test>0 branching with testing
1631
//WARNING_P1("---EXECUTE_ACTION_ON_MSG---%s---", msg);
1633
actionResult = executeAction(msg, search_index);
1635
if(actionResult != call::E_AR_NO_ERROR) {
1636
// Store last action result if it is an error
1637
// and go on with the scenario
1638
call::last_action_result = actionResult;
1639
if (actionResult == E_AR_STOP_CALL) {
1640
return rejectCall();
1649
if ((L_case = checkAutomaticResponseMode(request)) == 0) {
1650
if (!process_unexpected(msg)) {
1651
return false; // Call aborted by unexpected message handling
1654
automaticResponseMode(L_case, msg);
1655
return false ; // call aborted by automatic response mode
1659
/* Simulate loss of messages */
1660
if(lost(scenario[search_index] -> lost)) {
1661
TRACE_MSG((s, "%s message lost (recv).",
1662
TRANSPORT_TO_STRING(transport)));
1663
if(comp_state) { comp_free(&comp_state); }
1664
scenario[search_index] -> nb_lost++;
1668
/* This is an ACK or a response, and its index is greater than the
1669
* current active retransmission message, so we stop the retrans timer. */
1671
(!strcmp(request, "ACK"))) &&
1672
(search_index > last_send_index)) {
1676
/* This is a response with 200 so set the flag indicating that an
1677
* ACK is pending (used to prevent from release a call with CANCEL
1678
* when an ACK+BYE should be sent instead) */
1679
if (reply_code == 200) {
1680
ack_is_pending = true;
1683
/* If this message can be used to compute RTD, do it now */
1685
if(scenario[search_index] -> start_rtd) {
1686
start_time_rtd = clock_tick;
1689
if(scenario[search_index] -> stop_rtd) {
1690
rtd_sum += clock_tick - start_time_rtd;
1692
computeStat(CStat::E_ADD_RESPONSE_TIME_DURATION,
1693
clock_tick - start_time_rtd);
1699
/* Increment the recv counter */
1700
scenario[search_index] -> nb_recv++;
1702
/* store the route set only once. TODO: does not support target refreshes!! */
1703
if (scenario[search_index] -> bShouldRecordRoutes &&
1704
NULL == dialog_route_set ) {
1706
/* should cache the route set */
1710
char rr[MAX_HEADER_LEN];
1711
strcpy(rr, get_header_content(msg, (char*)"Record-Route:"));
1713
char actual_rr[MAX_HEADER_LEN];
1714
memset(actual_rr, 0, sizeof(actual_rr));
1719
char* pointer = strrchr(rr, ',');
1722
strcat(actual_rr, pointer + 1);
1728
strcat(actual_rr, rr);
1734
/* lose the bottom most record route -- that is the SUT */
1736
char ch[MAX_HEADER_LEN];
1737
strcpy(ch, get_header_content(msg, (char*)"Contact:"));
1739
if (strlen(actual_rr)) {
1740
dialog_route_set = (char *)
1741
calloc(1, strlen(actual_rr) + strlen(ch) + 2);
1742
sprintf(dialog_route_set, "%s,%s", actual_rr, ch);
1744
dialog_route_set = (char *)
1745
calloc(1, strlen(ch) + 2);
1746
sprintf(dialog_route_set, "%s", ch);
1752
char rr[MAX_HEADER_LEN];
1753
strcpy(rr, get_header_content(msg, (char*)"Record-Route:"));
1755
/* toss the first RR, it is going to be the SUT */
1756
char* actual_rr = strchr(rr, ',');
1762
char ch[MAX_HEADER_LEN];
1763
strcpy(ch, get_header_content(msg, (char*)"Contact:"));
1766
dialog_route_set = (char *)
1767
calloc(1, strlen(actual_rr) + strlen(ch) + 2);
1768
sprintf(dialog_route_set, "%s,%s", actual_rr, ch);
1770
dialog_route_set = (char *)
1771
calloc(1, strlen(ch) + 2);
1772
sprintf(dialog_route_set, "%s", ch);
1778
/* store the authentication info */
1779
if ((scenario[search_index] -> bShouldAuthenticate) &&
1780
(reply_code == 401 || reply_code == 407)) {
1782
/* is a challenge */
1783
char auth[MAX_HEADER_LEN];
1784
memset(auth, 0, sizeof(auth));
1785
strcpy(auth, get_header_content(msg, (char*)"Proxy-Authenticate:"));
1787
strcpy(auth, get_header_content(msg, (char*)"WWW-Authenticate:"));
1791
dialog_authentication = (char *) calloc(1, strlen(auth) + 2);
1792
sprintf(dialog_authentication, "%s", auth);
1794
/* Store the code of the challenge for building the proper header */
1795
dialog_challenge_type = reply_code;
1799
/* If this was a mandatory message, and keeps its cookie for
1800
* future retransmissions, and its body for fields inclusion
1801
* in our messages. Similarly if there is an explicit next label set
1803
if (!(scenario[search_index] -> optional) ||
1804
scenario[search_index]->next &&
1806
(test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
1808
msg_index = search_index;
1810
/* Store last recv msg information */
1811
last_recv_index = search_index;
1812
last_recv_hash = cookie;
1814
last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
1815
strcpy(last_recv_msg, msg);
1821
call::T_ActionResult call::executeAction(char * msg, int scenarioIndex)
1824
CAction* currentAction;
1825
CVariable* scenVariable;
1826
char msgPart[MAX_SUB_MESSAGE_LENGTH];
1829
actions = scenario[scenarioIndex]->M_actions;
1830
// looking for action to do on this message
1831
if(actions != NULL) {
1832
for(int i=0; i<actions->getUsedAction(); i++) {
1833
currentAction = actions->getAction(i);
1834
if(currentAction != NULL) {
1835
if(currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_REGEXP) {
1836
currentId = currentAction->getVarId();
1837
scenVariable = scenVariableTable[currentId];
1838
if(scenVariable != NULL) {
1839
if(currentAction->getLookingPlace() == CAction::E_LP_HDR) {
1842
currentAction->getLookingChar(),
1845
if(strlen(msgPart) > 0) {
1847
scenVariable->executeRegExp
1849
M_callVariableTable,
1851
currentAction->getNbSubVarId(),
1852
currentAction->getSubVarId()
1855
if( (!(M_callVariableTable[currentId]->isSet()))
1856
&& (currentAction->getCheckIt() == true) ) {
1857
// the message doesn't match and the checkit
1858
// action say it MUST match
1859
// Allow easier regexp debugging
1860
WARNING_P2("Failed regexp match: looking "
1861
"in '%s', with regexp '%s'",
1864
getRegularExpression());
1865
// --> Call will be marked as failed
1866
return(call::E_AR_REGEXP_DOESNT_MATCH);
1868
} else {// sub part of message not found
1869
if( currentAction->getCheckIt() == true ) {
1870
// the sub message is not found and the
1871
// checking action say it MUST match
1872
// --> Call will be marked as failed but
1874
return(call::E_AR_HDR_NOT_FOUND);
1877
} else {// we must look in the entire message
1878
// WARNING_P1("LOOKING IN MSG -%s-", msg);
1879
scenVariable->executeRegExp
1881
M_callVariableTable,
1883
currentAction->getNbSubVarId(),
1884
currentAction->getSubVarId()
1888
if((!(M_callVariableTable[currentId]->isSet()))
1889
&& (currentAction->getCheckIt() == true) ) {
1890
// the message doesn't match and the checkit
1891
// action say it MUST match
1892
// Allow easier regexp debugging
1893
WARNING_P2("Failed regexp match: looking in '%s'"
1894
", with regexp '%s'",
1896
scenVariable->getRegularExpression());
1897
// --> rejecting the call
1898
return(call::E_AR_REGEXP_DOESNT_MATCH);
1901
} // end if scen variable != null
1902
} else /* end action == E_AT_ASSIGN_FROM_REGEXP */
1903
if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
1904
char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
1905
LOG_MSG((s, "%s\n", x));
1906
} else /* end action == E_AT_LOG_TO_FILE */
1907
if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
1909
if (currentAction->getCmdLine()) {
1910
char* x = createSendingMessage(currentAction->getCmdLine(), -2 /* do not add crlf*/);
1911
// TRACE_MSG((s, "Trying to execute [%s]", x));
1913
switch(l_pid = fork())
1916
// error when forking !
1917
ERROR("Forking error");
1921
// child process - execute the command
1926
// parent process continue
1930
} else /* end action == E_AT_LOG_TO_FILE */
1931
if (currentAction->getActionType() == CAction::E_AT_EXEC_INTCMD) {
1932
switch (currentAction->getIntCmd())
1934
case CAction::E_INTCMD_STOP_ALL:
1937
case CAction::E_INTCMD_STOP_NOW:
1938
screen_exit(EXIT_TEST_RES_INTERNAL);
1940
case CAction::E_INTCMD_STOPCALL:
1942
return(call::E_AR_STOP_CALL);
1945
} else {// end action == E_AT_EXECUTE_CMD
1946
ERROR("call::executeAction unknown action");
1948
} // end if current action != null
1951
return(call::E_AR_NO_ERROR);
1954
void call::extractSubMessage(char * msg, char * matchingString, char* result)
1961
ptr = strstr(msg, matchingString);
1963
len = strlen(matchingString);
1964
strcpy(result, ptr+len);
1965
sizeOf = strlen(result);
1966
if(sizeOf >= MAX_SUB_MESSAGE_LENGTH)
1967
sizeOf = MAX_SUB_MESSAGE_LENGTH-1;
1968
while((i<sizeOf) && (result[i] != '\n') && (result[i] != '\r'))
1976
void call::dumpFileContents(void)
1978
WARNING_P3("Line choosing strategy is [%s]. m_counter [%d] numLinesInFile [%d]",
1979
m_usage == InputFileSequentialOrder ? "SEQUENTIAL" : "RANDOM",
1980
m_counter, numLinesInFile);
1982
for (int i(0); i < numLinesInFile && fileContents[i][0]; ++i) {
1983
WARNING_P2("%dth line reads [%s]", i, fileContents[i].c_str());
1987
/* Read MAX_CHAR_BUFFER_SIZE size lines from the
1988
* "fileName" and populate it in the fileContents
1989
* vector. The file should not be more than
1990
* MAX_LINES_IN_FILE lines long and each line
1991
* should be terminated with a '\n'
1994
void call::readInputFileContents(const char* fileName)
1996
ifstream *inFile = new ifstream(fileName);
1997
ifstream &inFileObj = *inFile;
1998
char line[MAX_CHAR_BUFFER_SIZE];
2000
if (!inFile->good()) {
2001
ERROR_P1("Unable to open file %s", fileName);
2006
call::m_counter = 0;
2008
inFileObj.getline(line, MAX_CHAR_BUFFER_SIZE);
2010
if (NULL != strstr(line, "RANDOM")) {
2011
call::m_usage = InputFileRandomOrder;
2012
} else if (NULL != strstr(line, "SEQUENTIAL")) {
2013
call::m_usage = InputFileSequentialOrder;
2016
call::m_usage = InputFileSequentialOrder;
2019
while (!inFileObj.eof()) {
2021
inFileObj.getline(line, MAX_CHAR_BUFFER_SIZE);
2023
if ('#' != line[0]) {
2024
fileContents.push_back(line);
2025
numLinesInFile++; /* this counts number of valid data lines */
2031
// call::dumpFileContents();
2035
void call::getFieldFromInputFile(const char* keyword, int lineNum, char*& dest)
2037
int nthField = atoi(keyword+5 /*strlen("field")*/);
2038
int origNth = nthField;
2040
if (fileContents.size() > lineNum) {
2041
const string& line = fileContents[lineNum];
2043
// WARNING_P3("lineNum [%d] nthField [%d] line [%s]",
2044
// lineNum, nthField, line.c_str());
2046
int pos(0), oldpos(0);
2049
int localint = line.find(';', oldpos);
2051
if (localint != string::npos) {
2058
//string x = line.substr(oldpos, pos - oldpos);
2059
// WARNING_P3("pos [%d] oldpos [%d] is [%s]", pos, oldpos, x.c_str());
2067
} while (oldpos != string::npos);
2070
WARNING_P1("Field %d not found in the file", origNth);
2071
// field not found in line
2073
if (string::npos != oldpos) {
2074
if (string::npos != pos) {
2075
// should not be decremented for fieldN
2076
pos -= (oldpos + 1);
2079
string x = line.substr(oldpos, pos);
2081
dest += sprintf(dest, "%s", x.c_str());
2084
// WARNING_P2("nthField [%d] is [%s]", origNth, x.c_str());
2088
// WARNING_P1("Field %d definition not found", nthField);
2092
int call::checkAutomaticResponseMode(char * P_recv) {
2096
if (strcmp(P_recv, "BYE")==0) {
2098
} else if (strcmp(P_recv, "CANCEL") == 0) {
2100
} else if (strcmp(P_recv, "PING") == 0) {
2109
void call::automaticResponseMode(int P_case, char * P_recv)
2114
// usage of last_ keywords
2115
last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
2116
strcpy(last_recv_msg, P_recv);
2119
case 1: // response for an unexpected BYE
2120
if (default_behavior) {
2121
WARNING_P1("Aborting call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
2122
res = sendBuffer(createSendingMessage(
2123
(char*)"SIP/2.0 200 OK\n"
2129
"Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
2130
"Content-Length: 0\n"
2134
// if twin socket call => reset the other part here
2135
if (twinSippSocket && (msg_index > 0)) {
2137
(createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
2139
#endif /* __3PCC__ */
2140
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
2141
CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
2144
WARNING_P1("Continuing call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
2148
case 2: // response for an unexpected cancel
2149
if (default_behavior) {
2150
WARNING_P1("Aborting call on an unexpected CANCEL for call: %s", (id==NULL)?"none":id);
2151
res = sendBuffer(createSendingMessage(
2152
(char*)"SIP/2.0 200 OK\n"
2158
"Contact: sip:sipp@[local_ip]:[local_port]\n"
2163
// if twin socket call => reset the other part here
2164
if (twinSippSocket && (msg_index > 0)) {
2166
(createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
2168
#endif /* __3PCC__ */
2170
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
2171
CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
2174
WARNING_P1("Continuing call on unexpected CANCEL for call: %s", (id==NULL)?"none":id);
2178
case 3: // response for a random ping
2179
if (default_behavior) {
2180
WARNING_P1("Automatic response mode for an unexpected PING for call: %s", (id==NULL)?"none":id);
2181
count_in_stats = false; // Call must not be counted in statistics
2182
res = sendBuffer(createSendingMessage(
2183
(char*)"SIP/2.0 200 OK\n"
2189
"Contact: sip:sipp@[local_ip]:[local_port]\n"
2192
// Note: the call ends here but it is not marked as bad. PING is a
2195
// if twin socket call => reset the other part here
2196
if (twinSippSocket && (msg_index > 0)) {
2198
(createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n",-1));
2200
#endif /* __3PCC__ */
2202
CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
2205
WARNING_P1("Do not answer on an unexpected PING for call: %s", (id==NULL)?"none":id);
2210
ERROR_P1("Internal error for automaticResponseMode %d", P_case);