You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3262 lines
112 KiB
3262 lines
112 KiB
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author : Richard GAYRAUD - 04 Nov 2003
|
|
* Olivier Jacques
|
|
* From Hewlett Packard Company.
|
|
* Shriram Natarajan
|
|
* Peter Higginson
|
|
* Venkatesh
|
|
* Lee Ballard
|
|
* Guillaume TEISSIER from FTR&D
|
|
* Wolfgang Beck
|
|
* Marc Van Diest from Belgacom
|
|
* Charles P. Wright from IBM Research
|
|
* Michael Stovenour
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include "sipp.hpp"
|
|
#ifdef HAVE_GSL
|
|
#include <gsl/gsl_rng.h>
|
|
#include <gsl/gsl_randist.h>
|
|
#include <gsl/gsl_cdf.h>
|
|
#endif
|
|
|
|
/************************ Class Constructor *************************/
|
|
|
|
message::message(int index, const char *desc)
|
|
{
|
|
this->index = index;
|
|
this->desc = desc;
|
|
pause_distribution = NULL;
|
|
pause_variable = -1;
|
|
pause_desc = NULL;
|
|
sessions = 0;
|
|
bShouldRecordRoutes = 0;
|
|
bShouldAuthenticate = 0;
|
|
|
|
send_scheme = NULL;
|
|
retrans_delay = 0;
|
|
timeout = 0;
|
|
|
|
recv_response = 0;
|
|
recv_request = NULL;
|
|
optional = 0;
|
|
advance_state = true;
|
|
regexp_match = 0;
|
|
regexp_compile = NULL;
|
|
|
|
/* Anyway */
|
|
start_rtd = 0;
|
|
stop_rtd = 0;
|
|
repeat_rtd = 0;
|
|
lost = -1;
|
|
crlf = 0;
|
|
hide = 0;
|
|
display_str = NULL;
|
|
test = -1;
|
|
condexec = -1;
|
|
condexec_inverse = false;
|
|
chance = 0;/* meaning always */
|
|
next = -1;
|
|
nextLabel = NULL;
|
|
on_timeout = -1;
|
|
onTimeoutLabel = NULL;
|
|
timewait = false;
|
|
|
|
/* 3pcc extended mode */
|
|
peer_dest = NULL;
|
|
peer_src = NULL;
|
|
|
|
/* Statistics */
|
|
nb_sent = 0;
|
|
nb_recv = 0;
|
|
nb_sent_retrans = 0;
|
|
nb_recv_retrans = 0;
|
|
nb_timeout = 0;
|
|
nb_unexp = 0;
|
|
nb_lost = 0;
|
|
counter = 0;
|
|
|
|
M_actions = NULL;
|
|
|
|
M_type = 0;
|
|
|
|
M_sendCmdData = NULL;
|
|
M_nbCmdSent = 0;
|
|
M_nbCmdRecv = 0;
|
|
|
|
content_length_flag = ContentLengthNoPresent;
|
|
|
|
/* How to match responses to this message. */
|
|
start_txn = 0;
|
|
response_txn = 0;
|
|
ack_txn = 0;
|
|
recv_response_for_cseq_method_list = NULL;
|
|
}
|
|
|
|
message::~message()
|
|
{
|
|
if(M_actions != NULL)
|
|
delete(M_actions);
|
|
|
|
if(send_scheme != NULL)
|
|
delete send_scheme;
|
|
|
|
if(recv_request != NULL)
|
|
free (recv_request);
|
|
|
|
if(regexp_compile != NULL)
|
|
regfree(regexp_compile);
|
|
free(regexp_compile);
|
|
|
|
|
|
if (pause_distribution) {
|
|
delete pause_distribution;
|
|
}
|
|
|
|
if(M_sendCmdData != NULL)
|
|
delete M_sendCmdData;
|
|
|
|
free(display_str);
|
|
free(peer_dest);
|
|
free(peer_src);
|
|
free(pause_desc);
|
|
free(recv_response_for_cseq_method_list);
|
|
}
|
|
|
|
/******** Global variables which compose the scenario file **********/
|
|
|
|
scenario *main_scenario;
|
|
scenario *ooc_scenario;
|
|
scenario *aa_scenario;
|
|
scenario *display_scenario;
|
|
|
|
/* This mode setting refers to whether we open calls autonomously (MODE_CLIENT)
|
|
* or in response to requests (MODE_SERVER). */
|
|
int creationMode = MODE_CLIENT;
|
|
/* Send mode. Do we send to a fixed address or to the last one we got. */
|
|
int sendMode = MODE_CLIENT;
|
|
/* This describes what our 3PCC behavior is. */
|
|
int thirdPartyMode = MODE_3PCC_NONE;
|
|
|
|
/*************** Helper functions for various types *****************/
|
|
long get_long(const char *ptr, const char *what) {
|
|
char *endptr;
|
|
long ret;
|
|
|
|
ret = strtol(ptr, &endptr, 0);
|
|
if (*endptr) {
|
|
ERROR("%s, \"%s\" is not a valid integer!\n", what, ptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
unsigned long long get_long_long(const char *ptr, const char *what) {
|
|
char *endptr;
|
|
unsigned long long ret;
|
|
|
|
ret = strtoull(ptr, &endptr, 0);
|
|
if (*endptr) {
|
|
ERROR("%s, \"%s\" is not a valid integer!\n", what, ptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* This function returns a time in milliseconds from a string.
|
|
* The multiplier is used to convert from the default input type into
|
|
* milliseconds. For example, for seconds you should use 1000 and for
|
|
* milliseconds use 1. */
|
|
long get_time(const char *ptr, const char *what, int multiplier) {
|
|
char *endptr;
|
|
const char *p;
|
|
long ret;
|
|
double dret;
|
|
int i;
|
|
|
|
if (!isdigit(*ptr)) {
|
|
ERROR("%s, \"%s\" is not a valid time!\n", what, ptr);
|
|
}
|
|
|
|
for (i = 0, p = ptr; *p; p++) {
|
|
if (*p == ':') {
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (i == 1) { /* mm:ss */
|
|
ERROR("%s, \"%s\" mm:ss not implemented yet!\n", what, ptr);
|
|
}
|
|
else if (i == 2) { /* hh:mm:ss */
|
|
ERROR("%s, \"%s\" hh:mm:ss not implemented yet!\n", what, ptr);
|
|
} else if (i != 0) {
|
|
ERROR("%s, \"%s\" is not a valid time!\n", what, ptr);
|
|
}
|
|
|
|
dret = strtod(ptr, &endptr);
|
|
if (*endptr) {
|
|
if (!strcmp(endptr, "s")) { /* Seconds */
|
|
ret = (long)(dret * 1000);
|
|
} else if (!strcmp(endptr, "ms")) { /* Milliseconds. */
|
|
ret = (long)dret;
|
|
} else if (!strcmp(endptr, "m")) { /* Minutes. */
|
|
ret = (long)(dret * 60000);
|
|
} else if (!strcmp(endptr, "h")) { /* Hours. */
|
|
ret = (long)(dret * 60 * 60 * 1000);
|
|
} else {
|
|
ERROR("%s, \"%s\" is not a valid time!\n", what, ptr);
|
|
}
|
|
} else {
|
|
ret = (long)(dret * multiplier);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
double get_double(const char *ptr, const char *what) {
|
|
char *endptr;
|
|
double ret;
|
|
|
|
ret = strtod(ptr, &endptr);
|
|
if (*endptr) {
|
|
ERROR("%s, \"%s\" is not a floating point number!\n", what, ptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
char * xp_get_string(const char *name, const char *what) {
|
|
char *ptr;
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
ERROR("%s is missing the required '%s' parameter.", what, name);
|
|
}
|
|
|
|
return strdup(ptr);
|
|
}
|
|
|
|
double xp_get_double(const char *name, const char *what) {
|
|
char *ptr;
|
|
char *helptext;
|
|
double val;
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
ERROR("%s is missing the required '%s' parameter.", what, name);
|
|
}
|
|
helptext = (char *)malloc(100 + strlen(name) + strlen(what));
|
|
sprintf(helptext, "%s '%s' parameter", what, name);
|
|
val = get_double(ptr, helptext);
|
|
free(helptext);
|
|
|
|
return val;
|
|
}
|
|
|
|
double xp_get_double(const char *name, const char *what, double defval) {
|
|
if (!(xp_get_value(name))) {
|
|
return defval;
|
|
}
|
|
return xp_get_double(name, what);
|
|
}
|
|
|
|
long xp_get_long(const char *name, const char *what) {
|
|
char *ptr;
|
|
char *helptext;
|
|
long val;
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
ERROR("%s is missing the required '%s' parameter.", what, name);
|
|
}
|
|
helptext = (char *)malloc(100 + strlen(name) + strlen(what));
|
|
sprintf(helptext, "%s '%s' parameter", what, name);
|
|
val = get_long(ptr, helptext);
|
|
free(helptext);
|
|
|
|
return val;
|
|
}
|
|
|
|
long xp_get_long(const char *name, const char *what, long defval) {
|
|
if (!(xp_get_value(name))) {
|
|
return defval;
|
|
}
|
|
return xp_get_long(name, what);
|
|
}
|
|
|
|
|
|
double xp_get_bool(const char *name, const char *what) {
|
|
char *ptr;
|
|
char *helptext;
|
|
bool val;
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
ERROR("%s is missing the required '%s' parameter.", what, name);
|
|
}
|
|
helptext = (char *)malloc(100 + strlen(name) + strlen(what));
|
|
sprintf(helptext, "%s '%s' parameter", what, name);
|
|
val = get_bool(ptr, helptext);
|
|
free(helptext);
|
|
|
|
return val;
|
|
}
|
|
|
|
double xp_get_bool(const char *name, const char *what, bool defval) {
|
|
if (!(xp_get_value(name))) {
|
|
return defval;
|
|
}
|
|
return xp_get_bool(name, what);
|
|
}
|
|
|
|
int scenario::get_txn(const char *txnName, const char *what, bool start, bool isInvite, bool isAck) {
|
|
/* Check the name's validity. */
|
|
if (txnName[0] == '\0') {
|
|
ERROR("Variable names may not be empty for %s\n", what);
|
|
}
|
|
if (strcspn(txnName, "$,") != strlen(txnName)) {
|
|
ERROR("Variable names may not contain $ or , for %s\n", what);
|
|
}
|
|
|
|
/* If this transaction has already been used, then we have nothing to do. */
|
|
str_int_map::iterator txn_it = txnMap.find(txnName);
|
|
if (txn_it != txnMap.end()) {
|
|
if (start) {
|
|
/* We need to fill in the invite field. */
|
|
transactions[txn_it->second - 1].started++;
|
|
} else if (isAck) {
|
|
transactions[txn_it->second - 1].acks++;
|
|
} else {
|
|
transactions[txn_it->second - 1].responses++;
|
|
}
|
|
return txn_it->second;
|
|
}
|
|
|
|
/* Assign this variable the next slot. */
|
|
struct txnControlInfo transaction;
|
|
|
|
transaction.name = strdup(txnName);
|
|
if (start) {
|
|
transaction.started = 1;
|
|
transaction.responses = 0;
|
|
transaction.acks = 0;
|
|
transaction.isInvite = isInvite;
|
|
} else if (isAck) {
|
|
/* Does not start or respond to this txn. */
|
|
transaction.started = 0;
|
|
transaction.responses = 0;
|
|
transaction.acks = 1;
|
|
transaction.isInvite = false;
|
|
} else {
|
|
transaction.started = 0;
|
|
transaction.responses = 1;
|
|
transaction.acks = 0;
|
|
transaction.isInvite = false;
|
|
}
|
|
|
|
transactions.push_back(transaction);
|
|
int txnNum = transactions.size();
|
|
txnMap[txnName] = txnNum;
|
|
|
|
return txnNum;
|
|
}
|
|
|
|
int scenario::find_var(const char *varName, const char *what) {
|
|
return allocVars->find(varName, false);
|
|
}
|
|
|
|
int scenario::get_var(const char *varName, const char *what) {
|
|
/* Check the name's validity. */
|
|
if (varName[0] == '\0') {
|
|
ERROR("Transaction names may not be empty for %s\n", what);
|
|
}
|
|
if (strcspn(varName, "$,") != strlen(varName)) {
|
|
ERROR("Transaction names may not contain $ or , for %s\n", what);
|
|
}
|
|
|
|
return allocVars->find(varName, true);
|
|
}
|
|
|
|
int scenario::xp_get_var(const char *name, const char *what) {
|
|
char *ptr;
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
ERROR("%s is missing the required '%s' variable parameter.", what, name);
|
|
}
|
|
|
|
return get_var(ptr, what);
|
|
}
|
|
|
|
int xp_get_optional(const char *name, const char *what) {
|
|
char *ptr = xp_get_value(name);
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
return OPTIONAL_FALSE;
|
|
}
|
|
|
|
if(!strcmp(ptr, "true")) {
|
|
return OPTIONAL_TRUE;
|
|
} else if(!strcmp(ptr, "global")) {
|
|
return OPTIONAL_GLOBAL;
|
|
} else if(!strcmp(ptr, "false")) {
|
|
return OPTIONAL_FALSE;
|
|
} else {
|
|
ERROR("Could not understand optional value for %s: %s", what, ptr);
|
|
}
|
|
|
|
return OPTIONAL_FALSE;
|
|
}
|
|
|
|
|
|
int scenario::xp_get_var(const char *name, const char *what, int defval) {
|
|
char *ptr;
|
|
|
|
if (!(ptr = xp_get_value(name))) {
|
|
return defval;
|
|
}
|
|
|
|
return xp_get_var(name, what);
|
|
}
|
|
|
|
bool get_bool(const char *ptr, const char *what) {
|
|
char *endptr;
|
|
long ret;
|
|
|
|
if (!strcmp(ptr, "true")) {
|
|
return true;
|
|
}
|
|
if (!strcmp(ptr, "false")) {
|
|
return false;
|
|
}
|
|
|
|
ret = strtol(ptr, &endptr, 0);
|
|
if (*endptr) {
|
|
ERROR("%s, \"%s\" is not a valid boolean!\n", what, ptr);
|
|
}
|
|
return ret ? true : false;
|
|
}
|
|
|
|
/* Pretty print a time. */
|
|
char *time_string(int ms) {
|
|
static char tmp[20];
|
|
|
|
if (ms < 10000) {
|
|
snprintf(tmp, sizeof(tmp), "%dms", ms);
|
|
} else if (ms < 100000) {
|
|
snprintf(tmp, sizeof(tmp), "%.1fs", ((float)ms)/1000);
|
|
} else {
|
|
snprintf(tmp, sizeof(tmp), "%ds", ms/1000);
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
int time_string(double ms, char *res, int reslen) {
|
|
if (ms < 10000) {
|
|
/* Less then 10 seconds we represent accurately. */
|
|
if ((int)(ms + 0.9999) == (int)(ms)) {
|
|
/* We have an integer, or close enough to it. */
|
|
return snprintf(res, reslen, "%dms", (int)ms);
|
|
} else {
|
|
if (ms < 1000) {
|
|
return snprintf(res, reslen, "%.2lfms", ms);
|
|
} else {
|
|
return snprintf(res, reslen, "%.1lfms", ms);
|
|
}
|
|
}
|
|
} else if (ms < 60000) {
|
|
/* We round to 100ms for times less than a minute. */
|
|
return snprintf(res, reslen, "%.1fs", ms/1000);
|
|
} else if (ms < 60 * 60000) {
|
|
/* We round to 1s for times more than a minute. */
|
|
int s = (unsigned int)(ms / 1000);
|
|
int m = s / 60;
|
|
s %= 60;
|
|
return snprintf(res, reslen, "%d:%02d", m, s);
|
|
} else {
|
|
int s = (unsigned int)(ms / 1000);
|
|
int m = s / 60;
|
|
int h = m / 60;
|
|
s %= 60;
|
|
m %= 60;
|
|
return snprintf(res, reslen, "%d:%02d:%02d", h, m, s);
|
|
}
|
|
}
|
|
|
|
char *double_time_string(double ms) {
|
|
static char tmp[20];
|
|
|
|
if (ms < 1000) {
|
|
snprintf(tmp, sizeof(tmp), "%.2lfms", ms);
|
|
} else if (ms < 10000) {
|
|
snprintf(tmp, sizeof(tmp), "%.1lfms", ms);
|
|
} else if (ms < 100000) {
|
|
snprintf(tmp, sizeof(tmp), "%.1lfs", ms / 1000);
|
|
} else {
|
|
snprintf(tmp, sizeof(tmp), "%ds", (int)(ms/1000));
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
/* For backwards compatibility, we assign "true" to slot 1, false to 0, and
|
|
* allow other valid integers. */
|
|
int scenario::get_rtd(const char *ptr, bool start) {
|
|
if(!strcmp(ptr, (char *)"false"))
|
|
return 0;
|
|
|
|
if(!strcmp(ptr, (char *)"true"))
|
|
return stats->findRtd("1", start);
|
|
|
|
return stats->findRtd(ptr, start);
|
|
}
|
|
|
|
/* Get a counter */
|
|
int scenario::get_counter(const char *ptr, const char *what) {
|
|
/* Check the name's validity. */
|
|
if (ptr[0] == '\0') {
|
|
ERROR("Counter names names may not be empty for %s\n", what);
|
|
}
|
|
if (strcspn(ptr, "$,") != strlen(ptr)) {
|
|
ERROR("Counter names may not contain $ or , for %s\n", what);
|
|
}
|
|
|
|
return stats->findCounter(ptr, true);
|
|
}
|
|
|
|
|
|
/* Some validation functions. */
|
|
|
|
void scenario::validate_variable_usage() {
|
|
allocVars->validate();
|
|
}
|
|
|
|
void scenario::validate_txn_usage() {
|
|
for (unsigned int i = 0; i < transactions.size(); i++) {
|
|
if(transactions[i].started == 0) {
|
|
ERROR("Transaction %s is never started!\n", transactions[i].name);
|
|
} else if(transactions[i].responses == 0) {
|
|
ERROR("Transaction %s has no responses defined!\n", transactions[i].name);
|
|
}
|
|
if (transactions[i].isInvite && transactions[i].acks == 0) {
|
|
ERROR("Transaction %s is an INVITE transaction without an ACK!\n", transactions[i].name);
|
|
}
|
|
if (!transactions[i].isInvite && (transactions[i].acks > 0)) {
|
|
ERROR("Transaction %s is a non-INVITE transaction with an ACK!\n", transactions[i].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Apply the next and ontimeout labels according to our map. */
|
|
void scenario::apply_labels(msgvec v, str_int_map labels) {
|
|
for (unsigned int i = 0; i < v.size(); i++) {
|
|
if (v[i]->nextLabel) {
|
|
str_int_map::iterator label_it = labels.find(v[i]->nextLabel);
|
|
if (label_it == labels.end()) {
|
|
ERROR("The label '%s' was not defined (index %d, next attribute)\n", v[i]->nextLabel, i);
|
|
}
|
|
v[i]->next = label_it->second;
|
|
}
|
|
if (v[i]->onTimeoutLabel) {
|
|
str_int_map::iterator label_it = labels.find(v[i]->onTimeoutLabel);
|
|
if (label_it == labels.end()) {
|
|
ERROR("The label '%s' was not defined (index %d, ontimeout attribute)\n", v[i]->onTimeoutLabel, i);
|
|
}
|
|
v[i]->on_timeout = label_it->second;
|
|
}
|
|
}
|
|
}
|
|
|
|
int get_cr_number(char *src)
|
|
{
|
|
int res=0;
|
|
char *ptr = src;
|
|
while(*ptr) {
|
|
if(*ptr == '\n') res++;
|
|
*ptr++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
char *clean_cdata(char *ptr, int *removed_crlf = NULL) {
|
|
char * msg;
|
|
|
|
while((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\n')) ptr++;
|
|
|
|
msg = (char *) malloc(strlen(ptr) + 3);
|
|
if(!msg) { ERROR("Memory Overflow"); }
|
|
strcpy(msg, ptr);
|
|
|
|
ptr = msg + strlen(msg);
|
|
ptr --;
|
|
|
|
while((ptr >= msg) &&
|
|
((*ptr == ' ') ||
|
|
(*ptr == '\t') ||
|
|
(*ptr == '\n'))) {
|
|
if(*ptr == '\n' && removed_crlf) {
|
|
(*removed_crlf)++;
|
|
}
|
|
*ptr-- = 0;
|
|
}
|
|
|
|
if(!strstr(msg, "\n\n")) {
|
|
strcat(msg, "\n\n");
|
|
}
|
|
|
|
if(ptr == msg) {
|
|
ERROR("Empty cdata in xml scenario file");
|
|
}
|
|
while ((ptr = strstr(msg, "\n "))) {
|
|
memmove(ptr + 1, ptr + 2, strlen(ptr) - 1);
|
|
}
|
|
while ((ptr = strstr(msg, " \n"))) {
|
|
memmove(ptr, ptr + 1, strlen(ptr));
|
|
}
|
|
while ((ptr = strstr(msg, "\n\t"))) {
|
|
memmove(ptr + 1, ptr + 2, strlen(ptr) - 1);
|
|
}
|
|
while ((ptr = strstr(msg, "\t\n"))) {
|
|
memmove(ptr, ptr + 1, strlen(ptr));
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
|
|
/********************** Scenario File analyser **********************/
|
|
|
|
void scenario::checkOptionalRecv(char *elem, unsigned int scenario_file_cursor) {
|
|
if (last_recv_optional) {
|
|
ERROR("<recv> before <%s> sequence without a mandatory message. Please remove one 'optional=true' (element %d).", elem, scenario_file_cursor);
|
|
}
|
|
last_recv_optional = false;
|
|
}
|
|
|
|
scenario::scenario(char * filename, int deflt)
|
|
{
|
|
char * elem;
|
|
char *method_list = NULL;
|
|
unsigned int scenario_file_cursor = 0;
|
|
int L_content_length = 0 ;
|
|
char * peer;
|
|
|
|
last_recv_optional = false;
|
|
|
|
if(filename) {
|
|
if(!xp_set_xml_buffer_from_file(filename)) {
|
|
ERROR("Unable to load or parse '%s' xml scenario file", filename);
|
|
}
|
|
} else {
|
|
if(!xp_set_xml_buffer_from_string(default_scenario[deflt])) {
|
|
ERROR("Unable to load default xml scenario file");
|
|
}
|
|
}
|
|
|
|
stats = new CStat();
|
|
allocVars = new AllocVariableTable(userVariables);
|
|
|
|
hidedefault = false;
|
|
|
|
elem = xp_open_element(0);
|
|
if (!elem) {
|
|
ERROR("No element in xml scenario file");
|
|
}
|
|
if(strcmp("scenario", elem)) {
|
|
ERROR("No 'scenario' section in xml scenario file");
|
|
}
|
|
|
|
if(char *ptr = xp_get_value((char *)"name")) {
|
|
name = strdup(ptr);
|
|
} else {
|
|
name = strdup("");
|
|
}
|
|
|
|
duration = 0;
|
|
found_timewait = false;
|
|
|
|
scenario_file_cursor = 0;
|
|
|
|
while ((elem = xp_open_element(scenario_file_cursor))) {
|
|
char * ptr;
|
|
scenario_file_cursor ++;
|
|
|
|
if(!strcmp(elem, "CallLengthRepartition")) {
|
|
ptr = xp_get_string("value", "CallLengthRepartition");
|
|
stats->setRepartitionCallLength(ptr);
|
|
free(ptr);
|
|
} else if(!strcmp(elem, "ResponseTimeRepartition")) {
|
|
ptr = xp_get_string("value", "ResponseTimeRepartition");
|
|
stats->setRepartitionResponseTime(ptr);
|
|
free(ptr);
|
|
} else if(!strcmp(elem, "Global")) {
|
|
ptr = xp_get_string("variables", "Global");
|
|
|
|
char ** currentTabVarName = NULL;
|
|
int currentNbVarNames;
|
|
|
|
createStringTable(ptr, ¤tTabVarName, ¤tNbVarNames);
|
|
for (int i = 0; i < currentNbVarNames; i++) {
|
|
globalVariables->find(currentTabVarName[i], true);
|
|
}
|
|
freeStringTable(currentTabVarName, currentNbVarNames);
|
|
free(ptr);
|
|
} else if(!strcmp(elem, "User")) {
|
|
ptr = xp_get_string("variables", "User");
|
|
|
|
char ** currentTabVarName = NULL;
|
|
int currentNbVarNames;
|
|
|
|
createStringTable(ptr, ¤tTabVarName, ¤tNbVarNames);
|
|
for (int i = 0; i < currentNbVarNames; i++) {
|
|
userVariables->find(currentTabVarName[i], true);
|
|
}
|
|
freeStringTable(currentTabVarName, currentNbVarNames);
|
|
free(ptr);
|
|
} else if(!strcmp(elem, "Reference")) {
|
|
ptr = xp_get_string("variables", "Reference");
|
|
|
|
char ** currentTabVarName = NULL;
|
|
int currentNbVarNames;
|
|
|
|
createStringTable(ptr, ¤tTabVarName, ¤tNbVarNames);
|
|
for (int i = 0; i < currentNbVarNames; i++) {
|
|
int id = allocVars->find(currentTabVarName[i], false);
|
|
if (id == -1) {
|
|
ERROR("Could not reference non-existant variable '%s'", currentTabVarName[i]);
|
|
}
|
|
}
|
|
freeStringTable(currentTabVarName, currentNbVarNames);
|
|
free(ptr);
|
|
} else if(!strcmp(elem, "DefaultMessage")) {
|
|
char *id = xp_get_string("id", "DefaultMessage");
|
|
if(!(ptr = xp_get_cdata())) {
|
|
ERROR("No CDATA in 'send' section of xml scenario file");
|
|
}
|
|
char *msg = clean_cdata(ptr);
|
|
set_default_message(id, msg);
|
|
free(id);
|
|
/* XXX: This should really be per scenario. */
|
|
} else if(!strcmp(elem, "label")) {
|
|
ptr = xp_get_string("id", "label");
|
|
if (labelMap.find(ptr) != labelMap.end()) {
|
|
ERROR("The label name '%s' is used twice.", ptr);
|
|
}
|
|
labelMap[ptr] = messages.size();
|
|
free(ptr);
|
|
} else if (!strcmp(elem, "init")) {
|
|
/* We have an init section, which must be full of nops or labels. */
|
|
int nop_cursor = 0;
|
|
char *initelem;
|
|
while ((initelem = xp_open_element(nop_cursor++))) {
|
|
if (!strcmp(initelem, "nop")) {
|
|
/* We should parse this. */
|
|
message *nopmsg = new message(initmessages.size(), "scenario initialization");
|
|
initmessages.push_back(nopmsg);
|
|
nopmsg->M_type = MSG_TYPE_NOP;
|
|
getCommonAttributes(nopmsg);
|
|
} else if (!strcmp(initelem, "label")) {
|
|
/* Add an init label. */
|
|
ptr = xp_get_value((char *)"id");
|
|
if (initLabelMap.find(ptr) != initLabelMap.end()) {
|
|
ERROR("The label name '%s' is used twice.", ptr);
|
|
}
|
|
initLabelMap[ptr] = initmessages.size();
|
|
} else {
|
|
ERROR("Invalid element in an init stanza: '%s'", initelem);
|
|
}
|
|
xp_close_element();
|
|
}
|
|
} else { /** Message Case */
|
|
if (found_timewait) {
|
|
ERROR("<timewait> can only be the last message in a scenario!\n");
|
|
}
|
|
message *curmsg = new message(messages.size(), name ? name : "unknown scenario");
|
|
messages.push_back(curmsg);
|
|
|
|
if(!strcmp(elem, "send")) {
|
|
checkOptionalRecv(elem, scenario_file_cursor);
|
|
curmsg->M_type = MSG_TYPE_SEND;
|
|
/* Sent messages descriptions */
|
|
if(!(ptr = xp_get_cdata())) {
|
|
ERROR("No CDATA in 'send' section of xml scenario file");
|
|
}
|
|
|
|
int removed_clrf = 0;
|
|
char * msg = clean_cdata(ptr, &removed_clrf);
|
|
|
|
L_content_length = xp_get_content_length(msg);
|
|
switch (L_content_length) {
|
|
case -1 :
|
|
// the msg does not contain content-length field
|
|
break ;
|
|
case 0 :
|
|
curmsg -> content_length_flag =
|
|
message::ContentLengthValueZero; // Initialize to No present
|
|
break ;
|
|
default :
|
|
curmsg -> content_length_flag =
|
|
message::ContentLengthValueNoZero; // Initialize to No present
|
|
break ;
|
|
}
|
|
|
|
if((msg[strlen(msg) - 1] != '\n') && (removed_clrf)) {
|
|
strcat(msg, "\n");
|
|
}
|
|
char *tsrc = msg;
|
|
while(*tsrc++);
|
|
curmsg -> send_scheme = new SendingMessage(this, msg);
|
|
free(msg);
|
|
|
|
// If this is a request we are sending, then store our transaction/method matching information.
|
|
if (!curmsg->send_scheme->isResponse()) {
|
|
char *method = curmsg->send_scheme->getMethod();
|
|
bool isInvite = !strcmp(method, "INVITE");
|
|
bool isAck = !strcmp(method, "ACK");
|
|
|
|
if ((ptr = xp_get_value("start_txn"))) {
|
|
if (isAck) {
|
|
ERROR("An ACK message can not start a transaction!");
|
|
}
|
|
curmsg->start_txn = get_txn(ptr, "start transaction", true, isInvite, false);
|
|
} else if ((ptr = xp_get_value("ack_txn"))) {
|
|
if (!isAck) {
|
|
ERROR("The ack_txn attribute is valid only for ACK messages!");
|
|
}
|
|
curmsg->ack_txn = get_txn(ptr, "ack transaction", false, false, true);
|
|
} else {
|
|
int len = method_list ? strlen(method_list) : 0;
|
|
method_list = (char *)realloc(method_list, len + strlen(method) + 1);
|
|
if (!method_list) {
|
|
ERROR_NO("Out of memory allocating method_list!");
|
|
}
|
|
strcpy(method_list + len, method);
|
|
}
|
|
} else {
|
|
if ((ptr = xp_get_value("start_txn"))) {
|
|
ERROR("Responses can not start a transaction");
|
|
}
|
|
if ((ptr = xp_get_value("ack_txn"))) {
|
|
ERROR("Responses can not ACK a transaction");
|
|
}
|
|
}
|
|
|
|
if ((ptr = xp_get_value("response_txn"))) {
|
|
ERROR("response_txn can only be used for received messages.");
|
|
}
|
|
|
|
curmsg -> retrans_delay = xp_get_long("retrans", "retransmission timer", 0);
|
|
curmsg -> timeout = xp_get_long("timeout", "message send timeout", 0);
|
|
} else if(!strcmp(elem, (char *)"recv")) {
|
|
curmsg->M_type = MSG_TYPE_RECV;
|
|
/* Received messages descriptions */
|
|
if((ptr = xp_get_value((char *)"response"))) {
|
|
curmsg ->recv_response = get_long(ptr, "response code");
|
|
if (method_list) {
|
|
curmsg->recv_response_for_cseq_method_list = strdup(method_list);
|
|
}
|
|
if ((ptr = xp_get_value("response_txn"))) {
|
|
curmsg->response_txn = get_txn(ptr, "transaction response", false, false, false);
|
|
}
|
|
}
|
|
|
|
if((ptr = xp_get_value((char *)"request"))) {
|
|
curmsg -> recv_request = strdup(ptr);
|
|
if ((ptr = xp_get_value("response_txn"))) {
|
|
ERROR("response_txn can only be used for received responses.");
|
|
}
|
|
}
|
|
|
|
curmsg->optional = xp_get_optional("optional", "recv");
|
|
last_recv_optional = curmsg->optional;
|
|
curmsg->advance_state = xp_get_bool("advance_state", "recv", true);
|
|
if (!curmsg->advance_state && curmsg->optional == OPTIONAL_FALSE) {
|
|
ERROR("advance_state is allowed only for optional messages (index = %d)\n", messages.size() - 1);
|
|
}
|
|
|
|
if (0 != (ptr = xp_get_value((char *)"regexp_match"))) {
|
|
if(!strcmp(ptr, "true")) {
|
|
curmsg -> regexp_match = 1;
|
|
}
|
|
}
|
|
|
|
curmsg->timeout = xp_get_long("timeout", "message timeout", 0);
|
|
|
|
/* record the route set */
|
|
/* TODO disallow optional and rrs to coexist? */
|
|
if((ptr = xp_get_value((char *)"rrs"))) {
|
|
curmsg -> bShouldRecordRoutes = get_bool(ptr, "record route set");
|
|
}
|
|
|
|
/* record the authentication credentials */
|
|
if((ptr = xp_get_value((char *)"auth"))) {
|
|
bool temp = get_bool(ptr, "message authentication");
|
|
curmsg -> bShouldAuthenticate = temp;
|
|
}
|
|
} else if(!strcmp(elem, "pause") || !strcmp(elem, "timewait")) {
|
|
checkOptionalRecv(elem, scenario_file_cursor);
|
|
curmsg->M_type = MSG_TYPE_PAUSE;
|
|
if (!strcmp(elem, "timewait")) {
|
|
curmsg->timewait = true;
|
|
found_timewait = true;
|
|
}
|
|
|
|
int var;
|
|
if ((var = xp_get_var("variable", "pause", -1)) != -1) {
|
|
curmsg->pause_variable = var;
|
|
} else {
|
|
CSample *distribution = parse_distribution(true);
|
|
|
|
bool sanity_check = xp_get_bool("sanity_check", "pause", true);
|
|
|
|
double pause_duration = distribution->cdfInv(0.99);
|
|
if (sanity_check && (pause_duration > INT_MAX)) {
|
|
char percentile[100];
|
|
char desc[100];
|
|
|
|
distribution->timeDescr(desc, sizeof(desc));
|
|
time_string(pause_duration, percentile, sizeof(percentile));
|
|
|
|
ERROR("The distribution %s has a 99th percentile of %s, which is larger than INT_MAX. You should chose different parameters.", desc, percentile);
|
|
}
|
|
|
|
curmsg->pause_distribution = distribution;
|
|
/* Update scenario duration with max duration */
|
|
duration += (int)pause_duration;
|
|
}
|
|
}
|
|
else if(!strcmp(elem, "nop")) {
|
|
checkOptionalRecv(elem, scenario_file_cursor);
|
|
/* Does nothing at SIP level. This message type can be used to handle
|
|
* actions, increment counters, or for RTDs. */
|
|
curmsg->M_type = MSG_TYPE_NOP;
|
|
}
|
|
else if(!strcmp(elem, "recvCmd")) {
|
|
curmsg->M_type = MSG_TYPE_RECVCMD;
|
|
curmsg->optional = xp_get_optional("optional", "recv");
|
|
last_recv_optional = curmsg->optional;
|
|
|
|
/* 3pcc extended mode */
|
|
if((ptr = xp_get_value((char *)"src"))) {
|
|
curmsg ->peer_src = strdup(ptr);
|
|
} else if (extendedTwinSippMode) {
|
|
ERROR("You must specify a 'src' for recvCmd when using extended 3pcc mode!");
|
|
}
|
|
} else if(!strcmp(elem, "sendCmd")) {
|
|
checkOptionalRecv(elem, scenario_file_cursor);
|
|
curmsg->M_type = MSG_TYPE_SENDCMD;
|
|
/* Sent messages descriptions */
|
|
|
|
/* 3pcc extended mode */
|
|
if((ptr = xp_get_value((char *)"dest"))) {
|
|
peer = strdup(ptr) ;
|
|
curmsg ->peer_dest = peer ;
|
|
peer_map::iterator peer_it;
|
|
peer_it = peers.find(peer_map::key_type(peer));
|
|
if(peer_it == peers.end()) /* the peer (slave or master)
|
|
has not been added in the map
|
|
(first occurence in the scenario) */
|
|
{
|
|
T_peer_infos infos;
|
|
infos.peer_socket = 0;
|
|
strcpy(infos.peer_host, get_peer_addr(peer));
|
|
peers[std::string(peer)] = infos;
|
|
}
|
|
} else if (extendedTwinSippMode) {
|
|
ERROR("You must specify a 'dest' for sendCmd with extended 3pcc mode!");
|
|
}
|
|
|
|
if(!(ptr = xp_get_cdata())) {
|
|
ERROR("No CDATA in 'sendCmd' section of xml scenario file");
|
|
}
|
|
char *msg = clean_cdata(ptr);
|
|
|
|
curmsg -> M_sendCmdData = new SendingMessage(this, msg, true /* skip sanity */);
|
|
free(msg);
|
|
}
|
|
else {
|
|
ERROR("Unknown element '%s' in xml scenario file", elem);
|
|
}
|
|
|
|
getCommonAttributes(curmsg);
|
|
} /** end * Message case */
|
|
xp_close_element();
|
|
} // end while
|
|
|
|
free(method_list);
|
|
|
|
str_int_map::iterator label_it = labelMap.find("_unexp.main");
|
|
if (label_it != labelMap.end()) {
|
|
unexpected_jump = label_it->second;
|
|
} else {
|
|
unexpected_jump = -1;
|
|
}
|
|
retaddr = find_var("_unexp.retaddr", "unexpected return address");
|
|
pausedaddr = find_var("_unexp.pausedaddr", "unexpected paused until");
|
|
|
|
/* Patch up the labels. */
|
|
apply_labels(messages, labelMap);
|
|
apply_labels(initmessages, initLabelMap);
|
|
|
|
/* Some post-scenario loading validation. */
|
|
stats->validateRtds();
|
|
|
|
/* Make sure that all variables are used more than once. */
|
|
validate_variable_usage();
|
|
|
|
/* Make sure that all started transactions have responses, and vice versa. */
|
|
validate_txn_usage();
|
|
|
|
if (messages.size() == 0) {
|
|
ERROR("Did not find any messages inside of scenario!");
|
|
}
|
|
}
|
|
|
|
void scenario::runInit() {
|
|
call *initcall;
|
|
if (initmessages.size() > 0) {
|
|
initcall = new call(main_scenario, NULL, NULL, "///main-init", 0, false, false, true);
|
|
initcall->run();
|
|
}
|
|
}
|
|
|
|
void clear_int_str(int_str_map m) {
|
|
for(int_str_map::iterator it = m.begin(); it != m.end(); it = m.begin()) {
|
|
free(it->second);
|
|
m.erase(it);
|
|
}
|
|
}
|
|
|
|
void clear_str_int(str_int_map m) {
|
|
for(str_int_map::iterator it = m.begin(); it != m.end(); it = m.begin()) {
|
|
m.erase(it);
|
|
}
|
|
}
|
|
|
|
void clear_int_int(int_int_map m) {
|
|
for(int_int_map::iterator it = m.begin(); it != m.end(); it = m.begin()) {
|
|
m.erase(it);
|
|
}
|
|
}
|
|
|
|
scenario::~scenario() {
|
|
for (msgvec::iterator i = messages.begin(); i != messages.end(); i++) {
|
|
delete *i;
|
|
}
|
|
messages.clear();
|
|
|
|
free(name);
|
|
|
|
allocVars->putTable();
|
|
delete stats;
|
|
|
|
for (unsigned int i = 0; i < transactions.size(); i++) {
|
|
free(transactions[i].name);
|
|
}
|
|
transactions.clear();
|
|
|
|
clear_str_int(labelMap);
|
|
clear_str_int(initLabelMap);
|
|
clear_str_int(txnMap);
|
|
}
|
|
|
|
CSample *parse_distribution(bool oldstyle = false) {
|
|
CSample *distribution;
|
|
char *distname;
|
|
char *ptr;
|
|
|
|
if(!(distname = xp_get_value("distribution"))) {
|
|
if (!oldstyle) {
|
|
ERROR("statistically distributed actions or pauses requires 'distribution' parameter");
|
|
}
|
|
if ((ptr = xp_get_value("normal"))) {
|
|
distname = "normal";
|
|
} else if ((ptr = xp_get_value("exponential"))) {
|
|
distname = "exponential";
|
|
} else if ((ptr = xp_get_value("lognormal"))) {
|
|
distname = "lognormal";
|
|
} else if ((ptr = xp_get_value("weibull"))) {
|
|
distname = "weibull";
|
|
} else if ((ptr = xp_get_value("pareto"))) {
|
|
distname = "pareto";
|
|
} else if ((ptr = xp_get_value("gamma"))) {
|
|
distname = "gamma";
|
|
} else if ((ptr = xp_get_value("min"))) {
|
|
distname = "uniform";
|
|
} else if ((ptr = xp_get_value("max"))) {
|
|
distname = "uniform";
|
|
} else if ((ptr = xp_get_value("milliseconds"))) {
|
|
double val = get_double(ptr, "Pause milliseconds");
|
|
return new CFixed(val);
|
|
} else {
|
|
return new CDefaultPause();
|
|
}
|
|
}
|
|
|
|
if (!strcmp(distname, "fixed")) {
|
|
double value = xp_get_double("value", "Fixed distribution");
|
|
distribution = new CFixed(value);
|
|
} else if (!strcmp(distname, "uniform")) {
|
|
double min = xp_get_double("min", "Uniform distribution");
|
|
double max = xp_get_double("max", "Uniform distribution");
|
|
distribution = new CUniform(min, max);
|
|
#ifdef HAVE_GSL
|
|
} else if (!strcmp(distname, "normal")) {
|
|
double mean = xp_get_double("mean", "Normal distribution");
|
|
double stdev = xp_get_double("stdev", "Normal distribution");
|
|
distribution = new CNormal(mean, stdev);
|
|
} else if (!strcmp(distname, "lognormal")) {
|
|
double mean = xp_get_double("mean", "Lognormal distribution");
|
|
double stdev = xp_get_double("stdev", "Lognormal distribution");
|
|
distribution = new CLogNormal(mean, stdev);
|
|
} else if (!strcmp(distname, "exponential")) {
|
|
double mean = xp_get_double("mean", "Exponential distribution");
|
|
distribution = new CExponential(mean);
|
|
} else if (!strcmp(distname, "weibull")) {
|
|
double lambda = xp_get_double("lambda", "Weibull distribution");
|
|
double k = xp_get_double("k", "Weibull distribution");
|
|
distribution = new CWeibull(lambda, k);
|
|
} else if (!strcmp(distname, "pareto")) {
|
|
double k = xp_get_double("k", "Pareto distribution");
|
|
double xsubm = xp_get_double("x_m", "Pareto distribution");
|
|
distribution = new CPareto(k, xsubm);
|
|
} else if (!strcmp(distname, "gpareto")) {
|
|
double shape = xp_get_double("shape", "Generalized Pareto distribution");
|
|
double scale = xp_get_double("scale", "Generalized Pareto distribution");
|
|
double location = xp_get_double("location", "Generalized Pareto distribution");
|
|
distribution = new CGPareto(shape, scale, location);
|
|
} else if (!strcmp(distname, "gamma")) {
|
|
double k = xp_get_double("k", "Gamma distribution");
|
|
double theta = xp_get_double("theta", "Gamma distribution");
|
|
distribution = new CGamma(k, theta);
|
|
} else if (!strcmp(distname, "negbin")) {
|
|
double n = xp_get_double("n", "Negative Binomial distribution");
|
|
double p = xp_get_double("p", "Negative Binomial distribution");
|
|
distribution = new CNegBin(n, p);
|
|
#else
|
|
} else if (!strcmp(distname, "normal")
|
|
|| !strcmp(distname, "lognormal")
|
|
|| !strcmp(distname, "exponential")
|
|
|| !strcmp(distname, "pareto")
|
|
|| !strcmp(distname, "gamma")
|
|
|| !strcmp(distname, "negbin")
|
|
|| !strcmp(distname, "weibull")) {
|
|
ERROR("The distribution '%s' is only available with GSL.", distname);
|
|
#endif
|
|
} else {
|
|
ERROR("Unknown distribution: %s\n", ptr);
|
|
}
|
|
|
|
return distribution;
|
|
}
|
|
|
|
|
|
|
|
/* 3pcc extended mode:
|
|
get the correspondances between
|
|
slave and master names and their
|
|
addresses */
|
|
|
|
void parse_slave_cfg()
|
|
{
|
|
FILE * f;
|
|
char line[MAX_PEER_SIZE];
|
|
char * temp_peer;
|
|
char * temp_host;
|
|
char * peer_host;
|
|
|
|
f = fopen(slave_cfg_file, "r");
|
|
if(f){
|
|
while (fgets(line, MAX_PEER_SIZE, f) != NULL)
|
|
{
|
|
if((temp_peer = strtok(line, ";"))) {
|
|
if((peer_host = (char *) malloc(MAX_PEER_SIZE))){
|
|
if((temp_host = strtok(NULL, ";"))){
|
|
strcpy(peer_host, temp_host);
|
|
peer_addrs[std::string(temp_peer)] = peer_host;
|
|
}
|
|
}else {
|
|
ERROR("Cannot allocate memory!\n");
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
ERROR("Can not open slave_cfg file %s\n", slave_cfg_file);
|
|
}
|
|
|
|
}
|
|
|
|
// Determine in which mode the sipp tool has been
|
|
// launched (client, server, 3pcc client, 3pcc server, 3pcc extended master or slave)
|
|
void scenario::computeSippMode()
|
|
{
|
|
bool isRecvCmdFound = false;
|
|
bool isSendCmdFound = false;
|
|
|
|
creationMode = -1;
|
|
sendMode = -1;
|
|
thirdPartyMode = MODE_3PCC_NONE;
|
|
|
|
assert(messages.size() > 0);
|
|
|
|
for(unsigned int i=0; i<messages.size(); i++)
|
|
{
|
|
switch(messages[i]->M_type)
|
|
{
|
|
case MSG_TYPE_PAUSE:
|
|
case MSG_TYPE_NOP:
|
|
/* Allow pauses or nops to go first. */
|
|
continue;
|
|
case MSG_TYPE_SEND:
|
|
if (sendMode == -1) {
|
|
sendMode = MODE_CLIENT;
|
|
}
|
|
if (creationMode == -1) {
|
|
creationMode = MODE_CLIENT;
|
|
}
|
|
break;
|
|
|
|
case MSG_TYPE_RECV:
|
|
if (sendMode == -1) {
|
|
sendMode = MODE_SERVER;
|
|
}
|
|
if (creationMode == -1) {
|
|
creationMode = MODE_SERVER;
|
|
}
|
|
break;
|
|
case MSG_TYPE_SENDCMD:
|
|
isSendCmdFound = true;
|
|
if (creationMode == -1) {
|
|
creationMode = MODE_CLIENT;
|
|
}
|
|
if(!isRecvCmdFound) {
|
|
if (creationMode == MODE_SERVER) {
|
|
/*
|
|
* If it is a server already, then start it in
|
|
* 3PCC A passive mode
|
|
*/
|
|
if(twinSippMode){
|
|
thirdPartyMode = MODE_3PCC_A_PASSIVE;
|
|
}else if (extendedTwinSippMode){
|
|
thirdPartyMode = MODE_MASTER_PASSIVE;
|
|
}
|
|
} else {
|
|
if(twinSippMode){
|
|
thirdPartyMode = MODE_3PCC_CONTROLLER_A;
|
|
}else if (extendedTwinSippMode){
|
|
thirdPartyMode = MODE_MASTER;
|
|
}
|
|
}
|
|
if((thirdPartyMode == MODE_MASTER_PASSIVE || thirdPartyMode == MODE_MASTER) && !master_name){
|
|
ERROR("Inconsistency between command line and scenario: master scenario but -master option not set\n");
|
|
}
|
|
if(!twinSippMode && !extendedTwinSippMode)
|
|
ERROR("sendCmd message found in scenario but no twin sipp"
|
|
" address has been passed! Use -3pcc option or 3pcc extended mode.\n");
|
|
}
|
|
break;
|
|
|
|
case MSG_TYPE_RECVCMD:
|
|
if (creationMode == -1) {
|
|
creationMode = MODE_SERVER;
|
|
}
|
|
isRecvCmdFound = true;
|
|
if(!isSendCmdFound)
|
|
{
|
|
if(twinSippMode){
|
|
thirdPartyMode = MODE_3PCC_CONTROLLER_B;
|
|
} else if(extendedTwinSippMode){
|
|
thirdPartyMode = MODE_SLAVE;
|
|
if(!slave_number) {
|
|
ERROR("Inconsistency between command line and scenario: slave scenario but -slave option not set\n");
|
|
}else{
|
|
thirdPartyMode = MODE_SLAVE;
|
|
}
|
|
}
|
|
if(!twinSippMode && !extendedTwinSippMode)
|
|
ERROR("recvCmd message found in scenario but no "
|
|
"twin sipp address has been passed! Use "
|
|
"-3pcc option\n");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if(creationMode == -1)
|
|
ERROR("Unable to determine creation mode of the tool (server, client)\n");
|
|
if(sendMode == -1)
|
|
ERROR("Unable to determine send mode of the tool (server, client)\n");
|
|
}
|
|
|
|
void scenario::handle_rhs(CAction *tmpAction, char *what) {
|
|
if (xp_get_value("value")) {
|
|
tmpAction->setDoubleValue(xp_get_double("value", what));
|
|
if (xp_get_value("variable")) {
|
|
ERROR("Value and variable are mutually exclusive for %s action!", what);
|
|
}
|
|
} else if (xp_get_value("variable")) {
|
|
tmpAction->setVarInId(xp_get_var("variable", what));
|
|
if (xp_get_value("value")) {
|
|
ERROR("Value and variable are mutually exclusive for %s action!", what);
|
|
}
|
|
} else {
|
|
ERROR("No value or variable defined for %s action!", what);
|
|
}
|
|
}
|
|
|
|
void scenario::handle_arithmetic(CAction *tmpAction, char *what) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", what));
|
|
handle_rhs(tmpAction, what);
|
|
}
|
|
|
|
void scenario::parseAction(CActions *actions) {
|
|
char * actionElem;
|
|
unsigned int recvScenarioLen = 0;
|
|
char * currentRegExp = NULL;
|
|
char * buffer = NULL;
|
|
char ** currentTabVarName = NULL;
|
|
int currentNbVarNames;
|
|
char * ptr;
|
|
int sub_currentNbVarId;
|
|
|
|
while((actionElem = xp_open_element(recvScenarioLen))) {
|
|
CAction *tmpAction = new CAction(this);
|
|
|
|
if(!strcmp(actionElem, "ereg")) {
|
|
ptr = xp_get_string("regexp", "ereg");
|
|
|
|
// keeping regexp expression in memory
|
|
if(currentRegExp != NULL)
|
|
delete[] currentRegExp;
|
|
currentRegExp = new char[strlen(ptr)+1];
|
|
buffer = new char[strlen(ptr)+1];
|
|
xp_replace(ptr, buffer, "<", "<");
|
|
xp_replace(buffer, currentRegExp, ">", ">");
|
|
if(buffer != NULL)
|
|
delete[] buffer;
|
|
tmpAction->setActionType(CAction::E_AT_ASSIGN_FROM_REGEXP);
|
|
|
|
// warning - although these are detected for both msg and hdr
|
|
// they are only implemented for search_in="hdr"
|
|
tmpAction->setCaseIndep(xp_get_bool("case_indep", "ereg", false));
|
|
tmpAction->setHeadersOnly(xp_get_bool("start_line", "ereg", false));
|
|
|
|
free(ptr);
|
|
if ( 0 != ( ptr = xp_get_value((char *)"search_in") ) ) {
|
|
tmpAction->setOccurence(1);
|
|
|
|
if ( 0 == strcmp(ptr, (char *)"msg") ) {
|
|
tmpAction->setLookingPlace(CAction::E_LP_MSG);
|
|
tmpAction->setLookingChar (NULL);
|
|
} else if ( 0 == strcmp(ptr, (char *)"body") ) {
|
|
tmpAction->setLookingPlace(CAction::E_LP_BODY);
|
|
tmpAction->setLookingChar (NULL);
|
|
} else if (!strcmp(ptr, (char *)"var")) {
|
|
tmpAction->setVarInId(xp_get_var("variable", "ereg"));
|
|
tmpAction->setLookingPlace(CAction::E_LP_VAR);
|
|
} else if (!strcmp(ptr, (char *)"hdr")) {
|
|
ptr = xp_get_value((char *)"header");
|
|
if (!ptr || !strlen(ptr)) {
|
|
ERROR("search_in=\"hdr\" requires header field");
|
|
}
|
|
tmpAction->setLookingPlace(CAction::E_LP_HDR);
|
|
tmpAction->setLookingChar(ptr);
|
|
if (0 != (ptr = xp_get_value((char *)"occurence"))) {
|
|
tmpAction->setOccurence (atol(ptr));
|
|
}
|
|
if (0 != (ptr = xp_get_value((char *)"occurrence"))) {
|
|
tmpAction->setOccurence (atol(ptr));
|
|
}
|
|
} else {
|
|
ERROR("Unknown search_in value %s", ptr);
|
|
}
|
|
} else {
|
|
tmpAction->setLookingPlace(CAction::E_LP_MSG);
|
|
tmpAction->setLookingChar(NULL);
|
|
} // end if-else search_in
|
|
|
|
if (xp_get_value("check_it")) {
|
|
tmpAction->setCheckIt(xp_get_bool("check_it", "ereg", false));
|
|
if (xp_get_value("check_it_inverse")) {
|
|
ERROR("Can not have both check_it and check_it_inverse for ereg!");
|
|
}
|
|
} else {
|
|
tmpAction->setCheckItInverse(xp_get_bool("check_it_inverse", "ereg", false));
|
|
}
|
|
|
|
if (!(ptr = xp_get_value((char *) "assign_to"))) {
|
|
ERROR("assign_to value is missing");
|
|
}
|
|
|
|
createStringTable(ptr, ¤tTabVarName, ¤tNbVarNames);
|
|
|
|
int varId = get_var(currentTabVarName[0], "assign_to");
|
|
tmpAction->setVarId(varId);
|
|
|
|
tmpAction->setRegExp(currentRegExp);
|
|
if (currentNbVarNames > 1 ) {
|
|
sub_currentNbVarId = currentNbVarNames - 1 ;
|
|
tmpAction->setNbSubVarId(sub_currentNbVarId);
|
|
|
|
for(int i=1; i<= sub_currentNbVarId; i++) {
|
|
int varId = get_var(currentTabVarName[i], "sub expression assign_to");
|
|
tmpAction->setSubVarId(varId);
|
|
}
|
|
}
|
|
|
|
freeStringTable(currentTabVarName, currentNbVarNames);
|
|
|
|
if(currentRegExp != NULL) {
|
|
delete[] currentRegExp;
|
|
}
|
|
currentRegExp = NULL;
|
|
} /* end !strcmp(actionElem, "ereg") */ else if(!strcmp(actionElem, "log")) {
|
|
tmpAction->setMessage(xp_get_string("message", "log"));
|
|
tmpAction->setActionType(CAction::E_AT_LOG_TO_FILE);
|
|
} else if(!strcmp(actionElem, "warning")) {
|
|
tmpAction->setMessage(xp_get_string("message", "warning"));
|
|
tmpAction->setActionType(CAction::E_AT_LOG_WARNING);
|
|
} else if(!strcmp(actionElem, "error")) {
|
|
tmpAction->setMessage(xp_get_string("message", "error"));
|
|
tmpAction->setActionType(CAction::E_AT_LOG_ERROR);
|
|
} else if(!strcmp(actionElem, "assign")) {
|
|
tmpAction->setActionType(CAction::E_AT_ASSIGN_FROM_VALUE);
|
|
handle_arithmetic(tmpAction, "assign");
|
|
} else if(!strcmp(actionElem, "assignstr")) {
|
|
tmpAction->setActionType(CAction::E_AT_ASSIGN_FROM_STRING);
|
|
tmpAction->setVarId(xp_get_var("assign_to", "assignstr"));
|
|
tmpAction->setMessage(xp_get_string("value", "assignstr"));
|
|
} else if(!strcmp(actionElem, "gettimeofday")) {
|
|
tmpAction->setActionType(CAction::E_AT_ASSIGN_FROM_GETTIMEOFDAY);
|
|
|
|
if (!(ptr = xp_get_value((char *) "assign_to"))) {
|
|
ERROR("assign_to value is missing");
|
|
}
|
|
createStringTable(ptr, ¤tTabVarName, ¤tNbVarNames);
|
|
if (currentNbVarNames != 2 ) {
|
|
ERROR("The gettimeofday action requires two output variables!");
|
|
}
|
|
tmpAction->setNbSubVarId(1);
|
|
|
|
int varId = get_var(currentTabVarName[0], "gettimeofday seconds assign_to");
|
|
tmpAction->setVarId(varId);
|
|
varId = get_var(currentTabVarName[1], "gettimeofday useconds assign_to");
|
|
tmpAction->setSubVarId(varId);
|
|
|
|
freeStringTable(currentTabVarName, currentNbVarNames);
|
|
} else if(!strcmp(actionElem, "index")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "index"));
|
|
tmpAction->setActionType(CAction::E_AT_ASSIGN_FROM_INDEX);
|
|
} else if(!strcmp(actionElem, "jump")) {
|
|
tmpAction->setActionType(CAction::E_AT_JUMP);
|
|
handle_rhs(tmpAction, "jump");
|
|
} else if(!strcmp(actionElem, "pauserestore")) {
|
|
tmpAction->setActionType(CAction::E_AT_PAUSE_RESTORE);
|
|
handle_rhs(tmpAction, "pauserestore");
|
|
} else if(!strcmp(actionElem, "add")) {
|
|
tmpAction->setActionType(CAction::E_AT_VAR_ADD);
|
|
handle_arithmetic(tmpAction, "add");
|
|
} else if(!strcmp(actionElem, "subtract")) {
|
|
tmpAction->setActionType(CAction::E_AT_VAR_SUBTRACT);
|
|
handle_arithmetic(tmpAction, "subtract");
|
|
} else if(!strcmp(actionElem, "multiply")) {
|
|
tmpAction->setActionType(CAction::E_AT_VAR_MULTIPLY);
|
|
handle_arithmetic(tmpAction, "multiply");
|
|
} else if(!strcmp(actionElem, "divide")) {
|
|
tmpAction->setActionType(CAction::E_AT_VAR_DIVIDE);
|
|
handle_arithmetic(tmpAction, "divide");
|
|
if (tmpAction->getVarInId() == 0) {
|
|
if (tmpAction->getDoubleValue() == 0.0) {
|
|
ERROR("divide actions can not have a value of zero!");
|
|
}
|
|
}
|
|
} else if(!strcmp(actionElem, "sample")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "sample"));
|
|
tmpAction->setActionType(CAction::E_AT_ASSIGN_FROM_SAMPLE);
|
|
tmpAction->setDistribution(parse_distribution());
|
|
} else if(!strcmp(actionElem, "todouble")) {
|
|
tmpAction->setActionType(CAction::E_AT_VAR_TO_DOUBLE);
|
|
tmpAction->setVarId(xp_get_var("assign_to", "todouble"));
|
|
tmpAction->setVarInId(xp_get_var("variable", "todouble"));
|
|
} else if(!strcmp(actionElem, "test")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "test"));
|
|
tmpAction->setVarInId(xp_get_var("variable", "test"));
|
|
if (xp_get_value("value")) {
|
|
tmpAction->setDoubleValue(xp_get_double("value", "test"));
|
|
if (xp_get_value("variable2")) {
|
|
ERROR("Can not have both a value and a variable2 for test!");
|
|
}
|
|
} else {
|
|
tmpAction->setVarIn2Id(xp_get_var("variable2", "test"));
|
|
}
|
|
tmpAction->setActionType(CAction::E_AT_VAR_TEST);
|
|
ptr = xp_get_string("compare", "test");
|
|
if (!strcmp(ptr, "equal")) {
|
|
tmpAction->setComparator(CAction::E_C_EQ);
|
|
} else if (!strcmp(ptr, "not_equal")) {
|
|
tmpAction->setComparator(CAction::E_C_NE);
|
|
} else if (!strcmp(ptr, "greater_than")) {
|
|
tmpAction->setComparator(CAction::E_C_GT);
|
|
} else if (!strcmp(ptr, "less_than")) {
|
|
tmpAction->setComparator(CAction::E_C_LT);
|
|
} else if (!strcmp(ptr, "greater_than_equal")) {
|
|
tmpAction->setComparator(CAction::E_C_GEQ);
|
|
} else if (!strcmp(ptr, "less_than_equal")) {
|
|
tmpAction->setComparator(CAction::E_C_LEQ);
|
|
} else {
|
|
ERROR("Invalid 'compare' parameter: %s", ptr);
|
|
}
|
|
free(ptr);
|
|
} else if(!strcmp(actionElem, "verifyauth")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "verifyauth"));
|
|
tmpAction->setMessage(xp_get_string("username", "verifyauth"), 0);
|
|
tmpAction->setMessage(xp_get_string("password", "verifyauth"), 1);
|
|
tmpAction->setActionType(CAction::E_AT_VERIFY_AUTH);
|
|
} else if(!strcmp(actionElem, "lookup")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "lookup"));
|
|
tmpAction->setMessage(xp_get_string("file", "lookup"), 0);
|
|
tmpAction->setMessage(xp_get_string("key", "lookup"), 1);
|
|
tmpAction->setActionType(CAction::E_AT_LOOKUP);
|
|
} else if(!strcmp(actionElem, "insert")) {
|
|
tmpAction->setMessage(xp_get_string("file", "insert"), 0);
|
|
tmpAction->setMessage(xp_get_string("value", "insert"), 1);
|
|
tmpAction->setActionType(CAction::E_AT_INSERT);
|
|
} else if(!strcmp(actionElem, "replace")) {
|
|
tmpAction->setMessage(xp_get_string("file", "replace"), 0);
|
|
tmpAction->setMessage(xp_get_string("line", "replace"), 1);
|
|
tmpAction->setMessage(xp_get_string("value", "replace"), 2);
|
|
tmpAction->setActionType(CAction::E_AT_REPLACE);
|
|
} else if(!strcmp(actionElem, "setdest")) {
|
|
tmpAction->setMessage(xp_get_string("host", actionElem), 0);
|
|
tmpAction->setMessage(xp_get_string("port", actionElem), 1);
|
|
tmpAction->setMessage(xp_get_string("protocol", actionElem), 2);
|
|
tmpAction->setActionType(CAction::E_AT_SET_DEST);
|
|
} else if(!strcmp(actionElem, "closecon")) {
|
|
tmpAction->setActionType(CAction::E_AT_CLOSE_CON);
|
|
} else if(!strcmp(actionElem, "strcmp")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "strcmp"));
|
|
tmpAction->setVarInId(xp_get_var("variable", "strcmp"));
|
|
if (xp_get_value("value")) {
|
|
tmpAction->setStringValue(xp_get_string("value", "strcmp"));
|
|
if (xp_get_value("variable2")) {
|
|
ERROR("Can not have both a value and a variable2 for strcmp!");
|
|
}
|
|
} else {
|
|
tmpAction->setVarIn2Id(xp_get_var("variable2", "strcmp"));
|
|
}
|
|
tmpAction->setActionType(CAction::E_AT_VAR_STRCMP);
|
|
} else if(!strcmp(actionElem, "trim")) {
|
|
tmpAction->setVarId(xp_get_var("assign_to", "trim"));
|
|
tmpAction->setActionType(CAction::E_AT_VAR_TRIM);
|
|
} else if(!strcmp(actionElem, "exec")) {
|
|
if((ptr = xp_get_value((char *)"command"))) {
|
|
tmpAction->setActionType(CAction::E_AT_EXECUTE_CMD);
|
|
tmpAction->setMessage(ptr);
|
|
} /* end (ptr = xp_get_value("command") */ else if((ptr = xp_get_value((char *)"int_cmd"))) {
|
|
CAction::T_IntCmdType type(CAction::E_INTCMD_STOPCALL); /* assume the default */
|
|
|
|
if (!strcmp(ptr, "stop_now")) {
|
|
type = CAction::E_INTCMD_STOP_NOW;
|
|
} else if (!strcmp(ptr, "stop_gracefully")) {
|
|
type = CAction::E_INTCMD_STOP_ALL;
|
|
} else if (!strcmp(ptr, "stop_call")) {
|
|
type = CAction::E_INTCMD_STOPCALL;
|
|
}
|
|
|
|
/* the action is well formed, adding it in the */
|
|
/* tmpActionTable */
|
|
tmpAction->setActionType(CAction::E_AT_EXEC_INTCMD);
|
|
tmpAction->setIntCmd(type);
|
|
#ifdef PCAPPLAY
|
|
} else if ((ptr = xp_get_value((char *) "play_pcap_audio"))) {
|
|
tmpAction->setPcapArgs(ptr);
|
|
tmpAction->setActionType(CAction::E_AT_PLAY_PCAP_AUDIO);
|
|
hasMedia = 1;
|
|
} else if ((ptr = xp_get_value((char *) "play_pcap_video"))) {
|
|
tmpAction->setPcapArgs(ptr);
|
|
tmpAction->setActionType(CAction::E_AT_PLAY_PCAP_VIDEO);
|
|
hasMedia = 1;
|
|
#else
|
|
} else if ((ptr = xp_get_value((char *) "play_pcap_audio"))) {
|
|
ERROR("play_pcap_audio requires pcap support! Please recompile SIPp");
|
|
} else if ((ptr = xp_get_value((char *) "play_pcap_video"))) {
|
|
ERROR("play_pcap_video requires pcap support! Please recompile SIPp");
|
|
#endif
|
|
} else {
|
|
ERROR("illegal <exec> in the scenario\n");
|
|
}
|
|
} else {
|
|
ERROR("Unknown action: %s", actionElem);
|
|
}
|
|
|
|
/* If the action was not well-formed, there should have already been an
|
|
* ERROR declaration, thus it is safe to add it here at the end of the loop. */
|
|
actions->setAction(tmpAction);
|
|
|
|
xp_close_element();
|
|
recvScenarioLen++;
|
|
} // end while
|
|
}
|
|
|
|
// Action list for the message indexed by message_index in
|
|
// the scenario
|
|
void scenario::getActionForThisMessage(message *message)
|
|
{
|
|
char * actionElem;
|
|
|
|
if(!(actionElem = xp_open_element(0))) {
|
|
return;
|
|
}
|
|
if(strcmp(actionElem, "action")) {
|
|
return;
|
|
}
|
|
|
|
/* We actually have an action element. */
|
|
if(message->M_actions != NULL) {
|
|
ERROR("Duplicate action for %s index %d", message->desc, message->index);
|
|
}
|
|
message->M_actions = new CActions();
|
|
|
|
parseAction(message->M_actions);
|
|
xp_close_element();
|
|
}
|
|
|
|
void scenario::getBookKeeping(message *message) {
|
|
char *ptr;
|
|
|
|
if((ptr = xp_get_value((char *)"rtd"))) {
|
|
message -> stop_rtd = get_rtd(ptr, false);
|
|
}
|
|
if ((ptr = xp_get_value((char *)"repeat_rtd"))) {
|
|
if (message -> stop_rtd) {
|
|
message-> repeat_rtd = get_bool(ptr, "repeat_rtd");
|
|
} else {
|
|
ERROR("There is a repeat_rtd element without an rtd element");
|
|
}
|
|
}
|
|
|
|
if((ptr = xp_get_value((char *)"start_rtd"))) {
|
|
message -> start_rtd = get_rtd(ptr, true);
|
|
}
|
|
|
|
if((ptr = xp_get_value((char *)"counter"))) {
|
|
message -> counter = get_counter(ptr, "counter");
|
|
}
|
|
}
|
|
|
|
void scenario::getCommonAttributes(message *message) {
|
|
char *ptr;
|
|
|
|
getBookKeeping(message);
|
|
getActionForThisMessage(message);
|
|
|
|
if((ptr = xp_get_value((char *)"lost"))) {
|
|
message -> lost = get_double(ptr, "lost percentage");
|
|
lose_packets = 1;
|
|
}
|
|
|
|
if((ptr = xp_get_value((char *)"crlf"))) {
|
|
message -> crlf = 1;
|
|
}
|
|
|
|
if (xp_get_value("hiderest")) {
|
|
hidedefault = xp_get_bool("hiderest", "hiderest");
|
|
}
|
|
message -> hide = xp_get_bool("hide", "hide", hidedefault);
|
|
if((ptr = xp_get_value((char *)"display"))) {
|
|
message -> display_str = strdup(ptr);
|
|
}
|
|
|
|
message -> condexec = xp_get_var("condexec", "condexec variable", -1);
|
|
message -> condexec_inverse = xp_get_bool("condexec_inverse", "condexec_inverse", false);
|
|
|
|
if ((ptr = xp_get_value((char *)"next"))) {
|
|
if (found_timewait) {
|
|
ERROR("next labels are not allowed in <timewait> elements.");
|
|
}
|
|
message -> nextLabel = strdup(ptr);
|
|
message -> test = xp_get_var("test", "test variable", -1);
|
|
if ( 0 != ( ptr = xp_get_value((char *)"chance") ) ) {
|
|
float chance = get_double(ptr,"chance");
|
|
/* probability of branch to next */
|
|
if (( chance < 0.0 ) || (chance > 1.0 )) {
|
|
ERROR("Chance %s not in range [0..1]", ptr);
|
|
}
|
|
message -> chance = (int)((1.0-chance)*RAND_MAX);
|
|
}
|
|
else {
|
|
message -> chance = 0; /* always */
|
|
}
|
|
}
|
|
|
|
if ((ptr = xp_get_value((char *)"ontimeout"))) {
|
|
if (found_timewait) {
|
|
ERROR("ontimeout labels are not allowed in <timewait> elements.");
|
|
}
|
|
message -> onTimeoutLabel = strdup(ptr);
|
|
}
|
|
}
|
|
|
|
// char* manipulation : create a int[] from a char*
|
|
// test first is the char* is formed by int separeted by coma
|
|
// and then create the table
|
|
|
|
int isWellFormed(char * P_listeStr, int * nombre)
|
|
{
|
|
char * ptr = P_listeStr;
|
|
int sizeOf;
|
|
bool isANumber;
|
|
|
|
(*nombre) = 0;
|
|
sizeOf = strlen(P_listeStr);
|
|
// getting the number
|
|
if(sizeOf > 0)
|
|
{
|
|
// is the string well formed ? [0-9] [,]
|
|
isANumber = false;
|
|
for(int i=0; i<=sizeOf; i++)
|
|
{
|
|
switch(ptr[i])
|
|
{
|
|
case ',':
|
|
if(isANumber == false)
|
|
{
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
(*nombre)++;
|
|
}
|
|
isANumber = false;
|
|
break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
isANumber = true;
|
|
break;
|
|
case '\t':
|
|
case ' ' :
|
|
break;
|
|
case '\0':
|
|
if(isANumber == false)
|
|
{
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
(*nombre)++;
|
|
}
|
|
break;
|
|
default:
|
|
return(0);
|
|
}
|
|
} // end for
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
int createIntegerTable(char * P_listeStr,
|
|
unsigned int ** listeInteger,
|
|
int * sizeOfList)
|
|
{
|
|
int nb=0;
|
|
char * ptr = P_listeStr;
|
|
char * ptr_prev = P_listeStr;
|
|
unsigned int current_int;
|
|
|
|
if(P_listeStr){
|
|
if(isWellFormed(P_listeStr, sizeOfList) == 1)
|
|
{
|
|
(*listeInteger) = new unsigned int[(*sizeOfList)];
|
|
while((*ptr) != ('\0'))
|
|
{
|
|
if((*ptr) == ',')
|
|
{
|
|
sscanf(ptr_prev, "%u", ¤t_int);
|
|
if (nb<(*sizeOfList))
|
|
(*listeInteger)[nb] = current_int;
|
|
nb++;
|
|
ptr_prev = ptr+1;
|
|
}
|
|
ptr++;
|
|
}
|
|
|
|
// Read the last
|
|
sscanf(ptr_prev, "%u", ¤t_int);
|
|
if (nb<(*sizeOfList))
|
|
(*listeInteger)[nb] = current_int;
|
|
nb++;
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}else return(0);
|
|
}
|
|
|
|
int createStringTable(char * inputString, char *** stringList, int *sizeOfList)
|
|
{
|
|
if(!inputString) {
|
|
return 0;
|
|
}
|
|
|
|
*stringList = NULL;
|
|
*sizeOfList = 0;
|
|
|
|
do
|
|
{
|
|
char *p = strchr(inputString, ',');
|
|
if (p) {
|
|
*p++ = '\0';
|
|
}
|
|
|
|
*stringList = (char **)realloc(*stringList, sizeof(char *) * (*sizeOfList + 1));
|
|
(*stringList)[*sizeOfList] = strdup(inputString);
|
|
(*sizeOfList)++;
|
|
|
|
inputString = p;
|
|
}
|
|
while (inputString);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void freeStringTable(char ** stringList, int sizeOfList) {
|
|
for (int i = 0; i < sizeOfList; i++) {
|
|
free(stringList[i]);
|
|
}
|
|
free(stringList);
|
|
}
|
|
|
|
/* These are the names of the scenarios, they must match the default_scenario table. */
|
|
char *scenario_table[] = {
|
|
"uac",
|
|
"uas",
|
|
"regexp",
|
|
"3pcc-C-A",
|
|
"3pcc-C-B",
|
|
"3pcc-A",
|
|
"3pcc-B",
|
|
"branchc",
|
|
"branchs",
|
|
"uac_pcap",
|
|
"ooc_default",
|
|
"ooc_dummy",
|
|
};
|
|
|
|
int find_scenario(const char *scenario) {
|
|
int i, max;
|
|
max = sizeof(scenario_table)/sizeof(scenario_table[0]);
|
|
|
|
for (i = 0; i < max; i++) {
|
|
if (!strcmp(scenario_table[i], scenario)) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
ERROR("Invalid default scenario name '%s'.\n", scenario);
|
|
return -1;
|
|
}
|
|
|
|
// TIP: to integrate an existing XML scenario, use the following sed line:
|
|
// cat ../3pcc-controller-B.xml | sed -e 's/\"/\\\"/g' -e 's/\(.*\)/\"\1\\n\"/'
|
|
char * default_scenario [] = {
|
|
/************* Default_scenario[0] ***************/
|
|
(char *)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'uac' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"Basic Sipstone UAC\">\n"
|
|
" <!-- In client mode (sipp placing calls), the Call-ID MUST be -->\n"
|
|
" <!-- generated by sipp. To do so, use [call_id] keyword. -->\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 INVITE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"100\"\n"
|
|
" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"180\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"183\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- By adding rrs=\"true\" (Record Route Sets), the route sets -->\n"
|
|
" <!-- are saved and used for following messages sent. Useful to test -->\n"
|
|
" <!-- against stateful SIP proxies/B2BUAs. -->\n"
|
|
" <recv response=\"200\" rtd=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- Packet lost can be simulated in any send/recv message by -->\n"
|
|
" <!-- by adding the 'lost = \"10\"'. Value can be [1-100] percent. -->\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 ACK\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- This delay can be customized by the -d command-line option -->\n"
|
|
" <!-- or by adding a 'milliseconds = \"value\"' option here. -->\n"
|
|
" <pause/>\n"
|
|
"\n"
|
|
" <!-- The 'crlf' option inserts a blank line in the statistics report. -->\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 2 BYE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"200\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n"
|
|
,
|
|
|
|
/************* Default_scenario[1] ***************/
|
|
(char *)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'uas' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"Basic UAS responder\">\n"
|
|
" <!-- By adding rrs=\"true\" (Record Route Sets), the route sets -->\n"
|
|
" <!-- are saved and used for following messages sent. Useful to test -->\n"
|
|
" <!-- against stateful SIP proxies/B2BUAs. -->\n"
|
|
" <recv request=\"INVITE\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- The '[last_*]' keyword is replaced automatically by the -->\n"
|
|
" <!-- specified header if it was present in the last message received -->\n"
|
|
" <!-- (except if it was a retransmission). If the header was not -->\n"
|
|
" <!-- present or if no message has been received, the '[last_*]' -->\n"
|
|
" <!-- keyword is discarded, and all bytes until the end of the line -->\n"
|
|
" <!-- are also discarded. -->\n"
|
|
" <!-- -->\n"
|
|
" <!-- If the specified header was present several times in the -->\n"
|
|
" <!-- message, all occurences are concatenated (CRLF separated) -->\n"
|
|
" <!-- to be used in place of the '[last_*]' keyword. -->\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 180 Ringing\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag01[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag01[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv request=\"ACK\"\n"
|
|
" optional=\"true\"\n"
|
|
" rtd=\"true\"\n"
|
|
" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv request=\"BYE\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Keep the call open for a while in case the 200 is lost to be -->\n"
|
|
" <!-- able to retransmit it if we receive the BYE again. -->\n"
|
|
" <timewait milliseconds=\"4000\"/>\n"
|
|
"\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/************* Default_scenario[2] ***************/
|
|
(char *)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'regexp client' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"Client with regexp scenario\">\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag02[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 INVITE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"100\"\n"
|
|
" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"180\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
" <recv response=\"183\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"200\" start_rtd=\"true\">\n"
|
|
" <!-- Definition of regexp in the action tag. The regexp must follow -->\n"
|
|
" <!-- the Posix Extended standard (POSIX 1003.2), see: -->\n"
|
|
" <!-- -->\n"
|
|
" <!-- http://www.opengroup.org/onlinepubs/007908799/xbd/re.html -->\n"
|
|
" <!-- -->\n"
|
|
" <!-- regexp : Contain the regexp to use for matching the -->\n"
|
|
" <!-- received message -->\n"
|
|
" <!-- MANDATORY -->\n"
|
|
" <!-- search_in : msg (try to match against the entire message) -->\n"
|
|
" <!-- : hdr (try to match against a specific SIP header -->\n"
|
|
" <!-- (passed in the header tag) -->\n"
|
|
" <!-- OPTIONAL - default value : msg -->\n"
|
|
" <!-- header : Header to try to match against. -->\n"
|
|
" <!-- Only used when the search_in tag is set to hdr -->\n"
|
|
" <!-- MANDATORY IF search_in is equal to hdr -->\n"
|
|
" <!-- check_it : if set to true, the call is marked as failed if -->\n"
|
|
" <!-- the regexp doesn't match. -->\n"
|
|
" <!-- OPTIONAL - default value : false -->\n"
|
|
" <!-- assign_to : contain the variable id (integer) or a list of -->\n"
|
|
" <!-- variable id which will be used to store the -->\n"
|
|
" <!-- result of the matching process between the regexp -->\n"
|
|
" <!-- and the message. This variable can be re-used at -->\n"
|
|
" <!-- a later time in the scenario using '[$n]' syntax -->\n"
|
|
" <!-- where n is the variable id. -->\n"
|
|
" <!-- MANDATORY -->\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[:][0-9]{1,5}\" \n"
|
|
" search_in=\"msg\" \n"
|
|
" check_it=\"true\" \n"
|
|
" assign_to=\"1\"/>\n"
|
|
" <ereg regexp=\".*\" \n"
|
|
" search_in=\"hdr\" \n"
|
|
" header=\"Contact:\" \n"
|
|
" check_it=\"true\" \n"
|
|
" assign_to=\"6\"/>\n"
|
|
" <ereg regexp=\"o=([[:alnum:]]*) ([[:alnum:]]*) ([[:alnum:]]*)\"\n"
|
|
" search_in=\"msg\" \n"
|
|
" check_it=\"true\" \n"
|
|
" assign_to=\"3,4,5,8\"/>\n"
|
|
" </action>\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
" ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag02[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 ACK\n"
|
|
" retrievedIp: [$1]\n"
|
|
" retrievedContact:[$6]\n"
|
|
" retrievedSdpOrigin:[$3]\n"
|
|
" retrievedSdpOrigin-username:[$4]\n"
|
|
" retrievedSdpOrigin-session-id:[$5]\n"
|
|
" retrievedSdpOrigin-version:[$8]\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- This delay can be customized by the -d command-line option -->\n"
|
|
" <!-- or by adding a 'milliseconds = \"value\"' option here. -->\n"
|
|
" <pause milliseconds = \"1000\"/>\n"
|
|
"\n"
|
|
" <!-- The 'crlf' option inserts a blank line in the statistics report. -->\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag02[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 2 BYE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"200\" crlf=\"true\" rtd=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"1000, 1040, 1080, 1120, 1160, 1200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"1000, 1100, 1200, 1300, 1400\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/************* Default_scenario[3] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- 3PCC - Controller - A side -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- A Controller B -->\n"
|
|
"<!-- |(1) INVITE no SDP | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(2) 200 offer1 | | -->\n"
|
|
"<!-- |==================>| | -->\n"
|
|
"<!-- | |(3) INVITE offer1 | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- | |(4) 200 OK answer1 | -->\n"
|
|
"<!-- | |<==================| -->\n"
|
|
"<!-- | |(5) ACK | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- |(6) ACK answer1 | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(7) RTP | | -->\n"
|
|
"<!-- |.......................................| -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"3PCC Controller - A side\">\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag03[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 INVITE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"100\" optional=\"true\"> </recv>\n"
|
|
" <recv response=\"180\" optional=\"true\"> </recv>\n"
|
|
" <recv response=\"183\" optional=\"true\"> </recv>\n"
|
|
" <recv response=\"200\" crlf=\"true\" start_rtd=\"true\">\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"Content-Type:.*\" \n"
|
|
" search_in=\"msg\" \n"
|
|
" assign_to=\"1\" /> \n"
|
|
" </action>\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <sendCmd>\n"
|
|
" <![CDATA[\n"
|
|
" Call-ID: [call_id]\n"
|
|
" [$1]\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </sendCmd>\n"
|
|
" \n"
|
|
" <recvCmd>\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"Content-Type:.*\" \n"
|
|
" search_in=\"msg\" \n"
|
|
" assign_to=\"2\" /> \n"
|
|
" </action>\n"
|
|
" \n"
|
|
" </recvCmd>\n"
|
|
" \n"
|
|
" <send rtd=\"true\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag03[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 ACK\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" [$2]\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <pause milliseconds=\"1000\"/>\n"
|
|
"\n"
|
|
" <!-- The 'crlf' option inserts a blank line in the statistics report. -->\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag03[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 2 BYE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"200\" crlf=\"true\"> </recv>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/************* Default_scenario[4] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- 3PCC - Controller - B side -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- A Controller B -->\n"
|
|
"<!-- |(1) INVITE no SDP | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(2) 200 offer1 | | -->\n"
|
|
"<!-- |==================>| | -->\n"
|
|
"<!-- | |(3) INVITE offer1 | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- | |(4) 200 OK answer1 | -->\n"
|
|
"<!-- | |<==================| -->\n"
|
|
"<!-- | |(5) ACK | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- |(6) ACK answer1 | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(7) RTP | | -->\n"
|
|
"<!-- |.......................................| -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"\n"
|
|
"<scenario name=\"3PCC Controller - B side\">\n"
|
|
"\n"
|
|
"<recvCmd>\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"Content-Type:.*\" \n"
|
|
" search_in=\"msg\" \n"
|
|
" assign_to=\"1\" /> \n"
|
|
" </action>\n"
|
|
"</recvCmd>\n"
|
|
"\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag04[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 INVITE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" [$1]\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"100\" optional=\"true\"> </recv>\n"
|
|
" <recv response=\"180\" optional=\"true\"> </recv>\n"
|
|
" <recv response=\"183\" optional=\"true\"> </recv>\n"
|
|
" <recv response=\"200\" crlf=\"true\">\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"Content-Type:.*\" \n"
|
|
" search_in=\"msg\" \n"
|
|
" assign_to=\"2\" /> \n"
|
|
" </action>\n"
|
|
" </recv>\n"
|
|
" \n"
|
|
" \n"
|
|
" <send start_rtd=\"true\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag04[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 ACK\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <sendCmd>\n"
|
|
" <![CDATA[\n"
|
|
" Call-ID: [call_id]\n"
|
|
" [$2]\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </sendCmd>\n"
|
|
" \n"
|
|
" <pause milliseconds=\"1000\"/>\n"
|
|
"\n"
|
|
"\n"
|
|
" <!-- The 'crlf' option inserts a blank line in the statistics report. -->\n"
|
|
" <send retrans=\"500\" rtd=\"true\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag04[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 2 BYE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"200\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/************* Default_scenario[5] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- 3PCC - A side emulator -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- A Controller B -->\n"
|
|
"<!-- |(1) INVITE no SDP | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(2) 200 offer1 | | -->\n"
|
|
"<!-- |==================>| | -->\n"
|
|
"<!-- | |(3) INVITE offer1 | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- | |(4) 200 OK answer1 | -->\n"
|
|
"<!-- | |<==================| -->\n"
|
|
"<!-- | |(5) ACK | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- |(6) ACK answer1 | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(7) RTP | | -->\n"
|
|
"<!-- |.......................................| -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"\n"
|
|
"<scenario name=\"3PCC A side\">\n"
|
|
" <recv request=\"INVITE\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag05[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv request=\"ACK\" rtd=\"true\" crlf=\"true\"> </recv>\n"
|
|
"\n"
|
|
" <!-- RTP flow starts from here! -->\n"
|
|
"\n"
|
|
" <recv request=\"BYE\" crlf=\"true\"> </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Keep the call open for a while in case the 200 is lost to be -->\n"
|
|
" <!-- able to retransmit it if we receive the BYE again. -->\n"
|
|
" <timewait milliseconds=\"2000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/************* Default_scenario[6] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- 3PCC - B side emulator -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- A Controller B -->\n"
|
|
"<!-- |(1) INVITE no SDP | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(2) 200 offer1 | | -->\n"
|
|
"<!-- |==================>| | -->\n"
|
|
"<!-- | |(3) INVITE offer1 | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- | |(4) 200 OK answer1 | -->\n"
|
|
"<!-- | |<==================| -->\n"
|
|
"<!-- | |(5) ACK | -->\n"
|
|
"<!-- | |==================>| -->\n"
|
|
"<!-- |(6) ACK answer1 | | -->\n"
|
|
"<!-- |<==================| | -->\n"
|
|
"<!-- |(7) RTP | | -->\n"
|
|
"<!-- |.......................................| -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"\n"
|
|
"\n"
|
|
"<scenario name=\"3PCC B side\">\n"
|
|
" <recv request=\"INVITE\" crlf=\"true\"> </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag06[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv request=\"ACK\" rtd=\"true\" crlf=\"true\"> </recv>\n"
|
|
"\n"
|
|
" <!-- RTP flow starts from here! -->\n"
|
|
"\n"
|
|
" <recv request=\"BYE\"> </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Keep the call open for a while in case the 200 is lost to be -->\n"
|
|
" <!-- able to retransmit it if we receive the BYE again. -->\n"
|
|
" <timewait milliseconds=\"2000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n",
|
|
|
|
/************* Default_scenario[7] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'branchc' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"branch_client\">\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" REGISTER sip:CA.cym.com SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: ua1 <sip:ua1@nnl.cym:[local_port]>;tag=[pid]SIPpTag07[call_number]\n"
|
|
" To: ua1 <sip:ua1@nnl.cym:[local_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 REGISTER\n"
|
|
" Contact: sip:ua1@[local_ip]:[local_port]\n"
|
|
" Content-Length: 0\n"
|
|
" Expires: 300\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- simple case - just jump over a line -->\n"
|
|
" <recv response=\"200\" rtd=\"true\" next=\"5\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"200\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <label id=\"5\"/>\n"
|
|
"\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" INVITE sip:ua2@CA.cym.com SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: ua[call_number] <sip:ua1@nnl.cym:[local_port]>;tag=[pid]SIPpTag07b[call_number]\n"
|
|
" To: ua2 <sip:ua2@nnl.cym:[remote_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 INVITE\n"
|
|
" Contact: sip:ua1@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"100\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"180\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"183\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- Do something different on an optional receive -->\n"
|
|
" <recv response=\"403\" optional=\"true\" next=\"1\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"200\">\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"ua25\"\n"
|
|
" search_in=\"hdr\"\n"
|
|
" header=\"From: \"\n"
|
|
" assign_to=\"8\"/>\n"
|
|
" </action>\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- set variable 8 above on 25th call, send the ACK but skip the pause for it -->\n"
|
|
" <send next=\"1\" test=\"8\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" ACK sip:ua2@CA.cym.com SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: ua1 <sip:ua1@nnl.cym:[local_port]>;tag=[pid]SIPpTag07b[call_number]\n"
|
|
" To: ua2 <sip:ua2@nnl.cym:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 ACK\n"
|
|
" Contact: sip:ua1@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <pause milliseconds=\"5000\"/>\n"
|
|
"\n"
|
|
" <label id=\"1\"/>\n"
|
|
"\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" BYE sip:ua2@CA.cym.com SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: ua1 <sip:ua1@nnl.cym:[local_port]>;tag=[pid]SIPpTag07b[call_number]\n"
|
|
" To: ua2 <sip:ua2@nnl.cym:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 2 BYE\n"
|
|
" Contact: sip:ua1@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"200\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <pause milliseconds=\"4000\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/************* Default_scenario[8] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'branchs' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"branch_server\">\n"
|
|
" <recv request=\"REGISTER\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag08[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
" Expires: 300\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Set variable 3 if the ua is of the form ua2... -->\n"
|
|
" <recv request=\"INVITE\" crlf=\"true\">\n"
|
|
" <action>\n"
|
|
" <ereg regexp=\"ua2\"\n"
|
|
" search_in=\"hdr\"\n"
|
|
" header=\"From: \"\n"
|
|
" assign_to=\"3\"/>\n"
|
|
" </action>\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- send 180 then trying if variable 3 is set -->\n"
|
|
" <send next=\"1\" test=\"3\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 180 Ringing\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag08b[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- if not, send a 403 error then skip to wait for a BYE -->\n"
|
|
" <send next=\"2\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 403 Error\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag08b[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <label id=\"1\"/>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 100 Trying\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag08b[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:];tag=[pid]SIPpTag08b[call_number]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[media_ip_type] [media_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [media_port] RTP/AVP 0\n"
|
|
" a=rtpmap:0 PCMU/8000\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv request=\"ACK\"\n"
|
|
" optional=\"true\"\n"
|
|
" rtd=\"true\"\n"
|
|
" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <label id=\"2\"/>\n"
|
|
"\n"
|
|
" <recv request=\"BYE\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Keep the call open for a while in case the 200 is lost to be -->\n"
|
|
" <!-- able to retransmit it if we receive the BYE again. -->\n"
|
|
" <timewait milliseconds=\"4000\"/>\n"
|
|
"\n"
|
|
" <!-- Definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- Definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
|
|
/* Although this scenario will not work without pcap play enabled, there is no
|
|
* harm in including it in the binary anyway, because the user could have
|
|
* dumped it and passed it with -sf. */
|
|
|
|
/************* Default_scenario[9] ***************/
|
|
(char*)
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp 'uac' scenario with pcap (rtp) play -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"UAC with media\">\n"
|
|
" <!-- In client mode (sipp placing calls), the Call-ID MUST be -->\n"
|
|
" <!-- generated by sipp. To do so, use [call_id] keyword. -->\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 INVITE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Type: application/sdp\n"
|
|
" Content-Length: [len]\n"
|
|
"\n"
|
|
" v=0\n"
|
|
" o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]\n"
|
|
" s=-\n"
|
|
" c=IN IP[local_ip_type] [local_ip]\n"
|
|
" t=0 0\n"
|
|
" m=audio [auto_media_port] RTP/AVP 8 101\n"
|
|
" a=rtpmap:8 PCMA/8000\n"
|
|
" a=rtpmap:101 telephone-event/8000\n"
|
|
" a=fmtp:101 0-11,16\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"100\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <recv response=\"180\" optional=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- By adding rrs=\"true\" (Record Route Sets), the route sets -->\n"
|
|
" <!-- are saved and used for following messages sent. Useful to test -->\n"
|
|
" <!-- against stateful SIP proxies/B2BUAs. -->\n"
|
|
" <recv response=\"200\" rtd=\"true\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- Packet lost can be simulated in any send/recv message by -->\n"
|
|
" <!-- by adding the 'lost = \"10\"'. Value can be [1-100] percent. -->\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 1 ACK\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Play a pre-recorded PCAP file (RTP stream) -->\n"
|
|
" <nop>\n"
|
|
" <action>\n"
|
|
" <exec play_pcap_audio=\"pcap/g711a.pcap\"/>\n"
|
|
" </action>\n"
|
|
" </nop>\n"
|
|
"\n"
|
|
" <!-- Pause 8 seconds, which is approximately the duration of the -->\n"
|
|
" <!-- PCAP file -->\n"
|
|
" <pause milliseconds=\"8000\"/>\n"
|
|
"\n"
|
|
" <!-- Play an out of band DTMF '1' -->\n"
|
|
" <nop>\n"
|
|
" <action>\n"
|
|
" <exec play_pcap_audio=\"pcap/dtmf_2833_1.pcap\"/>\n"
|
|
" </action>\n"
|
|
" </nop>\n"
|
|
"\n"
|
|
" <pause milliseconds=\"1000\"/>\n"
|
|
"\n"
|
|
" <!-- The 'crlf' option inserts a blank line in the statistics report. -->\n"
|
|
" <send retrans=\"500\">\n"
|
|
" <![CDATA[\n"
|
|
"\n"
|
|
" BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n"
|
|
" Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
|
|
" From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]\n"
|
|
" To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n"
|
|
" Call-ID: [call_id]\n"
|
|
" CSeq: 2 BYE\n"
|
|
" Contact: sip:sipp@[local_ip]:[local_port]\n"
|
|
" Max-Forwards: 70\n"
|
|
" Subject: Performance Test\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <recv response=\"200\" crlf=\"true\">\n"
|
|
" </recv>\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n"
|
|
"\n",
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'uas' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"Out-of-call UAS\">\n"
|
|
" <recv request=\".*\" regexp_match=\"true\" />\n"
|
|
"\n"
|
|
" <send>\n"
|
|
" <![CDATA[\n"
|
|
" SIP/2.0 200 OK\n"
|
|
" [last_Via:]\n"
|
|
" [last_From:]\n"
|
|
" [last_To:]\n"
|
|
" [last_Call-ID:]\n"
|
|
" [last_CSeq:]\n"
|
|
" Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
|
|
" Content-Length: 0\n"
|
|
"\n"
|
|
" ]]>\n"
|
|
" </send>\n"
|
|
"\n"
|
|
" <!-- Keep the call open for a while in case the 200 is lost to be -->\n"
|
|
" <!-- able to retransmit it if we receive the BYE again. -->\n"
|
|
" <timewait milliseconds=\"4000\"/>\n"
|
|
"\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n",
|
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
"<!DOCTYPE scenario SYSTEM \"sipp.dtd\">\n"
|
|
"\n"
|
|
"<!-- This program is free software; you can redistribute it and/or -->\n"
|
|
"<!-- modify it under the terms of the GNU General Public License as -->\n"
|
|
"<!-- published by the Free Software Foundation; either version 2 of the -->\n"
|
|
"<!-- License, or (at your option) any later version. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- This program is distributed in the hope that it will be useful, -->\n"
|
|
"<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->\n"
|
|
"<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->\n"
|
|
"<!-- GNU General Public License for more details. -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- You should have received a copy of the GNU General Public License -->\n"
|
|
"<!-- along with this program; if not, write to the -->\n"
|
|
"<!-- Free Software Foundation, Inc., -->\n"
|
|
"<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->\n"
|
|
"<!-- -->\n"
|
|
"<!-- Sipp default 'uas' scenario. -->\n"
|
|
"<!-- -->\n"
|
|
"\n"
|
|
"<scenario name=\"Out-of-call UAS\">\n"
|
|
" <recv request=\"DUMMY\" />\n"
|
|
"\n"
|
|
" <!-- definition of the response time repartition table (unit is ms) -->\n"
|
|
" <ResponseTimeRepartition value=\"10, 20, 30, 40, 50, 100, 150, 200\"/>\n"
|
|
"\n"
|
|
" <!-- definition of the call length repartition table (unit is ms) -->\n"
|
|
" <CallLengthRepartition value=\"10, 50, 100, 500, 1000, 5000, 10000\"/>\n"
|
|
"\n"
|
|
"</scenario>\n",
|
|
|
|
|
|
};
|