Skip to content

Commit fab4019

Browse files
Matthew Briggsorgads
Matthew Briggs
authored andcommitted
Enable a mixture of server-mode and client-mode operation simultaneously
Source: https://sourceforge.net/p/sipp/mailman/message/28557628/ I'm posting the following modifications in case others have been battling the same sipp limitations as I have. Background ========== I've had weeks of battle with SIPP server-mode scripts in an environment where maintaining registration with an SBC is required. Server mode means that you cannot start a script with a 'send' to carry out the registration, so a separate script had to be executed first to do this. Then all sorts of scripting acrobatics were required to maintain a registration (which had a 60 second expiry) and respond to options pings (as used by dynamic HNT to calculate the NAT timeout) during execution. Additionally running SIP over TCP proved completely impossible for server-mode (terminating party) scenarios - as discussed in a previous mail, our SBC drops the registration as soon as it received a FIN on the TCP session used to register the endpoint, meaning that it was impossible to run a separate client-mode script to register, then a server-mode script to terminate calls without losing our registration when the first script exits. The obvious solution was to enable SIPP to run in a mixture of client and server mode concurrently. Solution ======== The following diff log shows to updates required to do the above. The modifications add two new command line parameters: -sfrx -snrx Including either of these at the command line puts SIPP into a mixed mode where it loads two scenarios, the first (specified in -sn or -sf) in client mode, and the second (specified in -snrx or -sfrx) in server mode. The client mode scenario runs as normal, starting as many calls as specified in the command line parameters -m and -l. Any unsolicited messages are handled in server mode by the second scenario - spawning a new 'call' to handle each new incoming call-id received as done in normal server mode. The -m and -l call limits are ignored by the second server-mode scenario. The result is that a client mode scenario file can be specified in -sf to handle registration or make outgoing calls, and a server mode scenario file can simultaneously be specified in -sfrx to terminate multiple incoming calls and handle incoming options pings. This differs from the OOC scenario allowed previously where all incoming unsolicited messages were handled by the same 'call' irrespective of their call-id, making this option unusable for handling multiple simultaneous incoming calls. Fixes #745.
1 parent 464cf74 commit fab4019

13 files changed

+147
-65
lines changed

include/call.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ class call : virtual public task, virtual public listener, public virtual socket
7777
public:
7878
/* These are wrappers for various circumstances, (private) init does the real work. */
7979
//call(char * p_id, int userId, bool ipv6, bool isAutomatic);
80-
call(const char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest);
81-
call(const char *p_id, SIPpSocket *socket, struct sockaddr_storage *dest);
80+
call(scenario *call_scenario, const char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest);
81+
call(scenario *call_scenario, const char *p_id, SIPpSocket *socket, struct sockaddr_storage *dest);
8282
static call *add_call(int userId, bool ipv6, struct sockaddr_storage *dest);
8383
call(scenario * call_scenario, SIPpSocket *socket, struct sockaddr_storage *dest, const char * p_id, int userId, bool ipv6, bool isAutomatic, bool isInitCall);
8484

include/fileutil.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern "C"
2222
{
2323
#endif
2424

25-
char* find_file(const char* filename);
25+
char* find_file(const char* filename, const char *basepath);
2626

2727
#ifdef __cplusplus
2828
}

include/scenario.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
#define MODE_CLIENT 0
4646
#define MODE_SERVER 1
47+
#define MODE_MIXED 2
4748

4849
#define MODE_3PCC_NONE 0
4950
#define MODE_3PCC_CONTROLLER_A 2
@@ -190,6 +191,9 @@ class scenario
190191
int get_counter(const char *varName, const char *what);
191192
int get_rtd(const char *ptr, bool start);
192193
int find_var(const char *varName);
194+
void setFileName(const char *fileName);
195+
const std::string &getFileName() const { return fileName; }
196+
const std::string &getPath() const { return path; }
193197

194198
void addRtpTaskThreadID(pthread_t id);
195199
void removeRtpTaskThreadID(pthread_t id);
@@ -205,6 +209,8 @@ class scenario
205209
str_int_map initLabelMap;
206210

207211
str_int_map txnMap;
212+
std::string fileName;
213+
std::string path;
208214

209215
bool found_timewait;
210216

@@ -232,6 +238,7 @@ class scenario
232238

233239
/* There are external variable containing the current scenario */
234240
extern scenario *main_scenario;
241+
extern scenario *rx_scenario;
235242
extern scenario *ooc_scenario;
236243
extern scenario *aa_scenario;
237244
extern scenario *display_scenario;

