Fixed issues in creating and subsequently using correctly unique
[opal.git] / src / sip / sipep.cxx
bloba6b70a1582efc3a4a6efa6056d2a43203e18d9be
1 /*
2 * sipep.cxx
4 * Session Initiation Protocol endpoint.
6 * Open Phone Abstraction Library (OPAL)
8 * Copyright (c) 2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open Phone Abstraction Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 2.184 2007/09/10 03:15:05 rjongbloed
28 * Fixed issues in creating and subsequently using correctly unique
29 * payload types in OpalMediaFormat instances and transcoders.
31 * Revision 2.183 2007/09/04 05:40:15 rjongbloed
32 * Added OnRegistrationStatus() call back function so can distinguish
33 * between initial registration and refreshes.
35 * Revision 2.182 2007/08/21 03:12:03 csoutheren
36 * Fix problem with From having wrong protocol
38 * Revision 2.181 2007/08/07 19:44:41 dsandras
39 * Fixed typo. Ideally, the NAT binding refresh code should move to
40 * OpalTransportUDP.
42 * Revision 2.180 2007/08/07 17:23:14 hfriederich
43 * Re-enable NAT binding refreshes.
45 * Revision 2.179 2007/07/22 13:02:14 rjongbloed
46 * Cleaned up selection of registered name usage of URL versus host name.
48 * Revision 2.178 2007/07/22 03:25:18 rjongbloed
49 * Assured that if no expiry time is specified for REGISTER, the endpoint default is used.
51 * Revision 2.177 2007/07/05 05:44:16 rjongbloed
52 * Simplified the default local party name, prevents it from ever returning 0.0.0.0 as host.
54 * Revision 2.176 2007/06/30 16:43:47 dsandras
55 * Improved exit sequence.
57 * Revision 2.175 2007/06/29 06:59:58 rjongbloed
58 * Major improvement to the "product info", normalising H.221 and User-Agent mechanisms.
60 * Revision 2.174 2007/06/25 05:16:20 rjongbloed
61 * Changed GetDefaultTransport() so can return multiple transport names eg udp$ AND tcp$.
62 * Changed listener start up so if no transport is mentioned in the "interface" to listen on
63 * then will listen on all transports supplied by GetDefaultTransport()
65 * Revision 2.173 2007/06/10 08:55:13 rjongbloed
66 * Major rework of how SIP utilises sockets, using new "socket bundling" subsystem.
68 * Revision 2.172 2007/05/23 19:58:04 dsandras
69 * Run garbage collector more often.
71 * Revision 2.171 2007/05/22 21:04:49 dsandras
72 * Fixed issue when PTRACING if the transport could not be created.
74 * Revision 2.170 2007/05/21 17:45:11 dsandras
75 * Fixed usage of Register due to recent changes in the API leading to a crash
76 * on exit (when unregistering).
78 * Revision 2.169 2007/05/21 17:34:49 dsandras
79 * Added guard against NULL transport.
81 * Revision 2.168 2007/05/18 00:35:24 csoutheren
82 * Normalise Register functions
83 * Add symbol so applications know about presence of presence :)
85 * Revision 2.167 2007/05/16 10:25:57 dsandras
86 * Fixed previous commit.
88 * Revision 2.166 2007/05/16 01:17:07 csoutheren
89 * Added new files to Windows build
90 * Removed compiler warnings on Windows
91 * Added backwards compatible SIP Register function
93 * Revision 2.165 2007/05/15 20:46:00 dsandras
94 * Added various handlers to manage subscriptions for presence, message
95 * waiting indications, registrations, state publishing,
96 * message conversations, ...
97 * Adds/fixes support for RFC3856, RFC3903, RFC3863, RFC3265, ...
98 * Many improvements over the original SIPInfo code.
99 * Code contributed by NOVACOM (http://www.novacom.be) thanks to
100 * EuroWeb (http://www.euroweb.hu).
102 * Revision 2.164 2007/05/15 07:27:34 csoutheren
103 * Remove deprecated interface to STUN server in H323Endpoint
104 * Change UseNATForIncomingCall to IsRTPNATEnabled
105 * Various cleanups of messy and unused code
107 * Revision 2.163 2007/05/10 04:45:35 csoutheren
108 * Change CSEQ storage to be an atomic integer
109 * Fix hole in transaction mutex handling
111 * Revision 2.162 2007/05/01 05:29:32 csoutheren
112 * Fix problem with bad delete of SIPConnection when transport not available
114 * Revision 2.161 2007/04/21 11:05:56 dsandras
115 * Fixed more interoperability problems due to bugs in Cisco Call Manager.
116 * Do not clear calls if the video transport can not be established.
117 * Only reinitialize the registrar transport if required (STUN is being used
118 * and the public IP address has changed).
120 * Revision 2.160 2007/04/20 07:08:55 rjongbloed
121 * Fixed compiler warning
123 * Revision 2.159 2007/04/18 03:23:51 rjongbloed
124 * Moved large chunk of code from header to source file.
126 * Revision 2.158 2007/04/17 21:49:41 dsandras
127 * Fixed Via field in previous commit.
128 * Make sure the correct port is being used.
129 * Improved FindSIPInfoByDomain.
131 * Revision 2.157 2007/04/15 10:09:15 dsandras
132 * Some systems like CISCO Call Manager do not like having a Contact field in INVITE
133 * PDUs which is different to the one being used in the original REGISTER request.
134 * Added code to use the same Contact field in both cases if we can determine that
135 * we are registered to that specific account and if there is a transport running.
136 * Fixed problem where the SIP connection was not released with a BYE PDU when
137 * the ACK is received while we are already in EstablishedPhase.
139 * Revision 2.156 2007/04/04 02:12:02 rjongbloed
140 * Reviewed and adjusted PTRACE log levels
141 * Now follows 1=error,2=warn,3=info,4+=debug
143 * Revision 2.155 2007/04/03 07:40:24 rjongbloed
144 * Fixed CreateCall usage so correct function (with userData) is called on
145 * incoming connections.
147 * Revision 2.154 2007/03/30 14:45:32 hfriederich
148 * Reorganization of hte way transactions are handled. Delete transactions
149 * in garbage collector when they're terminated. Update destructor code
150 * to improve safe destruction of SIPEndPoint instances.
152 * Revision 2.153 2007/03/29 23:55:46 rjongbloed
153 * Tidied some code when a new connection is created by an endpoint. Now
154 * if someone needs to derive a connection class they can create it without
155 * needing to remember to do any more than the new.
157 * Revision 2.152 2007/03/27 21:51:40 dsandras
158 * Added more PTRACE statements
160 * Revision 2.151 2007/03/27 20:35:30 dsandras
161 * More checks for transport validity.
163 * Revision 2.150 2007/03/27 20:16:23 dsandras
164 * Temporarily removed use of shared transports as it could have unexpected
165 * side effects on the routing of PDUs.
166 * Various fixes on the way SIPInfo objects are being handled. Wait
167 * for transports to be closed before being deleted. Added missing mutexes.
168 * Added garbage collector.
170 * Revision 2.148 2007/03/17 15:00:24 dsandras
171 * Keep the transport open for a longer time when doing text conversations.
173 * Revision 2.147 2007/03/13 21:22:49 dsandras
174 * Take the remote port into account when unregistering.
176 * Revision 2.146 2007/03/10 17:56:58 dsandras
177 * Improved locking.
179 * Revision 2.145 2007/03/01 05:51:07 rjongbloed
180 * Fixed backward compatibility of OnIncomingConnection() virtual
181 * functions on various classes. If an old override returned FALSE
182 * then it will now abort the call as it used to.
184 * Revision 2.144 2007/02/27 21:22:42 dsandras
185 * Added missing locking. Fixes Ekiga report #411438.
187 * Revision 2.143 2007/02/20 07:15:03 csoutheren
188 * Second attempt at sane 180 handling
190 * Revision 2.142 2007/02/19 04:40:23 csoutheren
191 * Don't send multple 100 Trying
192 * Guard against inability to create transports
194 * Revision 2.141 2007/01/24 04:00:57 csoutheren
195 * Arrrghh. Changing OnIncomingConnection turned out to have a lot of side-effects
196 * Added some pure viritual functions to prevent old code from breaking silently
197 * New OpalEndpoint and OpalConnection descendants will need to re-implement
198 * OnIncomingConnection. Sorry :)
200 * Revision 2.140 2007/01/18 04:45:17 csoutheren
201 * Messy, but simple change to add additional options argument to OpalConnection constructor
202 * This allows the provision of non-trivial arguments for connections
204 * Revision 2.139 2007/01/15 22:14:19 dsandras
205 * Added missing mutexes.
207 * Revision 2.138 2007/01/04 22:09:41 dsandras
208 * Make sure we do not strip a > when stripping parameters from the From field
209 * when receiving a MESSAGE.
211 * Revision 2.137 2006/12/18 03:18:42 csoutheren
212 * Messy but simple fixes
213 * - Add access to SIP REGISTER timeout
214 * - Ensure OpalConnection options are correctly progagated
216 * Revision 2.136 2006/12/10 19:16:19 dsandras
217 * Fixed typo.
219 * Revision 2.135 2006/12/10 18:31:17 dsandras
220 * Synced with Phobos.
222 * Revision 2.134 2006/12/08 04:02:51 csoutheren
223 * Applied 1575788 - Fix a crash in ~SIPInfo due to an open transport
224 * Thanks to Drazen Dimoti
226 * Revision 2.133 2006/11/09 18:24:55 hfriederich
227 * Ensures that responses to received INVITE get sent out on the same network interface as where the INVITE was received. Remove cout statement
229 * Revision 2.132 2006/11/06 13:57:40 dsandras
230 * Use readonly locks as suggested by Robert as we are not
231 * writing to the collection. Fixes deadlock on SIP when
232 * reinvite.
234 * Revision 2.131 2006/10/06 09:08:32 dsandras
235 * Added autodetection of the realm from the challenge response.
237 * Revision 2.130 2006/09/28 07:42:18 csoutheren
238 * Merge of useful SRTP implementation
240 * Revision 2.129 2006/08/12 04:20:39 csoutheren
241 * Removed Windows warning and fixed timeout in SIP PING code
243 * Revision 2.128 2006/08/12 04:09:24 csoutheren
244 * Applied 1538497 - Add the PING method
245 * Thanks to Paul Rolland
247 * Revision 2.127 2006/07/29 08:47:34 hfriederich
248 * Abort the authentication process after a given number of unsuccessful authentication attempts to prevent infinite authentication attempts. Use not UINT_MAX as GetExpires() default to fix incorrect detection of registration/unregistration
250 * Revision 2.126 2006/07/14 04:22:43 csoutheren
251 * Applied 1517397 - More Phobos stability fix
252 * Thanks to Dinis Rosario
254 * Revision 2.125 2006/06/10 15:37:33 dsandras
255 * Look for the expires field in the PDU if not present in the contact header.
257 * Revision 2.124 2006/05/30 04:58:06 csoutheren
258 * Added suport for SIP INFO message (untested as yet)
259 * Fixed some issues with SIP state machine on answering calls
260 * Fixed some formatting issues
262 * Revision 2.123 2006/04/30 17:24:40 dsandras
263 * Various clean ups.
265 * Revision 2.122 2006/04/11 21:13:57 dsandras
266 * Modified GetRegisteredPartyName so that the DefaultLocalPartyName can be
267 * used as result if no match is found for the called domain.
269 * Revision 2.121 2006/04/06 20:39:41 dsandras
270 * Keep the same From header when sending authenticated requests than in the
271 * original request. Fixes Ekiga report #336762.
273 * Revision 2.120 2006/03/27 20:28:18 dsandras
274 * Added mutex to fix concurrency issues between OnReceivedPDU which checks
275 * if a connection is in the list, and OnReceivedINVITE, which adds it to the
276 * list. Fixes Ekiga report #334847. Thanks Robert for your input on this!
278 * Revision 2.119 2006/03/23 21:23:08 dsandras
279 * Fixed SIP Options request sent when refreshint NAT bindings.
281 * Revision 2.118 2006/03/19 18:57:06 dsandras
282 * More work on Ekiga report #334999.
284 * Revision 2.117 2006/03/19 18:14:11 dsandras
285 * Removed unused variable.
287 * Revision 2.116 2006/03/19 13:17:15 dsandras
288 * Ignore failures when unregistering and leaving. Fixes Ekiga #334997.
290 * Revision 2.115 2006/03/19 12:32:05 dsandras
291 * RFC3261 says that "CANCEL messages "SHOULD NOT" be sent for anything but INVITE
292 * requests". Fixes Ekiga report #334985.
294 * Revision 2.114 2006/03/19 11:45:48 dsandras
295 * The remote address of the registrar transport might have changed due
296 * to the Via field. This affected unregistering which was reusing
297 * the exact same transport to unregister. Fixed Ekiga report #334999.
299 * Revision 2.113 2006/03/08 20:10:12 dsandras
300 * Fixed logic error when receiving an incomplete MWI NOTIFY PDU.
302 * Revision 2.112 2006/03/08 18:55:04 dsandras
303 * Added missing return TRUE.
305 * Revision 2.111 2006/03/08 18:34:41 dsandras
306 * Added DNS SRV lookup.
308 * Revision 2.110 2006/03/06 22:52:59 csoutheren
309 * Reverted experimental SRV patch due to unintended side effects
311 * Revision 2.109 2006/03/06 19:01:47 dsandras
312 * Allow registering several accounts with the same realm but different
313 * user names to the same provider. Fixed possible crash due to transport
314 * deletion before the transaction is over.
316 * Revision 2.108 2006/03/06 12:56:03 csoutheren
317 * Added experimental support for SIP SRV lookups
319 * Revision 2.107 2006/02/28 19:18:24 dsandras
320 * Reset the expire time to its initial value accepted by the server when
321 * refreshing the registration. Have a default value of 1 for voicemail
322 * notifications.
324 * Revision 2.106 2006/02/14 19:04:07 dsandras
325 * Fixed problem when the voice-message field is not mentionned in the NOTIFY.
327 * Revision 2.105 2006/02/08 04:51:19 csoutheren
328 * Adde trace message when sending 502
330 * Revision 2.104 2006/02/05 22:19:18 dsandras
331 * Only refresh registered accounts. In case of timeout of a previously
332 * registered account, retry regularly.
334 * Revision 2.103 2006/01/31 03:27:19 csoutheren
335 * Removed unused variable
336 * Fixed typo in comparison
338 * Revision 2.102 2006/01/29 21:03:32 dsandras
339 * Removed cout.
341 * Revision 2.101 2006/01/29 20:55:33 dsandras
342 * Allow using a simple username or a fill url when registering.
344 * Revision 2.100 2006/01/29 17:09:48 dsandras
345 * Added guards against timeout of 0 when registering or subscribing.
346 * Make sure activeSIPInfo is empty and destroyed before exiting.
348 * Revision 2.99 2006/01/24 22:24:48 dsandras
349 * Fixed possible bug with wait called on non existing SIPInfo.
351 * Revision 2.98 2006/01/24 19:49:29 dsandras
352 * Simplified code, always recreate the transport.
354 * Revision 2.97 2006/01/14 10:43:06 dsandras
355 * Applied patch from Brian Lu <Brian.Lu _AT_____ sun.com> to allow compilation
356 * with OpenSolaris compiler. Many thanks !!!
358 * Revision 2.96 2006/01/09 12:15:42 csoutheren
359 * Fixed warning under VS.net 2003
361 * Revision 2.95 2006/01/08 21:53:41 dsandras
362 * Changed IsRegistered so that it takes the registration url as argument,
363 * allowing it to work when there are several accounts on the same server.
365 * Revision 2.94 2006/01/08 14:43:47 dsandras
366 * Improved the NAT binding refresh methods so that it works with all endpoint
367 * created transports that require it and so that it can work by sending
368 * SIP Options, or empty SIP requests. More methods can be added later.
370 * Revision 2.93 2006/01/07 18:30:20 dsandras
371 * Further simplification.
373 * Revision 2.92 2006/01/07 18:29:44 dsandras
374 * Fixed exit problems in case of unregistration failure.
376 * Revision 2.91 2006/01/02 11:28:07 dsandras
377 * Some documentation. Various code cleanups to prevent duplicate code.
379 * Revision 2.90 2005/12/20 20:40:47 dsandras
380 * Added missing parameter.
382 * Revision 2.89 2005/12/18 21:06:55 dsandras
383 * Added function to clean up the registrations object. Moved DeleteObjectsToBeRemoved call outside of the loop.
385 * Revision 2.88 2005/12/18 19:18:18 dsandras
386 * Regularly clean activeSIPInfo.
387 * Fixed problem with Register ignoring the timeout parameter.
389 * Revision 2.87 2005/12/17 21:14:12 dsandras
390 * Prevent loop when exiting if unregistration fails forever.
392 * Revision 2.86 2005/12/14 17:59:50 dsandras
393 * Added ForwardConnection executed when the remote asks for a call forwarding.
394 * Similar to what is done in the H.323 part with the method of the same name.
396 * Revision 2.85 2005/12/11 19:14:20 dsandras
397 * Added support for setting a different user name and authentication user name
398 * as required by some providers like digisip.
400 * Revision 2.84 2005/12/11 12:23:37 dsandras
401 * Removed unused variable.
403 * Revision 2.83 2005/12/08 21:14:54 dsandras
404 * Added function allowing to change the nat binding refresh timeout.
406 * Revision 2.82 2005/12/07 12:19:17 dsandras
407 * Improved previous commit.
409 * Revision 2.81 2005/12/07 11:50:46 dsandras
410 * Signal the registration failed in OnAuthenticationRequired with it happens
411 * for a REGISTER or a SUBSCRIBE.
413 * Revision 2.80 2005/12/05 22:20:57 dsandras
414 * Update the transport when the computer is behind NAT, using STUN, the IP
415 * address has changed compared to the original transport and a registration
416 * refresh must occur.
418 * Revision 2.79 2005/12/04 22:08:58 dsandras
419 * Added possibility to provide an expire time when registering, if not
420 * the default expire time for the endpoint will be used.
422 * Revision 2.78 2005/11/30 13:44:20 csoutheren
423 * Removed compile warnings on Windows
425 * Revision 2.77 2005/11/28 19:07:56 dsandras
426 * Moved OnNATTimeout to SIPInfo and use it for active conversations too.
427 * Added E.164 support.
429 * Revision 2.76 2005/11/07 21:44:49 dsandras
430 * Fixed origin of MESSAGE requests. Ignore refreshes for MESSAGE requests.
432 * Revision 2.75 2005/11/04 19:12:30 dsandras
433 * Fixed OnReceivedResponse for MESSAGE PDU's.
435 * Revision 2.74 2005/11/04 13:40:52 dsandras
436 * Initialize localPort (thanks Craig for pointing this)
438 * Revision 2.73 2005/11/02 22:17:56 dsandras
439 * Take the port into account in TransmitSIPInfo. Added missing break statements.
441 * Revision 2.72 2005/10/30 23:01:29 dsandras
442 * Added possibility to have a body for SIPInfo. Moved MESSAGE sending to SIPInfo for more efficiency during conversations.
444 * Revision 2.71 2005/10/30 15:55:55 dsandras
445 * Added more calls to OnMessageFailed().
447 * Revision 2.70 2005/10/22 17:14:44 dsandras
448 * Send an OPTIONS request periodically when STUN is being used to maintain the registrations binding alive.
450 * Revision 2.69 2005/10/22 10:29:29 dsandras
451 * Increased refresh interval.
453 * Revision 2.68 2005/10/20 20:26:22 dsandras
454 * Made the transactions handling thread-safe.
456 * Revision 2.67 2005/10/11 20:53:35 dsandras
457 * Allow the expire field to be outside of the SIPURL formed by the contact field.
459 * Revision 2.66 2005/10/09 20:42:59 dsandras
460 * Creating the connection thread can take more than 200ms. Send a provisional
461 * response before creating it.
463 * Revision 2.65 2005/10/05 20:54:54 dsandras
464 * Simplified some code.
466 * Revision 2.64 2005/10/03 21:46:20 dsandras
467 * Fixed previous commit (sorry).
469 * Revision 2.63 2005/10/03 21:18:55 dsandras
470 * Prevent looping at exit by removing SUBSCRIBE's and failed REGISTER from
471 * the activeSIPInfo.
473 * Revision 2.62 2005/10/02 21:48:40 dsandras
474 * - Use the transport port when STUN is being used when returning the contact address. That allows SIP proxies to regularly ping the UA so that the binding stays alive. As the REGISTER transport stays open, it permits to receive incoming calls when being behind a type of NAT supported by STUN without the need to forward any port (even not the listening port).
475 * - Call OnFailed for other registration failure causes than 4xx.
477 * Revision 2.61 2005/10/02 17:48:15 dsandras
478 * Added function to return the translated contact address of the endpoint.
479 * Fixed GetRegisteredPartyName so that it returns a default SIPURL if we
480 * have no registrations for the given host.
482 * Revision 2.60 2005/10/01 13:19:57 dsandras
483 * Implemented back Blind Transfer.
485 * Revision 2.59 2005/09/27 16:17:36 dsandras
486 * Remove the media streams on transfer.
488 * Revision 2.58 2005/09/21 19:50:30 dsandras
489 * Cleaned code. Make use of the new SIP_PDU function that returns the correct address where to send responses to incoming requests.
491 * Revision 2.57 2005/09/20 17:02:57 dsandras
492 * Adjust via when receiving an incoming request.
494 * Revision 2.56 2005/08/04 17:13:53 dsandras
495 * More implementation of blind transfer.
497 * Revision 2.55 2005/06/02 13:18:02 rjongbloed
498 * Fixed compiler warnings
500 * Revision 2.54 2005/05/25 18:36:07 dsandras
501 * Fixed unregistration of all accounts when exiting.
503 * Revision 2.53 2005/05/23 20:14:00 dsandras
504 * Added preliminary support for basic instant messenging.
506 * Revision 2.52 2005/05/13 12:47:51 dsandras
507 * Instantly remove unregistration from the collection, and do not process
508 * removed SIPInfo objects, thanks to Ted Szoczei.
510 * Revision 2.51 2005/05/12 19:44:12 dsandras
511 * Fixed leak thanks to Ted Szoczei.
513 * Revision 2.50 2005/05/06 07:37:06 csoutheren
514 * Various changed while working with SIP carrier
515 * - remove assumption that authentication realm is a domain name.
516 * - stopped rewrite of "To" field when proxy being used
517 * - fix Contact field in REGISTER to match actual port used when Symmetric NATin use
518 * - lots of formatting changes and cleanups
520 * Revision 2.49 2005/05/04 17:10:42 dsandras
521 * Get rid of the extra parameters in the Via field before using it to change
522 * the transport remote address.
524 * Revision 2.48 2005/05/03 20:42:33 dsandras
525 * Unregister accounts when exiting the program.
527 * Revision 2.47 2005/05/02 19:30:36 dsandras
528 * Do not use the realm in the comparison for the case when none is specified.
530 * Revision 2.46 2005/04/28 20:22:55 dsandras
531 * Applied big sanity patch for SIP thanks to Ted Szoczei <tszoczei@microtronix.ca>.
532 * Thanks a lot!
534 * Revision 2.45 2005/04/28 07:59:37 dsandras
535 * Applied patch from Ted Szoczei to fix problem when answering to PDUs containing
536 * multiple Via fields in the message header. Thanks!
538 * Revision 2.44 2005/04/26 19:50:15 dsandras
539 * Fixed remoteAddress and user parameters in MWIReceived.
540 * Added function to return the number of registered accounts.
542 * Revision 2.43 2005/04/25 21:12:51 dsandras
543 * Use the correct remote address.
545 * Revision 2.42 2005/04/15 10:48:34 dsandras
546 * Allow reading on the transport until there is an EOF or it becomes bad. Fixes interoperability problem with QSC.DE which is sending keep-alive messages, leading to a timeout (transport.good() fails, but the stream is still usable).
548 * Revision 2.41 2005/04/11 10:31:32 dsandras
549 * Cleanups.
551 * Revision 2.40 2005/04/11 10:26:30 dsandras
552 * Added SetUpTransfer similar to the one from in the H.323 part.
554 * Revision 2.39 2005/03/11 18:12:09 dsandras
555 * Added support to specify the realm when registering. That way softphones already know what authentication information to use when required. The realm/domain can also be used in the From field.
557 * Revision 2.38 2005/02/21 12:20:05 rjongbloed
558 * Added new "options list" to the OpalMediaFormat class.
560 * Revision 2.37 2005/02/19 22:48:48 dsandras
561 * Added the possibility to register to several registrars and be able to do authenticated calls to each of them. Added SUBSCRIBE/NOTIFY support for Message Waiting Indications.
563 * Revision 2.36 2005/01/15 23:34:26 dsandras
564 * Applied patch from Ted Szoczei to handle broken incoming connections.
566 * Revision 2.35 2005/01/09 03:42:46 rjongbloed
567 * Fixed warning about unused parameter
569 * Revision 2.34 2004/12/27 22:20:17 dsandras
570 * Added preliminary support for OPTIONS requests sent outside of a connection.
572 * Revision 2.33 2004/12/25 20:45:12 dsandras
573 * Only fail a REGISTER when proxy authentication is required and has already
574 * been done if the credentials are identical. Fixes registration refresh problem
575 * where some registrars request authentication with a new nonce.
577 * Revision 2.32 2004/12/22 18:56:39 dsandras
578 * Ignore ACK's received outside the context of a connection (e.g. when sending a non-2XX answer to an INVITE).
580 * Revision 2.31 2004/12/17 12:06:52 dsandras
581 * Added error code to OnRegistrationFailed. Made Register/Unregister wait until the transaction is over. Fixed Unregister so that the SIPRegister is used as a pointer or the object is deleted at the end of the function and make Opal crash when transactions are cleaned. Reverted part of the patch that was sending authentication again when it had already been done on a Register.
583 * Revision 2.30 2004/12/12 13:42:31 dsandras
584 * - Send back authentication when required when doing a REGISTER as it might be consecutive to an unregister.
585 * - Update the registered variable when unregistering from a SIP registrar.
586 * - Added OnRegistrationFailed () function to indicate when a registration failed. Call that function at various strategic places.
588 * Revision 2.29 2004/10/02 04:30:11 rjongbloed
589 * Added unregister function for SIP registrar
591 * Revision 2.28 2004/08/22 12:27:46 rjongbloed
592 * More work on SIP registration, time to live refresh and deregistration on exit.
594 * Revision 2.27 2004/08/20 12:54:48 rjongbloed
595 * Fixed crash caused by double delete of registration transactions
597 * Revision 2.26 2004/08/18 13:04:56 rjongbloed
598 * Fixed trying to start regitration if have empty string for domain/user
600 * Revision 2.25 2004/08/14 07:56:43 rjongbloed
601 * Major revision to utilise the PSafeCollection classes for the connections and calls.
603 * Revision 2.24 2004/07/11 12:42:13 rjongbloed
604 * Added function on endpoints to get the list of all media formats any
605 * connection the endpoint may create can support.
607 * Revision 2.23 2004/06/05 14:36:32 rjongbloed
608 * Added functions to get registration URL.
609 * Added ability to set proxy bu host/user/password strings.
611 * Revision 2.22 2004/04/26 06:30:35 rjongbloed
612 * Added ability to specify more than one defualt listener for an endpoint,
613 * required by SIP which listens on both UDP and TCP.
615 * Revision 2.21 2004/04/26 05:40:39 rjongbloed
616 * Added RTP statistics callback to SIP
618 * Revision 2.20 2004/04/25 08:46:08 rjongbloed
619 * Fixed GNU compatibility
621 * Revision 2.19 2004/03/29 10:56:31 rjongbloed
622 * Made sure SIP UDP socket is "promiscuous", ie the host/port being sent to may not
623 * be where packets come from.
625 * Revision 2.18 2004/03/14 11:32:20 rjongbloed
626 * Changes to better support SIP proxies.
628 * Revision 2.17 2004/03/14 10:13:04 rjongbloed
629 * Moved transport on SIP top be constructed by endpoint as any transport created on
630 * an endpoint can receive data for any connection.
631 * Changes to REGISTER to support authentication
633 * Revision 2.16 2004/03/14 08:34:10 csoutheren
634 * Added ability to set User-Agent string
636 * Revision 2.15 2004/03/13 06:51:32 rjongbloed
637 * Alllowed for empty "username" in registration
639 * Revision 2.14 2004/03/13 06:32:18 rjongbloed
640 * Fixes for removal of SIP and H.323 subsystems.
641 * More registration work.
643 * Revision 2.13 2004/03/09 12:09:56 rjongbloed
644 * More work on SIP register.
646 * Revision 2.12 2004/02/17 12:41:54 csoutheren
647 * Use correct Contact field when behind NAT
649 * Revision 2.11 2003/12/20 12:21:18 rjongbloed
650 * Applied more enhancements, thank you very much Ted Szoczei
652 * Revision 2.10 2003/03/24 04:32:58 robertj
653 * SIP register must have a server address
655 * Revision 2.9 2003/03/06 03:57:47 robertj
656 * IVR support (work in progress) requiring large changes everywhere.
658 * Revision 2.8 2002/10/09 04:27:44 robertj
659 * Fixed memory leak on error reading PDU, thanks Ted Szoczei
661 * Revision 2.7 2002/09/12 06:58:34 robertj
662 * Removed protocol prefix strings as static members as has problems with
663 * use in DLL environment.
665 * Revision 2.6 2002/07/04 07:41:47 robertj
666 * Fixed memory/thread leak of transports.
668 * Revision 2.5 2002/04/10 03:15:17 robertj
669 * Fixed using incorrect field as default reply address on receiving a respons PDU.
671 * Revision 2.4 2002/04/09 08:04:01 robertj
672 * Fixed typo in previous patch!
674 * Revision 2.3 2002/04/09 07:18:33 robertj
675 * Fixed the default return address for PDU requests not attached to connection.
677 * Revision 2.2 2002/04/05 10:42:04 robertj
678 * Major changes to support transactions (UDP timeouts and retries).
680 * Revision 2.1 2002/02/01 04:53:01 robertj
681 * Added (very primitive!) SIP support.
685 #include <ptlib.h>
686 #include <ptclib/enum.h>
688 #ifdef __GNUC__
689 #pragma implementation "sipep.h"
690 #endif
693 #include <sip/sipep.h>
695 #include <sip/sippdu.h>
696 #include <sip/sipcon.h>
698 #include <opal/manager.h>
699 #include <opal/call.h>
701 #include <sip/handlers.h>
704 #define new PNEW
707 ////////////////////////////////////////////////////////////////////////////
709 SIPEndPoint::SIPEndPoint(OpalManager & mgr)
710 : OpalEndPoint(mgr, "sip", CanTerminateCall),
711 retryTimeoutMin(500), // 0.5 seconds
712 retryTimeoutMax(0, 4), // 4 seconds
713 nonInviteTimeout(0, 16), // 16 seconds
714 pduCleanUpTimeout(0, 5), // 5 seconds
715 inviteTimeout(0, 32), // 32 seconds
716 ackTimeout(0, 32), // 32 seconds
717 registrarTimeToLive(0, 0, 0, 1), // 1 hour
718 notifierTimeToLive(0, 0, 0, 1), // 1 hour
719 natBindingTimeout(0, 0, 1) // 1 minute
721 defaultSignalPort = 5060;
722 mimeForm = FALSE;
723 maxRetries = 10;
724 lastSentCSeq = 0;
726 transactions.DisallowDeleteObjects();
727 activeSIPHandlers.AllowDeleteObjects();
729 natBindingTimer.SetNotifier(PCREATE_NOTIFIER(NATBindingRefresh));
730 natBindingTimer.RunContinuous(natBindingTimeout);
731 garbageTimer.SetNotifier(PCREATE_NOTIFIER(GarbageCollector));
732 garbageTimer.RunContinuous(PTimeInterval(0, 1));
734 natMethod = None;
736 // Make sure these have been contructed now to avoid
737 // payload type disambiguation problems.
738 GetOpalRFC2833();
739 GetOpalCiscoNSE();
741 PTRACE(4, "SIP\tCreated endpoint.");
745 SIPEndPoint::~SIPEndPoint()
747 while (activeSIPHandlers.GetSize()>0) {
748 for (PSafePtr<SIPHandler> handler(activeSIPHandlers, PSafeReadOnly); handler != NULL; ++handler) {
749 PString aor = handler->GetRemotePartyAddress ();
750 if (handler->GetMethod() == SIP_PDU::Method_REGISTER
751 && handler->GetState() == SIPHandler::Subscribed) {
752 Unregister(aor);
754 else {
755 handler->SetState(SIPHandler::Unsubscribed);
756 handler->SetExpire(-1);
760 activeSIPHandlers.DeleteObjectsToBeRemoved();
761 PThread::Current()->Sleep(10); // Let GarbageCollect() do the cleanup
764 for (PINDEX i = 0; i < transactions.GetSize(); i++) {
765 PWaitAndSignal m(transactionsMutex);
766 SIPTransaction *transaction = transactions.GetAt(i);
767 if (transaction)
768 WaitForTransactionCompletion(transaction);
771 // Clean up
772 transactions.RemoveAll();
773 listeners.RemoveAll();
775 // Stop timers before compiler destroys member objects
776 natBindingTimer.Stop();
777 garbageTimer.Stop();
779 PWaitAndSignal m(transactionsMutex);
780 PTRACE(4, "SIP\tDeleted endpoint.");
784 BOOL SIPEndPoint::NewIncomingConnection(OpalTransport * transport)
786 PTRACE_IF(2, transport->IsReliable(), "SIP\tListening thread started.");
788 transport->SetBufferSize(SIP_PDU::MaxSize);
790 do {
791 HandlePDU(*transport);
792 } while (transport->IsOpen() && transport->IsReliable() && !transport->bad() && !transport->eof());
794 PTRACE_IF(2, transport->IsReliable(), "SIP\tListening thread finished.");
796 return TRUE;
800 void SIPEndPoint::TransportThreadMain(PThread &, INT param)
802 PTRACE(4, "SIP\tRead thread started.");
803 OpalTransport * transport = (OpalTransport *)param;
805 do {
806 HandlePDU(*transport);
807 } while (transport->IsOpen() && !transport->bad() && !transport->eof());
809 PTRACE(4, "SIP\tRead thread finished.");
813 void SIPEndPoint::NATBindingRefresh(PTimer &, INT)
815 PTRACE(5, "SIP\tNAT Binding refresh started.");
817 if (natMethod == None)
818 return;
820 for (PSafePtr<SIPHandler> handler(activeSIPHandlers, PSafeReadOnly); handler != NULL; ++handler) {
822 OpalTransport & transport = handler->GetTransport();
823 BOOL stunTransport = FALSE;
825 if (!transport)
826 return;
828 stunTransport = (!transport.IsReliable() && GetManager().GetSTUN(transport.GetRemoteAddress().GetHostName()));
830 if (!stunTransport)
831 return;
833 switch (natMethod) {
835 case Options:
837 PStringList emptyRouteSet;
838 SIPOptions options(*this, transport, SIPURL(transport.GetRemoteAddress()).GetHostName());
839 options.Write(transport, options.GetSendAddress(emptyRouteSet));
841 break;
842 case EmptyRequest:
844 transport.Write("\r\n", 2);
846 break;
847 default:
848 break;
852 PTRACE(5, "SIP\tNAT Binding refresh finished.");
856 void SIPEndPoint::GarbageCollector(PTimer &, INT)
858 for (PINDEX i = activeSIPHandlers.GetSize(); i > 0; i--) {
860 PSafePtr<SIPHandler> handler = activeSIPHandlers.GetAt (i-1, PSafeReadWrite);
861 if (handler->CanBeDeleted()) {
862 activeSIPHandlers.RemoveAt(i-1);
865 activeSIPHandlers.DeleteObjectsToBeRemoved();
867 // Delete terminated transactions
869 PWaitAndSignal m(completedTransactionsMutex);
871 for (PINDEX i = completedTransactions.GetSize(); i > 0; i--) {
872 SIPTransaction & transaction = completedTransactions[i-1];
874 if (transaction.IsTerminated()) {
875 completedTransactions.RemoveAt(i-1);
884 OpalTransport * SIPEndPoint::CreateTransport(const OpalTransportAddress & remoteAddress,
885 const OpalTransportAddress & localAddress)
887 OpalTransport * transport = NULL;
889 for (PINDEX i = 0; i < listeners.GetSize(); i++) {
890 OpalTransportAddress binding = listeners[i].GetLocalAddress();
891 if (binding.Left(binding.Find('$')) *= remoteAddress.Left(remoteAddress.Find('$'))) {
892 transport = listeners[i].CreateTransport(localAddress);
893 break;
897 if (transport == NULL) {
898 // No compatible listeners, can't use their binding
899 transport = remoteAddress.CreateTransport(*this, OpalTransportAddress::NoBinding);
900 if(transport == NULL) {
901 PTRACE(1, "SIP\tCould not create transport for " << remoteAddress);
902 return NULL;
906 transport->SetRemoteAddress(remoteAddress);
907 PTRACE(4, "SIP\tCreated transport " << *transport);
909 transport->SetBufferSize(SIP_PDU::MaxSize);
910 if (!transport->ConnectTo(remoteAddress)) {
911 PTRACE(1, "SIP\tCould not connect to " << remoteAddress << " - " << transport->GetErrorText());
912 transport->CloseWait();
913 delete transport;
914 return NULL;
917 transport->SetPromiscuous(OpalTransport::AcceptFromAny);
919 if (transport->IsReliable())
920 transport->AttachThread(PThread::Create(PCREATE_NOTIFIER(TransportThreadMain),
921 (INT)transport,
922 PThread::NoAutoDeleteThread,
923 PThread::NormalPriority,
924 "SIP Transport:%x"));
925 return transport;
929 void SIPEndPoint::HandlePDU(OpalTransport & transport)
931 // create a SIP_PDU structure, then get it to read and process PDU
932 SIP_PDU * pdu = new SIP_PDU;
934 PTRACE(4, "SIP\tWaiting for PDU on " << transport);
935 if (pdu->Read(transport)) {
936 if (OnReceivedPDU(transport, pdu))
937 return;
939 else if (transport.good()) {
940 PTRACE(2, "SIP\tMalformed request received on " << transport);
941 SendResponse(SIP_PDU::Failure_BadRequest, transport, *pdu);
944 delete pdu;
948 BOOL SIPEndPoint::MakeConnection(OpalCall & call,
949 const PString & _remoteParty,
950 void * userData,
951 unsigned int options,
952 OpalConnection::StringOptions * stringOptions)
954 PString remoteParty;
956 if (_remoteParty.Find("sip:") != 0)
957 return FALSE;
959 ParsePartyName(_remoteParty, remoteParty);
961 PStringStream callID;
962 OpalGloballyUniqueID id;
963 callID << id << '@' << PIPSocket::GetHostName();
964 SIPConnection * connection = CreateConnection(call, callID, userData, remoteParty, NULL, NULL, options, stringOptions);
965 if (!AddConnection(connection))
966 return FALSE;
968 // If we are the A-party then need to initiate a call now in this thread. If
969 // we are the B-Party then SetUpConnection() gets called in the context of
970 // the A-party thread.
971 if (call.GetConnection(0) == (OpalConnection*)connection)
972 connection->SetUpConnection();
974 return TRUE;
978 OpalMediaFormatList SIPEndPoint::GetMediaFormats() const
980 return OpalMediaFormat::GetAllRegisteredMediaFormats();
984 BOOL SIPEndPoint::IsAcceptedAddress(const SIPURL & /*toAddr*/)
986 return TRUE;
990 SIPConnection * SIPEndPoint::CreateConnection(OpalCall & call,
991 const PString & token,
992 void * /*userData*/,
993 const SIPURL & destination,
994 OpalTransport * transport,
995 SIP_PDU * /*invite*/,
996 unsigned int options,
997 OpalConnection::StringOptions * stringOptions)
999 return new SIPConnection(call, *this, token, destination, transport, options, stringOptions);
1003 BOOL SIPEndPoint::SetupTransfer(const PString & token,
1004 const PString & /*callIdentity*/,
1005 const PString & _remoteParty,
1006 void * userData)
1008 PString remoteParty;
1009 // Make a new connection
1010 PSafePtr<OpalConnection> otherConnection =
1011 GetConnectionWithLock(token, PSafeReference);
1012 if (otherConnection == NULL) {
1013 return FALSE;
1016 OpalCall & call = otherConnection->GetCall();
1018 call.RemoveMediaStreams();
1020 ParsePartyName(_remoteParty, remoteParty);
1022 PStringStream callID;
1023 OpalGloballyUniqueID id;
1024 callID << id << '@' << PIPSocket::GetHostName();
1025 SIPConnection * connection = CreateConnection(call, callID, userData, remoteParty, NULL, NULL);
1026 if (!AddConnection(connection))
1027 return FALSE;
1029 call.OnReleased(*otherConnection);
1031 connection->SetUpConnection();
1032 otherConnection->Release(OpalConnection::EndedByCallForwarded);
1034 return TRUE;
1038 BOOL SIPEndPoint::ForwardConnection(SIPConnection & connection,
1039 const PString & forwardParty)
1041 OpalCall & call = connection.GetCall();
1043 PStringStream callID;
1044 OpalGloballyUniqueID id;
1045 callID << id << '@' << PIPSocket::GetHostName();
1047 SIPConnection * conn = CreateConnection(call, callID, NULL, forwardParty, NULL, NULL);
1048 if (!AddConnection(conn))
1049 return FALSE;
1051 call.OnReleased(connection);
1053 conn->SetUpConnection();
1054 connection.Release(OpalConnection::EndedByCallForwarded);
1056 return TRUE;
1059 BOOL SIPEndPoint::OnReceivedPDU(OpalTransport & transport, SIP_PDU * pdu)
1061 // Adjust the Via list
1062 if (pdu && pdu->GetMethod() != SIP_PDU::NumMethods)
1063 pdu->AdjustVia(transport);
1065 // Find a corresponding connection
1066 PSafePtr<SIPConnection> connection = GetSIPConnectionWithLock(pdu->GetMIME().GetCallID(), PSafeReadOnly);
1067 if (connection != NULL) {
1068 connection->QueuePDU(pdu);
1069 return TRUE;
1072 switch (pdu->GetMethod()) {
1073 case SIP_PDU::NumMethods :
1075 PWaitAndSignal m(transactionsMutex);
1076 SIPTransaction * transaction = transactions.GetAt(pdu->GetTransactionID());
1077 if (transaction != NULL)
1078 transaction->OnReceivedResponse(*pdu);
1080 break;
1082 case SIP_PDU::Method_INVITE :
1083 return OnReceivedINVITE(transport, pdu);
1085 case SIP_PDU::Method_REGISTER :
1086 case SIP_PDU::Method_SUBSCRIBE :
1088 SendResponse(SIP_PDU::Failure_MethodNotAllowed, transport, *pdu);
1089 break;
1092 case SIP_PDU::Method_NOTIFY :
1093 return OnReceivedNOTIFY(transport, *pdu);
1094 break;
1096 case SIP_PDU::Method_MESSAGE :
1098 OnReceivedMESSAGE(transport, *pdu);
1099 SendResponse(SIP_PDU::Successful_OK, transport, *pdu);
1100 break;
1103 case SIP_PDU::Method_OPTIONS :
1105 SendResponse(SIP_PDU::Successful_OK, transport, *pdu);
1106 break;
1108 case SIP_PDU::Method_ACK :
1110 // If we receive an ACK outside of the context of a connection,
1111 // ignore it.
1113 break;
1115 default :
1117 SendResponse(SIP_PDU::Failure_TransactionDoesNotExist, transport, *pdu);
1121 return FALSE;
1125 void SIPEndPoint::OnReceivedResponse(SIPTransaction & transaction, SIP_PDU & response)
1127 PSafePtr<SIPHandler> handler = NULL;
1129 if (transaction.GetMethod() == SIP_PDU::Method_REGISTER
1130 || transaction.GetMethod() == SIP_PDU::Method_SUBSCRIBE
1131 || transaction.GetMethod() == SIP_PDU::Method_PUBLISH
1132 || transaction.GetMethod() == SIP_PDU::Method_MESSAGE) {
1134 PString callID = transaction.GetMIME().GetCallID ();
1136 // Have a response to the REGISTER/SUBSCRIBE/MESSAGE,
1137 handler = activeSIPHandlers.FindSIPHandlerByCallID (callID, PSafeReadOnly);
1138 if (handler == NULL)
1139 return;
1142 switch (response.GetStatusCode()) {
1143 case SIP_PDU::Failure_UnAuthorised :
1144 case SIP_PDU::Failure_ProxyAuthenticationRequired :
1145 OnReceivedAuthenticationRequired(transaction, response);
1146 break;
1147 case SIP_PDU::Failure_RequestTimeout :
1148 if (handler != NULL) {
1149 handler->OnTransactionTimeout(transaction);
1151 break;
1153 default :
1154 switch (response.GetStatusCode()/100) {
1155 case 1 :
1156 // Do nothing on 1xx
1157 break;
1158 case 2 :
1159 OnReceivedOK(transaction, response);
1160 break;
1161 default :
1162 if (handler != NULL) {
1163 // Failure for a SUBSCRIBE/REGISTER/PUBLISH/MESSAGE
1164 handler->OnFailed (response.GetStatusCode());
1171 BOOL SIPEndPoint::OnReceivedINVITE(OpalTransport & transport, SIP_PDU * request)
1173 SIPMIMEInfo & mime = request->GetMIME();
1175 // parse the incoming To field, and check if we accept incoming calls for this address
1176 SIPURL toAddr(mime.GetTo());
1177 if (!IsAcceptedAddress(toAddr)) {
1178 PTRACE(2, "SIP\tIncoming INVITE from " << request->GetURI() << " for unknown address " << toAddr);
1179 SendResponse(SIP_PDU::Failure_NotFound, transport, *request);
1180 return FALSE;
1183 // send provisional response here because creating the connection can take a long time
1184 // on some systems
1185 SendResponse(SIP_PDU::Information_Trying, transport, *request);
1187 // ask the endpoint for a connection
1188 SIPConnection *connection = CreateConnection(*manager.CreateCall(NULL),
1189 mime.GetCallID(),
1190 NULL,
1191 request->GetURI(),
1192 CreateTransport(transport.GetRemoteAddress(), transport.GetLocalAddress()),
1193 request);
1194 if (!AddConnection(connection)) {
1195 PTRACE(1, "SIP\tFailed to create SIPConnection for INVITE from " << request->GetURI() << " for " << toAddr);
1196 SendResponse(SIP_PDU::Failure_NotFound, transport, *request);
1197 return FALSE;
1200 // Get the connection to handle the rest of the INVITE
1201 connection->QueuePDU(request);
1202 return TRUE;
1206 void SIPEndPoint::OnReceivedAuthenticationRequired(SIPTransaction & transaction, SIP_PDU & response)
1208 PSafePtr<SIPHandler> realm_handler = NULL;
1209 PSafePtr<SIPHandler> callid_handler = NULL;
1210 SIPTransaction * request = NULL;
1211 SIPAuthentication auth;
1213 BOOL isProxy =
1214 response.GetStatusCode() == SIP_PDU::Failure_ProxyAuthenticationRequired;
1215 PString lastNonce;
1216 PString lastUsername;
1218 #if PTRACING
1219 const char * proxyTrace = isProxy ? "Proxy " : "";
1220 #endif
1221 PTRACE(3, "SIP\tReceived " << proxyTrace << "Authentication Required response");
1223 // Only support REGISTER and SUBSCRIBE for now
1224 if (transaction.GetMethod() != SIP_PDU::Method_REGISTER
1225 && transaction.GetMethod() != SIP_PDU::Method_SUBSCRIBE
1226 && transaction.GetMethod() != SIP_PDU::Method_MESSAGE) {
1227 PTRACE(1, "SIP\tCannot do " << proxyTrace << "Authentication Required for non REGISTER, SUBSCRIBE or MESSAGE");
1228 return;
1231 // Try to find authentication information for the given call ID
1232 callid_handler = activeSIPHandlers.FindSIPHandlerByCallID(response.GetMIME().GetCallID(), PSafeReadOnly);
1234 if (!callid_handler)
1235 return;
1237 // Received authentication required response, try to find authentication
1238 // for the given realm
1239 if (!auth.Parse(response.GetMIME()(isProxy
1240 ? "Proxy-Authenticate"
1241 : "WWW-Authenticate"),
1242 isProxy)) {
1243 callid_handler->OnFailed(SIP_PDU::Failure_UnAuthorised);
1244 return;
1247 // Try to find authentication information for the requested realm
1248 // That realm is specified when registering
1249 realm_handler = activeSIPHandlers.FindSIPHandlerByAuthRealm(auth.GetAuthRealm(), auth.GetUsername().IsEmpty()?SIPURL(response.GetMIME().GetFrom()).GetUserName():auth.GetUsername(), PSafeReadOnly);
1251 // No authentication information found for the realm,
1252 // use what we have for the given CallID
1253 // and update the realm
1254 if (realm_handler == NULL) {
1255 realm_handler = callid_handler;
1256 if (!auth.GetAuthRealm().IsEmpty())
1257 realm_handler->SetAuthRealm(auth.GetAuthRealm());
1258 PTRACE(3, "SIP\tUpdated realm to " << auth.GetAuthRealm());
1261 // No realm handler, weird
1262 if (realm_handler == NULL) {
1263 PTRACE(1, "SIP\tNo Authentication handler found for that realm, authentication impossible");
1264 return;
1267 if (realm_handler->GetAuthentication().IsValid()) {
1268 lastUsername = realm_handler->GetAuthentication().GetUsername();
1269 lastNonce = realm_handler->GetAuthentication().GetNonce();
1272 if (!realm_handler->GetAuthentication().Parse(response.GetMIME()(isProxy
1273 ? "Proxy-Authenticate"
1274 : "WWW-Authenticate"),
1275 isProxy)) {
1276 callid_handler->OnFailed(SIP_PDU::Failure_UnAuthorised);
1277 return;
1280 // Already sent handler for that callID. Check if params are different
1281 // from the ones found for the given realm
1282 if (callid_handler->GetAuthentication().IsValid()
1283 && lastUsername == callid_handler->GetAuthentication().GetUsername ()
1284 && lastNonce == callid_handler->GetAuthentication().GetNonce ()
1285 && callid_handler->GetState() == SIPHandler::Subscribing) {
1286 PTRACE(2, "SIP\tAlready done REGISTER/SUBSCRIBE for " << proxyTrace << "Authentication Required");
1287 callid_handler->OnFailed(SIP_PDU::Failure_UnAuthorised);
1288 return;
1291 // Abort after some unsuccesful authentication attempts. This is required since
1292 // some implementations return "401 Unauthorized" with a different nonce at every
1293 // time.
1294 unsigned authenticationAttempts = callid_handler->GetAuthenticationAttempts();
1295 if(authenticationAttempts < 10) {
1296 authenticationAttempts++;
1297 callid_handler->SetAuthenticationAttempts(authenticationAttempts);
1298 } else {
1299 PTRACE(1, "SIP\tAborting after " << authenticationAttempts << " attempts to REGISTER/SUBSCRIBE");
1300 callid_handler->OnFailed(SIP_PDU::Failure_UnAuthorised);
1301 return;
1304 // Restart the transaction with new authentication handler
1305 request = callid_handler->CreateTransaction(transaction.GetTransport());
1306 if (!realm_handler->GetAuthentication().Authorise(*request)) {
1307 // don't send again if no authentication handler available
1308 delete request;
1309 callid_handler->OnFailed(SIP_PDU::Failure_UnAuthorised);
1310 return;
1312 // Section 8.1.3.5 of RFC3261 tells that the authenticated
1313 // request SHOULD have the same value of the Call-ID, To and From.
1314 request->GetMIME().SetFrom(transaction.GetMIME().GetFrom());
1315 if (!request->Start()) {
1316 delete request;
1317 PTRACE(1, "SIP\tCould not restart REGISTER/SUBSCRIBE for Authentication Required");
1322 void SIPEndPoint::OnReceivedOK(SIPTransaction & /*transaction*/, SIP_PDU & response)
1324 PSafePtr<SIPHandler> handler = NULL;
1326 handler = activeSIPHandlers.FindSIPHandlerByCallID(response.GetMIME().GetCallID(), PSafeReadOnly);
1328 if (handler == NULL)
1329 return;
1331 // reset the number of unsuccesful authentication attempts
1332 handler->SetAuthenticationAttempts(0);
1333 handler->OnReceivedOK(response);
1337 void SIPEndPoint::OnTransactionTimeout(SIPTransaction & transaction)
1339 PSafePtr<SIPHandler> handler = NULL;
1341 handler = activeSIPHandlers.FindSIPHandlerByCallID(transaction.GetMIME().GetCallID(), PSafeReadOnly);
1342 if (handler == NULL)
1343 return;
1345 handler->OnTransactionTimeout(transaction);
1349 BOOL SIPEndPoint::OnReceivedNOTIFY (OpalTransport & transport, SIP_PDU & pdu)
1351 PSafePtr<SIPHandler> handler = NULL;
1352 PCaselessString state;
1353 SIPSubscribe::SubscribeType event;
1355 PTRACE(3, "SIP\tReceived NOTIFY");
1357 if (pdu.GetMIME().GetEvent().Find("message-summary") != P_MAX_INDEX)
1358 event = SIPSubscribe::MessageSummary;
1359 else if (pdu.GetMIME().GetEvent().Find("presence") != P_MAX_INDEX)
1360 event = SIPSubscribe::Presence;
1361 else {
1363 // Only support MWI and presence Subscribe for now,
1364 // other events are unrequested
1365 SendResponse(SIP_PDU::Failure_BadEvent, transport, pdu);
1367 return FALSE;
1371 // A NOTIFY will have the same CallID than the SUBSCRIBE request
1372 // it corresponds to
1373 handler = activeSIPHandlers.FindSIPHandlerByCallID(pdu.GetMIME().GetCallID(), PSafeReadOnly);
1374 if (handler == NULL) {
1376 if (event == SIPSubscribe::Presence) {
1377 PTRACE(3, "SIP\tCould not find a SUBSCRIBE corresponding to the NOTIFY");
1378 SendResponse(SIP_PDU::Failure_TransactionDoesNotExist, transport, pdu);
1379 return FALSE;
1381 if (event == SIPSubscribe::MessageSummary) {
1382 PTRACE(3, "SIP\tCould not find a SUBSCRIBE corresponding to the NOTIFY : Work around Asterisk bug");
1383 SIPURL url_from (pdu.GetMIME().GetFrom());
1384 SIPURL url_to (pdu.GetMIME().GetTo());
1385 PString to = url_to.GetUserName() + "@" + url_from.GetHostName();
1386 handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_SUBSCRIBE, event, PSafeReadOnly);
1387 if (handler == NULL) {
1388 SendResponse(SIP_PDU::Failure_TransactionDoesNotExist, transport, pdu);
1389 return FALSE;
1393 if (!handler->OnReceivedNOTIFY(pdu))
1394 return FALSE;
1396 return TRUE;
1400 void SIPEndPoint::OnReceivedMESSAGE(OpalTransport & /*transport*/,
1401 SIP_PDU & pdu)
1403 PString from = pdu.GetMIME().GetFrom();
1404 PINDEX j = from.Find (';');
1405 if (j != P_MAX_INDEX)
1406 from = from.Left(j); // Remove all parameters
1407 j = from.Find ('<');
1408 if (j != P_MAX_INDEX && from.Find ('>') == P_MAX_INDEX)
1409 from += '>';
1411 OnMessageReceived(from, pdu.GetEntityBody());
1415 void SIPEndPoint::OnRegistrationStatus(const PString & aor,
1416 BOOL wasRegistering,
1417 BOOL /*reRegistering*/,
1418 SIP_PDU::StatusCodes reason)
1420 if (reason == SIP_PDU::Successful_OK)
1421 OnRegistered(aor, wasRegistering);
1422 else
1423 OnRegistrationFailed(aor, reason, wasRegistering);
1427 void SIPEndPoint::OnRegistrationFailed(const PString & /*aor*/,
1428 SIP_PDU::StatusCodes /*reason*/,
1429 BOOL /*wasRegistering*/)
1434 void SIPEndPoint::OnRegistered(const PString & /*aor*/,
1435 BOOL /*wasRegistering*/)
1440 BOOL SIPEndPoint::IsRegistered(const PString & url)
1442 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(url, SIP_PDU::Method_REGISTER, PSafeReadOnly);
1444 if (handler == NULL)
1445 return FALSE;
1447 return (handler->GetState() == SIPHandler::Subscribed);
1451 BOOL SIPEndPoint::IsSubscribed(SIPSubscribe::SubscribeType type,
1452 const PString & to)
1454 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_SUBSCRIBE, type, PSafeReadOnly);
1456 if (handler == NULL)
1457 return FALSE;
1459 return (handler->GetState() == SIPHandler::Subscribed);
1462 BOOL SIPEndPoint::Register(
1463 const PString & host,
1464 const PString & user,
1465 const PString & authName,
1466 const PString & password,
1467 const PString & authRealm,
1468 unsigned expire,
1469 const PTimeInterval & minRetryTime,
1470 const PTimeInterval & maxRetryTime
1473 PString aor;
1474 if (user.Find('@') != P_MAX_INDEX)
1475 aor = user;
1476 else
1477 aor = user + '@' + host;
1479 if (expire == 0)
1480 expire = GetRegistrarTimeToLive().GetSeconds();
1481 return Register(expire, aor, authName, password, authRealm, minRetryTime, maxRetryTime);
1484 BOOL SIPEndPoint::Register(unsigned expire,
1485 const PString & aor,
1486 const PString & authName,
1487 const PString & password,
1488 const PString & realm,
1489 const PTimeInterval & minRetryTime,
1490 const PTimeInterval & maxRetryTime)
1492 PSafePtr<SIPHandler> handler = NULL;
1494 // Create the SIPHandler structure
1495 handler = activeSIPHandlers.FindSIPHandlerByUrl(aor, SIP_PDU::Method_REGISTER, PSafeReadOnly);
1497 // If there is already a request with this URL and method,
1498 // then update it with the new information
1499 if (handler != NULL) {
1500 if (!password.IsEmpty())
1501 handler->SetPassword(password); // Adjust the password if required
1502 if (!realm.IsEmpty())
1503 handler->SetAuthRealm(realm); // Adjust the realm if required
1504 if (!authName.IsEmpty())
1505 handler->SetAuthUser(authName); // Adjust the authUser if required
1506 handler->SetExpire(expire); // Adjust the expire field
1508 // Otherwise create a new request with this method type
1509 else {
1510 handler = CreateRegisterHandler(aor, authName, password, realm, expire, minRetryTime, maxRetryTime);
1511 activeSIPHandlers.Append(handler);
1514 if (!handler->SendRequest()) {
1515 activeSIPHandlers.Remove(handler);
1516 return FALSE;
1519 return TRUE;
1522 SIPRegisterHandler * SIPEndPoint::CreateRegisterHandler(const PString & aor,
1523 const PString & authName,
1524 const PString & password,
1525 const PString & realm,
1526 int expire,
1527 const PTimeInterval & minRetryTime,
1528 const PTimeInterval & maxRetryTime)
1530 return new SIPRegisterHandler(*this, aor, authName, password, realm, expire, minRetryTime, maxRetryTime);
1533 BOOL SIPEndPoint::Unregister(const PString & aor)
1535 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl (aor, SIP_PDU::Method_REGISTER, PSafeReadOnly);
1536 if (handler == NULL) {
1537 PTRACE(1, "SIP\tCould not find active REGISTER for " << aor);
1538 return FALSE;
1541 if (!handler->GetState() == SIPHandler::Subscribed) {
1542 handler->SetExpire(-1);
1543 return FALSE;
1546 return Register(0, aor);
1550 BOOL SIPEndPoint::Subscribe(SIPSubscribe::SubscribeType & type,
1551 unsigned expire,
1552 const PString & to)
1554 // Create the SIPHandler structure
1555 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_SUBSCRIBE, type, PSafeReadOnly);
1557 // If there is already a request with this URL and method,
1558 // then update it with the new information
1559 if (handler != NULL) {
1560 handler->SetExpire(expire); // Adjust the expire field
1562 // Otherwise create a new request with this method type
1563 else {
1564 handler = new SIPSubscribeHandler(*this,
1565 type,
1567 expire);
1568 activeSIPHandlers.Append(handler);
1571 if (!handler->SendRequest()) {
1572 handler->SetExpire(-1);
1573 return FALSE;
1576 return TRUE;
1580 BOOL SIPEndPoint::Unsubscribe(SIPSubscribe::SubscribeType & type,
1581 const PString & to)
1583 // Create the SIPHandler structure
1584 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_SUBSCRIBE, type, PSafeReadOnly);
1586 if (handler == NULL) {
1587 PTRACE(1, "SIP\tCould not find active SUBSCRIBE for " << to);
1588 return FALSE;
1591 if (!handler->GetState() == SIPHandler::Subscribed) {
1592 handler->SetExpire(-1);
1593 return FALSE;
1596 return Subscribe(type, 0, to);
1601 BOOL SIPEndPoint::Message (const PString & to,
1602 const PString & body)
1604 // Create the SIPHandler structure
1605 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_MESSAGE, PSafeReadOnly);
1607 // Otherwise create a new request with this method type
1608 if (handler != NULL)
1609 handler->SetBody(body);
1610 else {
1611 handler = new SIPMessageHandler(*this,
1613 body);
1614 activeSIPHandlers.Append(handler);
1617 if (!handler->SendRequest()) {
1618 handler->SetExpire(-1);
1619 return FALSE;
1622 return TRUE;
1626 BOOL SIPEndPoint::Publish(const PString & to,
1627 const PString & body,
1628 unsigned expire)
1630 // Create the SIPHandler structure
1631 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_PUBLISH, PSafeReadOnly);
1633 // Otherwise create a new request with this method type
1634 if (handler != NULL)
1635 handler->SetBody(body);
1636 else {
1637 handler = new SIPPublishHandler(*this,
1639 body,
1640 expire);
1641 activeSIPHandlers.Append(handler);
1643 if (!handler->SendRequest()) {
1644 handler->SetExpire(-1);
1645 return FALSE;
1649 return TRUE;
1653 BOOL SIPEndPoint::Ping(const PString & to)
1655 // Create the SIPHandler structure
1656 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByUrl(to, SIP_PDU::Method_PING, PSafeReadOnly);
1658 // Otherwise create a new request with this method type
1659 if (handler == NULL) {
1660 handler = new SIPPingHandler(*this,
1661 to);
1664 if (!handler->SendRequest()) {
1665 handler->SetExpire(-1);
1666 return FALSE;
1669 return TRUE;
1673 void SIPEndPoint::OnMessageReceived (const SIPURL & /*from*/,
1674 const PString & /*body*/)
1679 void SIPEndPoint::OnMWIReceived (const PString & /*to*/,
1680 SIPSubscribe::MWIType /*type*/,
1681 const PString & /*msgs*/)
1686 void SIPEndPoint::OnPresenceInfoReceived (const PString & /*user*/,
1687 const PString & /*basic*/,
1688 const PString & /*note*/)
1693 void SIPEndPoint::OnMessageFailed(const SIPURL & /* messageUrl */,
1694 SIP_PDU::StatusCodes /* reason */)
1699 void SIPEndPoint::ParsePartyName(const PString & remoteParty, PString & party)
1701 party = remoteParty;
1703 #if P_DNS
1704 // if there is no '@', and then attempt to use ENUM
1705 if (remoteParty.Find('@') == P_MAX_INDEX) {
1707 // make sure the number has only digits
1708 PString e164 = remoteParty;
1709 if (e164.Left(4) *= "sip:")
1710 e164 = e164.Mid(4);
1711 PINDEX i;
1712 for (i = 0; i < e164.GetLength(); ++i)
1713 if (!isdigit(e164[i]) && (i != 0 || e164[0] != '+'))
1714 break;
1715 if (i >= e164.GetLength()) {
1716 PString str;
1717 if (PDNS::ENUMLookup(e164, "E2U+SIP", str)) {
1718 PTRACE(4, "SIP\tENUM converted remote party " << remoteParty << " to " << str);
1719 party = str;
1723 #endif
1727 void SIPEndPoint::SetProxy(const PString & hostname,
1728 const PString & username,
1729 const PString & password)
1731 PStringStream str;
1732 if (!hostname) {
1733 str << "sip:";
1734 if (!username) {
1735 str << username;
1736 if (!password)
1737 str << ':' << password;
1738 str << '@';
1740 str << hostname;
1742 proxy = str;
1746 void SIPEndPoint::SetProxy(const SIPURL & url)
1748 proxy = url;
1752 PString SIPEndPoint::GetUserAgent() const
1754 return userAgentString;
1758 BOOL SIPEndPoint::WaitForTransactionCompletion(SIPTransaction * transaction)
1760 transaction->WaitForCompletion();
1761 BOOL success = !transaction->IsFailed();
1762 AddCompletedTransaction(transaction);
1763 return success;
1767 BOOL SIPEndPoint::GetAuthentication(const PString & realm, SIPAuthentication &auth)
1769 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByAuthRealm(realm, PString::Empty(), PSafeReadOnly);
1770 if (handler == NULL)
1771 return FALSE;
1773 auth = handler->GetAuthentication();
1775 return TRUE;
1779 SIPURL SIPEndPoint::GetRegisteredPartyName(const SIPURL & url)
1781 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByDomain(url.GetHostName(), SIP_PDU::Method_REGISTER, PSafeReadOnly);
1783 if (handler == NULL)
1784 return GetDefaultRegisteredPartyName();
1786 return handler->GetTargetAddress();
1790 SIPURL SIPEndPoint::GetDefaultRegisteredPartyName()
1792 OpalTransportAddress addr(PIPSocket::GetHostName(), GetDefaultSignalPort(), "udp");
1793 SIPURL rpn(GetDefaultLocalPartyName(), addr, GetDefaultSignalPort());
1794 rpn.SetDisplayName(GetDefaultDisplayName());
1795 return rpn;
1799 SIPURL SIPEndPoint::GetContactURL(const OpalTransport &transport, const PString & userName, const PString & host)
1801 PSafePtr<SIPHandler> handler = activeSIPHandlers.FindSIPHandlerByDomain(host, SIP_PDU::Method_REGISTER, PSafeReadOnly);
1802 return GetLocalURL(handler != NULL ? handler->GetTransport() : transport, userName);
1806 SIPURL SIPEndPoint::GetLocalURL(const OpalTransport &transport, const PString & userName)
1808 PIPSocket::Address ip(PIPSocket::GetDefaultIpAny());
1809 OpalTransportAddress contactAddress = transport.GetLocalAddress();
1810 WORD contactPort = GetDefaultSignalPort();
1811 if (transport.IsOpen())
1812 transport.GetLocalAddress().GetIpAndPort(ip, contactPort);
1813 else {
1814 for (PINDEX i = 0; i < listeners.GetSize(); i++) {
1815 OpalTransportAddress binding = listeners[i].GetLocalAddress();
1816 if (transport.IsCompatibleTransport(binding)) {
1817 binding.GetIpAndPort(ip, contactPort);
1818 break;
1823 PIPSocket::Address localIP;
1824 WORD localPort;
1826 if (contactAddress.GetIpAndPort(localIP, localPort)) {
1827 PIPSocket::Address remoteIP;
1828 if (transport.GetRemoteAddress().GetIpAddress(remoteIP)) {
1829 GetManager().TranslateIPAddress(localIP, remoteIP);
1830 contactPort = localPort;
1831 contactAddress = OpalTransportAddress(localIP, contactPort, "udp");
1835 SIPURL contact(userName, contactAddress, contactPort);
1837 return contact;
1841 BOOL SIPEndPoint::SendResponse(SIP_PDU::StatusCodes code, OpalTransport & transport, SIP_PDU & pdu)
1843 SIP_PDU response(pdu, code);
1844 PString username = SIPURL(response.GetMIME().GetTo()).GetUserName();
1845 response.GetMIME().SetContact(GetLocalURL(transport, username));
1846 return response.Write(transport, pdu.GetViaAddress(*this));
1850 void SIPEndPoint::OnRTPStatistics(const SIPConnection & /*connection*/,
1851 const RTP_Session & /*session*/) const
1856 // End of file ////////////////////////////////////////////////////////////////