Benny, This fix isn't quite enough. My assumption that there'll only be one Contact: header is invalid in some circumstances. As your new WIKI entry says about expiry= appended to Contact: header lines, "This is necessary to support multiple registrations (the same AOR is registered more than once in the server by multiple user agents)...". Also, of course, in NAT situations SIP servers that do this change the internal address (as supplied by the client in the request) to the client's external address in returned Contact: headers. I have started using a test server we have running. This is PortaOne's intended replacement for its aging PortaSIP, which doesn't support buddy registration, etc. Unfortunately it doesn't put out Client: headers so I can't tell much about its origins. I'm guessing this is OpenSER. It has been built with similar bad habits anyway. One of the things I want to use PJSIP for is to build a *clean* TAPI driver. This will require multiple client registrations behind the same NAT. [BTW I'm well aware of sipTAPI and its big red switch re-entrancy problems on multiprocessor/core/hyper-threading machines]. For starters, if there are multiple Contact: headers my previous fix/hack is clearly going to fail anyway so I made this change to that first to do some testing: from: if (expiration == NOEXP) expiration = -1; else if (expiration == 0 && contact_cnt == 1 && contact[0]->expires > 0) expiration = contact[0]->expires; to: if (expiration == NOEXP) expiration = -1; else if (expiration == 0 && contact_cnt > 0 && contact[0]->expires > 0) expiration = contact[0]->expires; The obvious problem with this is that on UNregistration with multiple client registrations present a legitimate value of 0 is not going to be returned to the callback. To test this would actually happen I used two client instances on the same IP address, one using port 5061, the other using 5062. The test was as follows: Register 5061 Register 5062 Unregister 5062 Unregister 5061 As expected, for the 5061 instance the fix works OK since at unregister time it is the only surviving client. Here is what happened on the 5062 instance: (best viewed in an HTML mail reader). REGISTER sip:sip2.xxx.xxx SIP/2.0 Via: SIP/2.0/UDP 192.168.128.10:5062;rport;branch=z9hG4bKPjb0aeca4b2b8040b795865e6f4d32d3bd Max-Forwards: 70 From: <sip:510xxxxxxx@xxxxxxxxxxxx>;tag=abf4fc9416704a948c0833db70d6ab4d To: <sip:510xxxxxxx at sip2.xxx.xxx> Call-ID: 0020823c2db04b868851a9c632b92cb2 CSeq: 18510 REGISTER Contact: <sip:510xxxxxxx at 192.168.128.10:5062;transport=UDP> Expires: 300 Authorization: Digest username="510xxxxxxx", realm="sip2.xxx.xxx", nonce="1209929276:e675cbb3a92c2c28d1e4a47b90992924", uri="sip:sip2.xxx.xxx", response="6e2e85e548b0ea427ef40c588fa9a591", algorithm=MD5 Content-Length: 0 ________________________________ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.128.10:5062;branch=z9hG4bKPjb0aeca4b2b8040b795865e6f4d32d3bd;received=81.xxx.xxx.xxx;rport=5062 Contact: <sip:510xxxxxxx at 81.xxx.xxx.xxx:5061;transport=UDP>;expires=281 Contact: <sip:510xxxxxxx at 81.xxx.xxx.xxx:5062;transport=UDP>;expires=300 To: <sip:510xxxxxxx at sip2.xxx.xxx>;tag=2d6d6560 From: <sip:510xxxxxxx@xxxxxxxxxxxx>;tag=abf4fc9416704a948c0833db70d6ab4d Call-ID: 0020823c2db04b868851a9c632b92cb2 CSeq: 18510 REGISTER Date: Sun, 04 May 2008 19:27:56 GMT Content-Length: 0 20:27:56.912 pjsua_acc.c sip:510xxxxxxx at sip2.xxx.xxx: registration success, status=200 (OK), will re-register in 281 seconds ________________________________ REGISTER sip:sip2.xxx.xxx SIP/2.0 Via: SIP/2.0/UDP 192.168.128.10:5062;rport;branch=z9hG4bKPj48482147229948609ec6b20bad0701ef Max-Forwards: 70 From: <sip:510xxxxxxx@xxxxxxxxxxxx>;tag=7b703bbd3bc547f0b52855ce7027a7cc To: <sip:510xxxxxxx at sip2.xxx.xxx> Call-ID: 0020823c2db04b868851a9c632b92cb2 CSeq: 18512 REGISTER Contact: <sip:510xxxxxxx at 192.168.128.10:5062;transport=UDP> Expires: 0 Authorization: Digest username="510xxxxxxx", realm="sip2.xxx.xxx", nonce="1209929286:881ded53e0bb2f0555ebaeb672b9f5b7", uri="sip:sip2.xxx.xxx", response="f0b6951b81aad73d97b9d0214f7a6ab0", algorithm=MD5 Content-Length: 0 ________________________________ SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.128.10:5062;branch=z9hG4bKPj48482147229948609ec6b20bad0701ef;received=81.xxx.xxx.xxx;rport=5062 Contact: <sip:510xxxxxxx at 81.xxx.xxx.xxx:5061;transport=UDP>;expires=271 To: <sip:510xxxxxxx at sip2.xxx.xxx>;tag=2bdc4e7d From: <sip:510xxxxxxx@xxxxxxxxxxxx>;tag=7b703bbd3bc547f0b52855ce7027a7cc Call-ID: 0020823c2db04b868851a9c632b92cb2 CSeq: 18512 REGISTER Date: Sun, 04 May 2008 19:28:06 GMT Content-Length: 0 20:28:06.881 pjsua_acc.c sip:510xxxxxxx at sip2.xxx.xxx: registration success, status=200 (OK), will re-register in 271 seconds Clearly this is hopeless. After UNregistration we have the client stack in an odd state. While that may be benign, especially if the client then immediately terminates, obviously after the registration of 5062 it's re-registration timer is wrong since it has got the time remaining until 5061 expires. In the example above this wouldn't matter much but it's clearly going to cause all sorts of problems in the real world. So ... attached is a much better solution that handles multiple client registrations and should not break anything. You'll find a comment at the top and all changes are comment bracketed throughout. This approach relies on timing the transaction latency and deducting it from the client's requested expiry time if and only if all attempts to parse a returned Expires: header and match Contact: headers has failed. Again, please remember I have only been working with PJSIP code for three days so please scrutinize carefully. Note in particular that I have extended the opaque pjsip__regc structure and explicitly set the expires member on initialization. Having chased down all references to this as best I can, as far as I can see this should be fine. Let me know what you think. I guess I'd better learn how to get to SVN, any advice for a Wintel coder new to all this appreciated. Best Regards, Alan. -----Original Message----- From: pjsip-bounces@xxxxxxxxxxxxxxx [mailto:pjsip-bounces at lists.pjsip.org] On Behalf Of Benny Prijono Sent: 04 May 2008 13:07 To: pjsip list Subject: Re: Parsing expires from REGISTER reply Hi Alan, First of all, I think this issue has come up several times on this list, so I've just added this entry in the FAQ to explain the rationale why PJSIP behaves this way, and also few solutions to cope with it: http://trac.pjsip.org/repos/wiki/FAQ#regc I do like your solution. And while this is server problem (regardless of how popular it is; if it's broken, then it needs to be fixed, IMO), in the SVN trunk we already have couple of settings to deal with this, so if we want to handle this, why not go all the way. So I've just added the trick (to get the expiration value from the single Contact, if Expires header is not present) in the latest SVN version. Thanks for the suggestion. Now enjoy the bank holiday. :) Cheers Benny <snip> -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/attachments/20080505/aa1ace07/attachment-0001.html -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: sip_reg.c Url: http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/attachments/20080505/aa1ace07/attachment-0001.c