thanks for this great detail in providing a patch from another SIPp branch. I integrated everything but without committing the changes.
I still have a question, maybe for the users of SIPp. When a timeout occurs with an "ontimeout" attribute, SIPp jumps to the the next statement in the scenario or to the "ontimeout" label if it is defined.
I would rather have (because SIPp is a test tool) marked the call as "failed" because of a timeout. I think I will make that optional. But before adding the option, I'm wondering if the users think that the default should be:
- Mark the call as failed on timeout and close the call (CANCEL or BYE)
- Leave it as it is
Thanks again Peter, yet another useful feature.
Olivier.
Hi Olivier – here you go with the code changes you asked for:
For completeness, this is the spec:
Added timeout="milliseconds" as a recv (and recvCmd) option. This sets a time limit on how long to wait for a received message. (Note that if you have optional receives in a sequence, the timeout needs to be set on every one, not just the last. The times may be additive.)
Added as an option to timeout for recv, recvCmd and send (with retrans) to allow control of the flow on timeout rather than just dropping through to the next statement.
Added optional="global" as a new option and changed the meaning of optional="true" to be limited to a consecutive sequence of receives.
And this was the further discussion on the last item:
On the last I thought I had sent a separate email. I discovered that in process_incomming() the code section headed /* Try to find it in the old non-mandatory receptions */ looks backwards without limit. We were working on some very long scenarios at the time with lots of optional receives and until I looked at the code I believed that an optional receive had to be part of the immediate receive block. So I decided to change optional="true" to search only as far as the next non-receive and have optional="global" incase we actually needed the original behaviour. (Clearly you could keep optional="true" and add optional="local" if you thought the existing code was correct.)
OJ>>Hmmm. I must have missed the email. Clearly, the current behaviour is not expected (pessimist programmers or even testers might call this a bug :) ). I also thought that the optional="true" was local. I think that optional="global" (the current behavior) should not be kept. Ok, I'm up for those changes too :)
(Note originally I had another item, but when I looked further, I discovered that the public code already has an equivalent change.)
Line numbers refer to the sipp_2006_07_11 version.
The first set of changes is to scenario.hpp/cpp to implement the new options:
In scenario.hpp, add these defines after the existing ones, say at line 53.
#define OPTIONAL_TRUE 1
#define OPTIONAL_FALSE 0
#define OPTIONAL_GLOBAL 2
#define MAX_LABELS 20
Later (line 81) in the message class, change the definition of optional to int:
int optional;
In the "anyway" section (line 89), add:
unsigned int on_timeout;
At the end (line 150), change the labelArray declaration to this line:
extern unsigned int labelArray[MAX_LABELS];
Notes on the above: 1) I maybe should have used an enum for optional. 2) I re-used the send variable retrans_delay for receive as well – probably worth a comment. 3) I actually have MAX_LABELS set to 100 on my system because I needed more labels.
In scenario.cpp (line 56) add a line to initialize on_timeout:
>
In scenario.cpp load_scenario(), in the recv decode, replace the current optional test (lines 328-333) by this one and add the timeout decode:
if (0 != (ptr = xp_get_value((char *)"optional"))) {
if(!strcmp(ptr, "true")) {
scenario[scenario_len] -> optional = OPTIONAL_TRUE;
++recv_opt_count;
}
if(!strcmp(ptr, "global")) {
scenario[scenario_len] -> optional = OPTIONAL_GLOBAL;
++recv_opt_count;
}
}
if (0 != (ptr = xp_get_value((char *)"timeout"))) {
scenario[scenario_len]->retrans_delay = atol(ptr);
}
Later, in the generic section at the end (line 494), add this code:
if (0 != (ptr = xp_get_value((char *)"ontimeout")) ) {
if ((::scenario[scenario_len]-> >= MAX_LABELS) {
ERROR_P1("Ontimeout label larger than max supported %d", MAX_LABELS-1);
}
}
Note with the above code "ontimeout" will be accepted in any scenario command – it is only implemented with send, recv and recvCmd though.
Currently if you next to an undefined label, you go to scenario line 0 – some would call that a bug. The current code has no test that all used labels are defined, that labels are defined only once, etc. For the purpose of keeping this change simple, I have left my fixes for these out because they involve several changes to other existing bits of code.
There is also a bug fix that you need here, replace line 495 (was scenario_len++;) by this test:
if (++scenario_len >= SCEN_MAX_MESSAGES) {
ERROR("Too many items in xml scenario file");
}
Otherwise too long scenario files seg fault.
In call.cpp we need to implement these things, I'll do them by function rather than position in the file:
In the retransmit code, where we detect too many retransmissions, we need to test for "ontimeout" being set. So between lines 1126 and 1127, which are:
scenario[last_send_index] -> nb_timeout ++;
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
Insert this new code:
if (scenario[last_send_index]->on_timeout) { // action on timeout
msg_index = labelArray[scenario[last_send_index]->on_timeout];
next_retrans = 0;
WARNING_P2("Step call %ld to state %d on timeout",m_number,msg_index);
recv_timeout = 0;
if (msg_index < scenario_len) return true;
// here if asked to go to the last label – delete the call
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
delete_call(id);
return false;
}
Note the code I have is not exactly as above – I just drop through for the last label case. However the public code has the "default_behavior" logic and I think you don't want default behaviour if you explicitly asked to go to a label that does nothing.
In the periodic scan, we need to implement the receive timeout code. So near the very end of run(), change line 1304 from
}
to:
} else if (scenario[msg_index]->M_type == MSG_TYPE_RECV
#ifdef __3PCC__
|| scenario[msg_index]->M_type == MSG_TYPE_RECVCMD
#endif
) {
if (recv_timeout) {
if(recv_timeout > clock_tick || recv_timeout > getmilliseconds()) {
return true;
}
recv_timeout = 0;
++scenario[msg_index]->nb_timeout;
if (scenario[msg_index]-> 0) {
// if you set a timeout but not a label you drop through to the next scenario line
return next();
}
msg_index = labelArray[scenario[msg_index]->on_timeout];
recv_timeout = 0;
WARNING_P2("Step call %ld to state %d on recv timeout",m_number,msg_index);
if (msg_index < scenario_len) return true;
// special case - the label points to the end - finish the call
CStat::instance()->computeStat(CStat::E_CALL_FAILED);
delete_call();
return false;
} else if (scenario[msg_index]->retrans_delay) {
recv_timeout = getmilliseconds() + scenario[msg_index]->retrans_delay;
return true;
}
}
Just to check – the next line is:
return true;
Again my code is different because I use a switch rather than an if(){ } else if () { } chain. Note the way the above works is that on the call to run() on entering receive mode it starts the timeout and on following scans it checks for timeout expiry.
There are a few things you need to do to add recv_timeout to the class, etc.
Define it in call.hpp:
unsigned int recv_timeout;
Initialize it,
recv_timeout(0),
and clear it when we do a next():
recv_timeout = 0;
Note it was also cleared in the transmit "ontimeout" above. I could not find any other cases that the public code jumps about the scenario without going through next() – if there are then they also need to clear recv_timeout.
Next we need to implement the optional="global" or optional="true" stuff. The current code at call.cpp line 2355 is:
/* Try to find it in the old non-mandatory receptions */
if(!found) {
for(search_index = msg_index - 1;
search_index >= 0;
search_index--) {
if(MATCHES_SCENARIO(search_index)) {
if ((scenario[search_index] -> optional)) {
found = true;
break;
Change it to this:
/* Try to find it in the old non-mandatory receptions */
if(!found) {
bool contig = true;
for(search_index = msg_index - 1;
search_index >= 0;
search_index--) {
if (scenario[search_index]->optional == OPTIONAL_FALSE) contig = false;
if(MATCHES_SCENARIO(search_index) &&
(contig || scenario[search_index]->optional == OPTIONAL_GLOBAL)) {
found = true;
break;
I think that's everything. Let me know of any problems or questions.
---------------
This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and delete this e-mail. Any unauthorized copying, disclosure or distribution of the contents in this e-mail is strictly forbidden.
---------------
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sipp-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sipp-users
--
HP OpenCall Software
http://www.hp.com/go/opencall/
------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________ Sipp-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sipp-users
