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) {