I have below question on behavior of SIP Core in SIP communication.
Suppose party A calling party B. B receives INVITE and generates a '200 OK'. After generating '200 OK', B reaches the terminating state (SIP State Machine) and consequently there is no state machine in B.
Now if '200 OK' does not reach A, B is suppose to re-transmit '200 OK' as it has not receive ACK. RFC 3261 says it is SIP Core responsibility to re-transmit the '200 OK'.
So what is trigger in B's SIP core to send this re-transmit? Does it maintains any timers? Or is it implementation dependent?
Regards,
Sudhansu
The restransmission of 2xx from B is explained in Section 13.3.1.4 The INVITE is Accepted
The exact text is this one:
The 2xx response is passed to the transport with an
interval that starts at T1 seconds and doubles for each
retransmission until it reaches T2 seconds (T1 and T2 are defined in
Section 17). Response retransmissions cease when an ACK request for
the response is received.
The end of retransmission is explained after:
If the server retransmits the 2xx response for 64*T1 seconds without
receiving an ACK, the dialog is confirmed, but the session SHOULD be
terminated. This is accomplished with a BYE, as described in Section
15.
This means that the application layer (ie: not the transaction layer)
needs to manage the timers.
The timers T1 and T2 are defined in table 4: A Table of Timer Values.
T1 500ms default Section 17.1.1.1 RTT Estimate
T2 4s Section 17.1.2.2 The maximum retransmit
interval for non-INVITE
requests and INVITE
responses
T4 5s Section 17.1.2.2 Maximum duration a
message will
remain in the network
Is it allowed to modify the T1, T2 and T4 values. However, in theory, for usual Internet, they shouldn't be changed.
For example, if all ACK are lost, the retransmission would be made within those intervals:
500ms
1s
2s
4s
4s
4s
4s
...
until total is 64*T1 = 32 seconds
Related
I'm using 0MQ to let multiple processes talk to each other (IPC sockets, but should also work via TCP across different nodes). My code is similar to a client/server pattern, but REQ/REP sockets are not enough. Here is a sample conversation. See below for further details.
Process A
Process B
open socket
not started
start process B
-
-
open socket, connect to A
-
send hello (successful start, socket information)
request work
-
-
do work
-
send response (work result 1)
-
send response (work result 2)
-
send unsolicited message
-
send response (work finished)
request termination
-
Actually, A is (even though doing all the requests) closer to be the server component, since it is constantly running. Based on external triggers, A starts a sort of plugin process B.
Every request needs to be answered by a finished response. Before that, N (between 0 and an arbitrary upper bound) responses can be sent from B.
A new request can be sent from A even when the current request is still ongoing (no finished message received). If relevant, the code could be updated to buffer the requests.
B sends an initial message which is not preceded by a request from A.
B can send other messages (logging) anywhere in between, also not preceded by a request.
Optional: A single socket in A should handle multiple plugin processes B, C, D...
A DEALER/ROUTER combination would probably match all requirements, but might be a bit too much. Process B will only ever connect to a single peer. And without the optional requirement above, the same would be true for process A as well. So I'm a bit hesitant to use DEALER and ROUTER sockets which are both able to handle multiple peers.
Consider this sample SIP dialog
A-->--INVITE-->--B CSeq 101
A--<--TRYING--<--B CSeq 101
A--<--200 OK--<--B CSeq 101
A-->-- ACK -->--B CSeq 101
A-->-- INFO -->--B CSeq 2
A--<-- 500 --<--B CSeq 2
...
While working on a SIP handling code, we put a validation for CSeq of a SIP INFO message for a dialog to be greater than the one sent for the INVITE.
However, as shown in the above SIP flow, one of the remote SIP gateways is sending it to be lower, ie 2 instead of the expected 102 or higher.
The RFC https://www.ietf.org/rfc/rfc3261.txt states that
Requests within a dialog MUST contain strictly monotonically
increasing and contiguous CSeq sequence numbers (increasing-by-one) in
each direction
So, is the observed behavior a violation of the RFC?
Yes, it is. You paraphrased the correct text.
The RFC on SIP INFO messages states CSeq header values follow the mechanism in RFC3261:
The Info Package mechanism does not define a delivery order
mechanism. Info Packages can rely on the CSeq header field [RFC3261]
to detect if an INFO request is received out of order.
However, keep in mind you can't rely on the received CSeq number being only one higher than the previously received one (https://www.rfc-editor.org/rfc/rfc3261#section-12.2.2):
It is possible for the
CSeq sequence number to be higher than the remote sequence number by
more than one. This is not an error condition, and a UAS SHOULD be
prepared to receive and process requests with CSeq values more than
one higher than the previous received request. The UAS MUST then set
the remote sequence number to the value of the sequence number in the
CSeq header field value in the request.
If a proxy challenges a request generated by the UAC, the UAC has
to resubmit the request with credentials. The resubmitted request
will have a new CSeq number. The UAS will never see the first
request, and thus, it will notice a gap in the CSeq number space.
Such a gap does not represent any error condition.
I am reading "UNIX Network Programming: The Sockets API" and it mentions that SCTP does not require a TIME_WAIT state as TCP does due to its use of verification tags. Why is this the case? I understand why verification tags fix the issue with duplicate packets, since the receiver can determine whether a packet is part of the current SCTP association or not, but surely the final SCTP SHUTDOWN-COMPLETE packet can be lost just as the final ACK in TCP can be lost, so the peer performing the active close still has to maintain some sort of state to handle this event just as with TCP.
There is no need to maintain state information in this case. RFC 4960 defines a sort of default handling for unknown (out of the blue) packets.
Let’s say, you have two sides in your association: side A and side B. v1/v2 are verification tags used by these sides.
Side A initiated shutdown.
`
A B
Shutdown(v1)
-------------------->
Shutdown_ack(v2)
<--------------------
Shutdown_complete(v1)
-------------------->
`
When side A sends SHUTDOWN COMPLETE it deallocates all the resources used by this association. As far as side A concerns the association is gone.
If for some reasons SHUTDOWN COMPLETE chunk has been lost, side B will re-transmit SHUTDOWN ACK chunk after t2 timer (RFC 4960 term) expiration.
When side A receives this retransmitted SHUTDOWN ACK chunk, it will not be able to determinate to which association it belongs, because that association has already been closed. So, side A will treat this packet as “out of the blue”. RFC 4960 chapter 8.4 describes how to handle out of the blue packet, bullet #5 describes how to handle “out of the blue” SHUTDOWN ACK.
In this case side A will reply with SHUTDOWN COMPLETE. However, packet that carries SHUTDOWN COMPLETE chunk will be slightly different from the original one. The new packet will have t-bit set to 1 and contain what is called reflected verification tag (which is just verification tag from the packet that contained SHUTDOWN ACK).
A B Shutdown(v1) --------------------> Shutdown_ack(v2) <-------------------- Shutdown_complete(v1) -------LOST-------- Shutdown_ack(v2) <-------------------- Shutdown_complete(v2), t-bit=1 -------------------->
Side B knows how to handle packet with t-bit set to 1 and process SHUTDOWN COMPLETE.
As far as you can see, side A does not keep any state information once it sent SHUTDOWN COMPLETE. If any packets belong to this association arrives after that, they will be treated as “out of the blue”.
I have a Kamailio 4.0.4 proxy (K) running registrar and tm. There are multiple clients for some AORs and they all auto-accept certain INVITEs which is causing a race condition and having 200 OKs from multiple branches being sent to the callee.
Scenario:
- A sends invite to B
K finds 2 contacts in the uloc for B, let's call them B1 & B2
INVITE is branched and sent to B1 and B2
Note: B1 has a link latency of 100ms and B2 latency of 150ms
Both B1 and B2 auto-accept with 200 OK instantly as they get it
200ms after branching INVITE, K gets 200 OK from B1 and relays it to A
K also CANCELs the INVITE to B2
A is actually a local AS which ACKs the 200 OK back to B1 instantly
Now the problem is that B2 already sent a 200 OK 50ms ago and won't be receiving the CANCEL for another 150ms
So the 200 OK from B2 comes to K but the call is already setup between A and B1
What happens is that the 200 OK is relayed to A which at this point gets utterly confused because it's not a very good AS to be honest.
Now to the actual question, how do I stop the extra 200 OK from going to A?
I can see a few options of how it should work:
Drop the 200 OK, just throw it away. B2 should not resend it because the CANCEL will hit it soon
ACK + BYE the 200 OK from inside Kamailio, but this will result in a media session being brought up and torn down immediately by B2
I can't even find an RFC covering this race condition..
IIRC, according to the rfc, the 200ok responses have to be always forwarded, being the decision of caller to pick one and send a ACK+BYE for the other.
The easy solution with kamailio is to drop any 200ok once you got one. The callee might not stop resending it even when a CANCEL arrives, will wait for ACK and eventually BYE.
TM module will always forward the 200ok, as per rfc. If you want to drop in kamailio.cfg, a possible solution:
use reply_route { ... } block to intercept 200ok for invite
use htable to store when first 200ok is received (the key can be call-id)
use cfgutils to get locks that will protect against races to access/update the htable
processing logic: if it is a 200ok for INVITE, lock for htable, check if there is a key for that callid. If yes, unlock and drop. If not, add an item with call-id as a key, unlock and let the response go on
If client socket sends:
Packet A - dropped
Packet B
Packet C
Will server socket receive and queue B and C and then when A is received B and C will be passed to the server application immediately? Or B and C will be resent too? Or no packets will be sent at all until A is delivered?
TCP is a sophisticated protocol that changes many parameters depending on the current network state, there are whole books written about the subject. The clearest way to answer your question is to say that TCP generally maintains a given send 'window' size in bytes. This is the amount of data that will be sent until previously sent acknowledgments are successfully returned.
In older TCP specifications a dropped packet within that window would result in a complete resend of data from the dropped packet onwards. To solve this problem as it's obviously a little wasteful, TCP now employs a selective acknowledgment (SACK) option (RFC 2018). This would result in just the lost/corrupted packet being resent.
Back to your example, assuming the window size is large enough to encompass all three packets, and providing you are taking advantage of the latest TCP standard (don't see why you wouldn't), if packet A were dropped only packet A would be resent. If all packets are individually larger than the window then the packets must be sent and acknowledged sequentially.
It depends on the latencies. In general, first A is resent. If the client gets it and already has B and C, it can acknowledge them as well.
If this happens fast enough, B and C won't be resent, or maybe only B.