include/send_packets.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ typedef struct {
124124
extern "C"
125125
{
126126
#endif
127-
int parse_play_args(const char*, pcap_pkts*);
127+
int parse_play_args(const char*, const char*, pcap_pkts*);
128128
int parse_dtmf_play_args(const char*, pcap_pkts*, uint16_t start_seq_no);
129129
void free_pcaps(pcap_pkts* pkts);
130130
void send_packets(play_args_t*);

include/sipp.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -326,13 +326,14 @@ MAYBE_EXTERN double tls_version DEFVAL(0.0);
326326
MAYBE_EXTERN const char * bind_to_device_name DEFVAL(nullptr);
327327
#endif
328328

329-
MAYBE_EXTERN char* scenario_file DEFVAL(nullptr);
330-
MAYBE_EXTERN char* scenario_path DEFVAL(nullptr);
329+
MAYBE_EXTERN const char * scenario_file DEFVAL(nullptr);
331330

332331
// extern field file management
333332
typedef std::map<std::string, FileContents *> file_map;
334333
MAYBE_EXTERN file_map inFiles;
335334
typedef std::map<std::string, str_int_map *> file_index;
335+
MAYBE_EXTERN char *rx_ip_file DEFVAL(NULL);
336+
MAYBE_EXTERN char *rx_default_file DEFVAL(NULL);
336337
MAYBE_EXTERN char *ip_file DEFVAL(nullptr);
337338
MAYBE_EXTERN char *default_file DEFVAL(nullptr);
338339

src/actions.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ void CAction::setPcapArgs(const char* P_value)
539539

540540
if (P_value != nullptr) {
541541
M_pcapArgs = (pcap_pkts *) malloc(sizeof(*M_pcapArgs));
542-
if (parse_play_args(P_value, M_pcapArgs) == -1) {
542+
if (parse_play_args(P_value, M_scenario->getPath().c_str(), M_pcapArgs) == -1) {
543543
ERROR("Play pcap error");
544544
}
545545
if (access(M_pcapArgs->file, F_OK)) {
@@ -712,7 +712,7 @@ void CAction::setRTPStreamActInfo(const char *P_value)
712712

713713
// Lookup best file match
714714
if (pattern_mode == 0) {
715-
found_file = find_file(argument_buf);
715+
found_file = find_file(argument_buf, M_scenario->getPath().c_str());
716716
if (found_file) {
717717
if (strlen(found_file) >= sizeof(M_rtpstream_actinfo.filename)) {
718718
ERROR("Filename/Pattern keyword %s is too long -- maximum supported length %zu",

src/call.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -785,14 +785,14 @@ unsigned long call::hash(const char * msg)
785785
}
786786

787787
/******************* Call class implementation ****************/
788-
call::call(const char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest) : listener(p_id, true)
788+
call::call(scenario *call_scenario, const char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest) : listener(p_id, true)
789789
{
790-
init(main_scenario, nullptr, dest, p_id, userId, use_ipv6, false, false);
790+
init(call_scenario, nullptr, dest, p_id, userId, use_ipv6, false, false);
791791
}
792792

793-
call::call(const char *p_id, SIPpSocket *socket, struct sockaddr_storage *dest) : listener(p_id, true)
793+
call::call(scenario *call_scenario, const char *p_id, SIPpSocket *socket, struct sockaddr_storage *dest) : listener(p_id, true)
794794
{
795-
init(main_scenario, socket, dest, p_id, 0 /* No User. */, socket->ss_ipv6, false /* Not Auto. */, false);
795+
init(call_scenario, socket, dest, p_id, 0 /* No User. */, socket->ss_ipv6, false /* Not Auto. */, false);
796796
}
797797

798798
call::call(scenario * call_scenario, SIPpSocket *socket, struct sockaddr_storage *dest, const char * p_id, int userId, bool ipv6, bool isAutomatic, bool isInitialization) : listener(p_id, true)
@@ -6857,7 +6857,7 @@ void *send_wrapper(void *arg)
68576857

68586858
class mockcall : public call {
68596859
public:
6860-
mockcall(bool is_ipv6) : listener("//testing", true), call("///testing", is_ipv6, 0, nullptr) {}
6860+
mockcall(bool is_ipv6) : listener("//testing", true), call(main_scenario, "///testing", is_ipv6, 0, nullptr) {}
68616861

68626862
/* Helpers to poke at protected internals */
68636863
void parse_media_addr(std::string const& msg) { get_remote_media_addr(msg); }

src/fileutil.c

+4-6
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
#include <string.h>
2323
#include <unistd.h>
2424

25-
extern char* scenario_path;
26-
2725
int expand_user_path(const char* path, char* expanded_home_path /*The buffer*/, size_t buflen)
2826
{
2927
if (path[0] != '~') { /* We have nothing to expand here */
@@ -79,7 +77,7 @@ int expand_user_path(const char* path, char* expanded_home_path /*The buffer*/,
7977
return 1;
8078
}
8179

82-
char* find_file(const char* filename)
80+
char* find_file(const char* filename, const char *basepath)
8381
{
8482
char tmppath[MAX_PATH];
8583
tmppath[0] = '\0';
@@ -88,13 +86,13 @@ char* find_file(const char* filename)
8886
filepathptr = filename;
8987
}
9088

91-
if (filepathptr[0] == '/' || !*scenario_path) {
89+
if (filepathptr[0] == '/' || !*basepath) {
9290
return strdup(filepathptr);
9391
}
9492

95-
size_t len = strlen(scenario_path) + strlen(filepathptr) + 1;
93+
size_t len = strlen(basepath) + strlen(filepathptr) + 1;
9694
char* fullpath = malloc(len);
97-
snprintf(fullpath, len, "%s%s", scenario_path, filepathptr);
95+
snprintf(fullpath, len, "%s%s", basepath, filepathptr);
9896

9997
if (access(fullpath, R_OK) < 0) {
10098
free(fullpath);

src/scenario.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ message::~message()
136136

137137
/******** Global variables which compose the scenario file **********/
138138

139+
scenario *rx_scenario;
139140
scenario *main_scenario;
140141
scenario *ooc_scenario;
141142
scenario *aa_scenario;
@@ -410,6 +411,25 @@ void scenario::addRtpTaskThreadID(pthread_t id)
410411
threadIDs[id] = "threadID";
411412
}
412413

414+
void scenario::setFileName(const char *name)
415+
{
416+
const char* sep = strrchr(name, '/');
417+
if (sep) {
418+
++sep; // include slash
419+
path = std::string(name, sep - name);
420+
} else {
421+
path.clear();
422+
sep = name;
423+
}
424+
const char* ext = strrchr(sep, '.');
425+
if (ext && strcmp(ext, ".xml") == 0) {
426+
fileName = std::string(sep, ext - sep);
427+
} else {
428+
fileName = sep;
429+
}
430+
stats->setFileName(fileName.c_str(), ".csv");
431+
}
432+
413433
void scenario::removeRtpTaskThreadID(pthread_t id)
414434
{
415435
threadIDs.erase(id);
@@ -697,6 +717,9 @@ scenario::scenario(char * filename, int deflt)
697717
stats = new CStat();
698718
allocVars = new AllocVariableTable(userVariables);
699719

720+
if(filename) {
721+
setFileName(filename);
722+
}
700723
hidedefault = false;
701724

702725
elem = xp_open_element(0);
@@ -1248,7 +1271,9 @@ void scenario::computeSippMode()
12481271
bool isRecvCmdFound = false;
12491272
bool isSendCmdFound = false;
12501273

1251-
creationMode = -1;
1274+
if (creationMode != MODE_MIXED) {
1275+
creationMode = -1;
1276+
}
12521277
sendMode = -1;
12531278
thirdPartyMode = MODE_3PCC_NONE;
12541279

src/screen.cpp

+23-8
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ void print_statistics(int last)
8080
}
8181
}
8282

83+
static bool display_client()
84+
{
85+
return (creationMode == MODE_CLIENT) || ((creationMode == MODE_MIXED) && (display_scenario == main_scenario));
86+
}
87+
88+
static bool display_server()
89+
{
90+
return (creationMode == MODE_SERVER) || ((creationMode == MODE_MIXED) && (display_scenario == rx_scenario));
91+
}
92+
93+
8394
void ScreenPrinter::print_closing_stats() {
8495
M_last = true;
8596
get_lines();
@@ -220,6 +231,10 @@ void ScreenPrinter::get_lines()
220231
ERROR("Internal error: creationMode=%d, thirdPartyMode=%d",
221232
creationMode, thirdPartyMode);
222233
}
234+
} else if((creationMode == MODE_MIXED) && (display_scenario == main_scenario)) {
235+
lines.push_back("----------------Sipp Mixed Mode - main - call originating scenario------------");
236+
} else if((creationMode == MODE_MIXED) && (display_scenario == rx_scenario)) {
237+
lines.push_back("-----------------Sipp Mixed mode - rx - call terminating screnario-------------");
223238
} else {
224239
assert(creationMode == MODE_SERVER);
225240
switch (thirdPartyMode) {
@@ -270,14 +285,14 @@ void ScreenPrinter::draw_scenario_screen()
270285
unsigned long long total_calls =
271286
display_scenario->stats->GetStat(CStat::CPT_C_IncomingCallCreated) +
272287
display_scenario->stats->GetStat(CStat::CPT_C_OutgoingCallCreated);
273-
if (creationMode == MODE_SERVER) {
288+
if (display_server()) {
274289
lines.push_back(" Port Total-time Total-calls Transport");
275290
snprintf(buf, bufsiz, " %-5d %6lu.%02lu s %8llu %s", local_port,
276291
clock_tick / 1000, (clock_tick % 1000) / 10, total_calls,
277292
TRANSPORT_TO_STRING(transport));
278293
lines.push_back(buf);
279294
} else {
280-
assert(creationMode == MODE_CLIENT);
295+
assert(display_client());
281296
if (users >= 0) {
282297
lines.push_back(" Users (length) Port Total-time "
283298
"Total-calls Remote-host");
@@ -320,7 +335,7 @@ void ScreenPrinter::draw_scenario_screen()
320335
lines.push_back(buf);
321336

322337
/* 2nd line */
323-
if (creationMode == MODE_SERVER) {
338+
if (display_server()) {
324339
snprintf(left_buf, 40, "%llu calls",
325340
display_scenario->stats->GetStat(CStat::CPT_C_CurrentCall));
326341
} else {
@@ -342,7 +357,7 @@ void ScreenPrinter::draw_scenario_screen()
342357
/* 3rd line dead call msgs, and optional out-of-call msg */
343358
snprintf(left_buf, 40, "%llu dead call msg (discarded)",
344359
display_scenario->stats->GetStat(CStat::CPT_G_C_DeadCallMsgs));
345-
if (creationMode == MODE_CLIENT) {
360+
if (display_client()) {
346361
snprintf(
347362
buf, bufsiz, " %-38s %llu out-of-call msg (discarded)", left_buf,
348363
display_scenario->stats->GetStat(CStat::CPT_G_C_OutOfCallMsgs));
@@ -479,7 +494,7 @@ void ScreenPrinter::draw_scenario_screen()
479494
int buf_len = 0;
480495

481496
if (SendingMessage* src = curmsg->send_scheme) {
482-
if (creationMode == MODE_SERVER) {
497+
if (display_server()) {
483498
if (src->isResponse()) {
484499
buf_len += snprintf(buf + buf_len, bufsiz - buf_len,
485500
" <---------- %-10d ", src->getCode());
@@ -527,7 +542,7 @@ void ScreenPrinter::draw_scenario_screen()
527542
: "");
528543
}
529544
} else if (curmsg->recv_response) {
530-
if (creationMode == MODE_SERVER) {
545+
if (display_server()) {
531546
buf_len += snprintf(buf + buf_len, bufsiz - buf_len,
532547
" ----------> %-10s ", curmsg->recv_response);
533548
} else {
@@ -570,7 +585,7 @@ void ScreenPrinter::draw_scenario_screen()
570585
}
571586
int len = strlen(desc) < 9 ? 9 : strlen(desc);
572587

573-
if (creationMode == MODE_SERVER) {
588+
if (display_server()) {
574589
snprintf(left_buf, 40, " [%9s] Pause%*s", desc,
575590
23 - len > 0 ? 23 - len : 0, "");
576591
} else {
@@ -583,7 +598,7 @@ void ScreenPrinter::draw_scenario_screen()
583598
curmsg->sessions,
584599
curmsg->nb_unexp);
585600
} else if (curmsg->recv_request) {
586-
if (creationMode == MODE_SERVER) {
601+
if (display_server()) {
587602
buf_len +=
588603
snprintf(buf + buf_len, bufsiz - buf_len,
589604
" ----------> %-10s ", curmsg->recv_request);

src/send_packets.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ float2timer(float time, struct timeval *tvp)
9393
tvp->tv_usec = n * 100000;
9494
}
9595

96-
int parse_play_args(const char* filename, pcap_pkts* pkts)
96+
int parse_play_args(const char* filename, const char *basepath, pcap_pkts* pkts)
9797
{
98-
pkts->file = find_file(filename);
98+
pkts->file = find_file(filename, basepath);
9999
prepare_pkts(pkts->file, pkts);
100100
return 1;
101101
}

0 commit comments

Comments
 (0)