diff --git a/include/scenario.hpp b/include/scenario.hpp
index c35b7f4f..90bd0c08 100644
--- a/include/scenario.hpp
+++ b/include/scenario.hpp
@@ -93,7 +93,7 @@ class message
char * peer_src;
/* If this is a recv */
- int recv_response;
+ char * recv_response;
char * recv_request;
int optional;
bool advance_state;
diff --git a/regress/github-#0769/run b/regress/github-#0769/run
new file mode 100755
index 00000000..aa2f2f49
--- /dev/null
+++ b/regress/github-#0769/run
@@ -0,0 +1,16 @@
+#!/bin/sh
+# This regression test is a part of SIPp.
+# Author: Petr Cisar
+. "`dirname "$0"`/../functions"; init
+
+# uac.xml checks reception of regex-based responses
+sippbg -sn uas -i 127.0.0.1 -p 5070 -m 1
+sippbg -sf uac.xml -i 127.0.0.1 -m 1 127.0.0.1:5070
+job2=$!
+
+# If job2 did not finish, we have failure.
+if /bin/kill -0 $job2 2>/dev/null; then
+ fail
+else
+ ok
+fi
diff --git a/regress/github-#0769/uac.xml b/regress/github-#0769/uac.xml
new file mode 100644
index 00000000..ec84c750
--- /dev/null
+++ b/regress/github-#0769/uac.xml
@@ -0,0 +1,77 @@
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service]
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=-
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service] [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service] [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 4 BYE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
diff --git a/sipp.dtd b/sipp.dtd
index ce8f4672..b144aee7 100644
--- a/sipp.dtd
+++ b/sipp.dtd
@@ -25,7 +25,7 @@
-
+
diff --git a/src/call.cpp b/src/call.cpp
index d3ea6188..a7368644 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -2348,7 +2348,7 @@ bool call::process_unexpected(const char* msg)
if (curmsg -> recv_request) {
desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%s' ", curmsg -> recv_request);
} else {
- desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%d' ", curmsg -> recv_response);
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%s' ", curmsg -> recv_response);
}
} else if (curmsg -> M_type == MSG_TYPE_SEND) {
desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending ");
@@ -4451,24 +4451,45 @@ bool call::matches_scenario(unsigned int index, int reply_code, char * request,
} else {
return !strcmp(curmsg->recv_request, request);
}
- } else if (curmsg->recv_response && (curmsg->recv_response == reply_code)) {
- /* This is a potential candidate, we need to match transactions. */
- if (curmsg->response_txn) {
- if (transactions[curmsg->response_txn - 1].txnID && !strcmp(transactions[curmsg->response_txn - 1].txnID, txn)) {
- return true;
- } else {
- return false;
+ } else if (curmsg->recv_response) {
+ if (curmsg->regexp_match) { // Match response code using regex
+ char reply_code_str[8];
+ snprintf(reply_code_str, 8, "%u", reply_code); // Convert the response code to string
+ if (curmsg->regexp_compile == nullptr) {
+ regex_t *re = new regex_t;
+ /* No regex match position needed (NOSUB), we're simply
+ * looking for the
+ * regex. */
+ if (regcomp(re, curmsg->recv_response, REGCOMP_PARAMS|REG_NOSUB)) {
+ ERROR("Invalid regular expression for index %d: %s", index, curmsg->recv_response);
+ }
+ curmsg->regexp_compile = re;
}
- } else if (index == 0) {
- /* Always true for the first message. */
- return true;
- } else if (curmsg->recv_response_for_cseq_method_list &&
- strstr(curmsg->recv_response_for_cseq_method_list, responsecseqmethod)) {
- /* If we do not have a transaction defined, we just check the CSEQ method. */
- return true;
- } else {
- return false;
- }
+ if (regexec(curmsg->regexp_compile, reply_code_str, (size_t)0, nullptr, REGEXEC_PARAMS)) {
+ return false;
+ }
+ } else { // Exact numerical match
+ if (atoi(curmsg->recv_response) != reply_code) {
+ return false;
+ }
+ }
+ /* This is a potential candidate, we need to match transactions. */
+ if (curmsg->response_txn) {
+ if (transactions[curmsg->response_txn - 1].txnID && !strcmp(transactions[curmsg->response_txn - 1].txnID, txn)) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (index == 0) {
+ /* Always true for the first message. */
+ return true;
+ } else if (curmsg->recv_response_for_cseq_method_list &&
+ strstr(curmsg->recv_response_for_cseq_method_list, responsecseqmethod)) {
+ /* If we do not have a transaction defined, we just check the CSEQ method. */
+ return true;
+ } else {
+ return false;
+ }
}
return false;
diff --git a/src/logger.cpp b/src/logger.cpp
index 4991c32e..2c32fde0 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -114,7 +114,7 @@ void print_count_file(FILE* f, int header)
}
} else if (curmsg->recv_response) {
if (header) {
- sprintf(temp_str, "%u_%d_", index, curmsg->recv_response);
+ sprintf(temp_str, "%u_%s_", index, curmsg->recv_response);
fprintf(f, "%sRecv%s", temp_str, stat_delimiter);
fprintf(f, "%sRetrans%s", temp_str, stat_delimiter);
diff --git a/src/scenario.cpp b/src/scenario.cpp
index 743051c8..eb15e635 100644
--- a/src/scenario.cpp
+++ b/src/scenario.cpp
@@ -53,7 +53,7 @@ message::message(int index, const char *desc)
retrans_delay = 0;
timeout = 0;
- recv_response = 0;
+ recv_response = nullptr; // free on exit
recv_request = nullptr; // free on exit
optional = 0;
advance_state = true;
@@ -116,6 +116,7 @@ message::~message()
free(pause_desc);
delete send_scheme;
free(recv_request);
+ free(recv_response);
if (regexp_compile != nullptr) {
regfree(regexp_compile);
}
@@ -891,7 +892,7 @@ scenario::scenario(char * filename, int deflt)
curmsg->M_type = MSG_TYPE_RECV;
/* Received messages descriptions */
if((cptr = xp_get_value("response"))) {
- curmsg ->recv_response = get_long(cptr, "response code");
+ curmsg ->recv_response = strdup(cptr);
if (method_list) {
curmsg->recv_response_for_cseq_method_list = strdup(method_list);
}
diff --git a/src/screen.cpp b/src/screen.cpp
index 7e53eece..c2834169 100644
--- a/src/screen.cpp
+++ b/src/screen.cpp
@@ -529,10 +529,10 @@ void ScreenPrinter::draw_scenario_screen()
} else if (curmsg->recv_response) {
if (creationMode == MODE_SERVER) {
buf_len += snprintf(buf + buf_len, bufsiz - buf_len,
- " ----------> %-10d ", curmsg->recv_response);
+ " ----------> %-10s ", curmsg->recv_response);
} else {
buf_len += snprintf(buf + buf_len, bufsiz - buf_len,
- " %10d <---------- ", curmsg->recv_response);
+ " %10s <---------- ", curmsg->recv_response);
}
if (curmsg->start_rtd) {