1 /*
2 * handlers.cxx
3 *
4 * Session Initiation Protocol endpoint.
5 *
6 * Open Phone Abstraction Library (OPAL)
7 *
8 * Copyright (c) 2000 Equivalence Pty. Ltd.
9 *
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/
14 *
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.
19 *
20 * The Original Code is Open Phone Abstraction Library.
21 *
22 * The Initial Developer of the Original Code is Damien Sandras.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 29080 $
27 * $Author: rjongbloed $
28 * $Date: 2013-02-12 18:52:05 -0600 (Tue, 12 Feb 2013) $
29 *
30 * This code implements all or part of the following RFCs
31 *
32 * RFC 4479 "A Data Model for Presence"
33 * RFC 4480 "RPID: Rich Presence Extensions to the Presence Information Data Format (PIDF)"
34 */
35
36 #include <ptlib.h>
37 #include <opal/buildopts.h>
38
39 #if OPAL_SIP
40
41 #ifdef __GNUC__
42 #pragma implementation "handlers.h"
43 #endif
44
45 #include <sip/handlers.h>
46
47 #include <ptclib/pdns.h>
48 #include <ptclib/enum.h>
49 #include <sip/sipep.h>
50 #include <ptclib/pxml.h>
51 #include <ptclib/random.h>
52
53 #include <algorithm>
54
55
56 #define new PNEW
57
58
59 #if PTRACING
operator <<(ostream & strm,SIPHandler::State state)60 ostream & operator<<(ostream & strm, SIPHandler::State state)
61 {
62 static const char * const StateNames[] = {
63 "Subscribed", "Subscribing", "Unavailable", "Refreshing", "Restoring", "Unsubscribing", "Unsubscribed"
64 };
65 if (state < PARRAYSIZE(StateNames))
66 strm << StateNames[state];
67 else
68 strm << (unsigned)state;
69 return strm;
70 }
71 #endif
72
73
74 ////////////////////////////////////////////////////////////////////////////
75
SIPHandler(SIP_PDU::Methods method,SIPEndPoint & ep,const SIPParameters & params)76 SIPHandler::SIPHandler(SIP_PDU::Methods method, SIPEndPoint & ep, const SIPParameters & params)
77 : endpoint(ep)
78 , m_authentication(NULL)
79 , m_authenticateErrors(0)
80 , m_username(params.m_authID)
81 , m_password(params.m_password)
82 , m_realm(params.m_realm)
83 , m_transport(NULL)
84 , m_method(method)
85 , m_addressOfRecord(params.m_addressOfRecord)
86 , m_remoteAddress(params.m_remoteAddress)
87 , m_callID(SIPTransaction::GenerateCallID())
88 , m_lastCseq(0)
89 , m_currentExpireTime(params.m_expire)
90 , m_originalExpireTime(params.m_expire)
91 , m_offlineExpireTime(params.m_restoreTime)
92 , m_state(Unavailable)
93 , m_receivedResponse(false)
94 , m_proxy(params.m_proxyAddress)
95 {
96 m_transactions.DisallowDeleteObjects();
97 m_expireTimer.SetNotifier(PCREATE_NOTIFIER(OnExpireTimeout));
98
99 if (m_proxy.IsEmpty())
100 m_proxy = ep.GetProxy();
101
102 PTRACE(4, "SIP\tConstructed " << m_method << " handler for " << m_addressOfRecord);
103 }
104
105
~SIPHandler()106 SIPHandler::~SIPHandler()
107 {
108 m_expireTimer.Stop();
109
110 if (m_transport) {
111 m_transport->CloseWait();
112 delete m_transport;
113 }
114
115 delete m_authentication;
116
117 PTRACE(4, "SIP\tDestroyed " << m_method << " handler for " << m_addressOfRecord);
118 }
119
120
Compare(const PObject & obj) const121 PObject::Comparison SIPHandler::Compare(const PObject & obj) const
122 {
123 PAssert(PIsDescendant(&obj, SIPHandler), PInvalidCast);
124 const SIPHandler * other = dynamic_cast<const SIPHandler *>(&obj);
125 return other != NULL ? GetCallID().Compare(other->GetCallID()) : GreaterThan;
126 }
127
128
ShutDown()129 bool SIPHandler::ShutDown()
130 {
131 PSafeList<SIPTransaction> transactions;
132
133 {
134 PSafeLockReadWrite mutex(*this);
135 if (!mutex.IsLocked())
136 return true;
137
138 while (!m_stateQueue.empty())
139 m_stateQueue.pop();
140
141 switch (GetState()) {
142 case Subscribed :
143 case Unavailable :
144 SendRequest(Unsubscribing);
145 case Unsubscribing :
146 return m_transactions.IsEmpty();
147
148 default :
149 break;
150 }
151
152 transactions = m_transactions;
153 }
154
155 for (PSafePtr<SIPTransaction> transaction(transactions, PSafeReference); transaction != NULL; ++transaction)
156 transaction->Abort();
157
158 return true;
159 }
160
161
SetState(SIPHandler::State newState)162 void SIPHandler::SetState(SIPHandler::State newState)
163 {
164 if (m_state == newState)
165 return;
166
167 PTRACE(4, "SIP\tChanging " << GetMethod() << " handler from " << GetState() << " to " << newState
168 << ", target=" << GetAddressOfRecord() << ", id=" << GetCallID());
169
170 m_state = newState;
171
172 switch (m_state) {
173 case Subscribing :
174 case Refreshing :
175 case Restoring :
176 case Unsubscribing :
177 return;
178
179 default :
180 break;
181 }
182
183 if (m_stateQueue.empty())
184 return;
185
186 newState = m_stateQueue.front();
187 m_stateQueue.pop();
188 SendRequest(newState);
189 }
190
191
ActivateState(SIPHandler::State newState)192 bool SIPHandler::ActivateState(SIPHandler::State newState)
193 {
194 if (GetState() == Unsubscribed)
195 return false;
196
197 // If subscribing with zero expiry time, is same as unsubscribe
198 if (newState == Subscribing && GetExpire() == 0)
199 newState = Unsubscribing;
200
201 // If unsubscribing and never got a response from server, rather than trying
202 // to send more unsuccessful packets, abort transactions and mark Unsubscribed
203 if (newState == Unsubscribing && !m_receivedResponse) {
204 SetState(Unsubscribed); // Allow garbage collection thread to clean up
205 return true;
206 }
207
208 static const enum {
209 e_Invalid,
210 e_NoChange,
211 e_Execute,
212 e_Queue
213 } StateChangeActions[NumStates][NumStates] =
214 {
215 /* old-state
216 V new-state-> Subscribed Subscribing Unavailable Refreshing Restoring Unsubscribing Unsubscribed */
217 /* Subscribed */ { e_NoChange, e_Execute, e_Invalid, e_Execute, e_Execute, e_Execute, e_Invalid },
218 /* Subscribing */ { e_Invalid, e_Queue, e_Invalid, e_NoChange, e_NoChange, e_Queue, e_Invalid },
219 /* Unavailable */ { e_Invalid, e_Execute, e_NoChange, e_Execute, e_Execute, e_Execute, e_Invalid },
220 /* Refreshing */ { e_Invalid, e_Queue, e_Invalid, e_NoChange, e_NoChange, e_Queue, e_Invalid },
221 /* Restoring */ { e_Invalid, e_Queue, e_Invalid, e_NoChange, e_NoChange, e_Queue, e_Invalid },
222 /* Unsubscribing */ { e_Invalid, e_Invalid, e_Invalid, e_Invalid, e_NoChange, e_NoChange, e_Invalid },
223 /* Unsubscribed */ { e_Invalid, e_Invalid, e_Invalid, e_Invalid, e_Invalid, e_NoChange, e_NoChange }
224 };
225
226 PSafeLockReadWrite mutex(*this);
227 if (!mutex.IsLocked())
228 return true;
229
230 switch (StateChangeActions[GetState()][newState]) {
231 case e_Invalid :
232 PTRACE(2, "SIP\tCannot change state to " << newState << " for " << GetMethod()
233 << " handler while in " << GetState() << " state, target="
234 << GetAddressOfRecord() << ", id=" << GetCallID());
235 return false;
236
237 case e_NoChange :
238 PTRACE(4, "SIP\tAlready in state " << GetState() << " for " << GetMethod()
239 << " handler, target=" << GetAddressOfRecord() << ", id=" << GetCallID());
240 break;
241
242 case e_Execute :
243 PTRACE(4, "SIP\tExecuting state change to " << newState << " for " << GetMethod()
244 << " handler, target=" << GetAddressOfRecord() << ", id=" << GetCallID());
245 return SendRequest(newState);
246
247 case e_Queue :
248 PTRACE(3, "SIP\tQueueing state change to " << newState << " for " << GetMethod()
249 << " handler while in " << GetState() << " state, target="
250 << GetAddressOfRecord() << ", id=" << GetCallID());
251 m_stateQueue.push(newState);
252 break;
253 }
254
255 return true;
256 }
257
258
SendRequest(SIPHandler::State newState)259 PBoolean SIPHandler::SendRequest(SIPHandler::State newState)
260 {
261 m_expireTimer.Stop(false); // Stop automatic retry
262
263 SetState(newState);
264
265 if (GetTransport() == NULL)
266 OnFailed(SIP_PDU::Local_BadTransportAddress);
267 else {
268 m_lastCseq = 0;
269
270 // Restoring or first time, try every interface
271 if (newState == Restoring || m_transport->GetInterface().IsEmpty()) {
272 PWaitAndSignal mutex(m_transport->GetWriteMutex());
273 if (m_transport->WriteConnect(WriteSIPHandler, this))
274 return true;
275 }
276 else {
277 // We contacted the server on an interface last time, assume it still works!
278 if (WriteSIPHandler(*m_transport, false))
279 return true;
280 }
281
282 OnFailed(SIP_PDU::Local_TransportError);
283 }
284
285 if (newState == Unsubscribing) {
286 // Transport level error, probably never going to get the unsubscribe through
287 SetState(Unsubscribed);
288 return true;
289 }
290
291 RetryLater(m_offlineExpireTime);
292 return true;
293 }
294
295
GetTransport()296 OpalTransport * SIPHandler::GetTransport()
297 {
298 if (m_transport != NULL) {
299 if (m_transport->IsOpen())
300 return m_transport;
301
302 m_transport->CloseWait();
303 delete m_transport;
304 m_transport = NULL;
305 }
306
307 const PStringToString & remoteParams = m_remoteAddress.GetParamVars();
308
309 // Look for a "proxy" parameter to override default proxy
310 if (m_proxy.IsEmpty() && remoteParams.Contains(OPAL_PROXY_PARAM)) {
311 m_proxy.Parse(remoteParams(OPAL_PROXY_PARAM));
312 m_remoteAddress.SetParamVar(OPAL_PROXY_PARAM, PString::Empty());
313 }
314
315 SIPURL url;
316 if (!m_proxy.IsEmpty())
317 url = m_proxy;
318 else {
319 url = m_remoteAddress;
320 url.AdjustToDNS();
321 }
322
323 PString localInterface = remoteParams(OPAL_INTERFACE_PARAM);
324 if (localInterface.IsEmpty())
325 localInterface = "*"; // Must specify a network interface or get infinite recursion
326
327 m_transport = endpoint.CreateTransport(url, localInterface);
328 return m_transport;
329 }
330
331
SetExpire(int e)332 void SIPHandler::SetExpire(int e)
333 {
334 m_currentExpireTime = e;
335 PTRACE(3, "SIP\tExpiry time for " << GetMethod() << " set to " << e << " seconds.");
336
337 // Only modify the m_originalExpireTime for future requests if IntervalTooBrief gives
338 // a bigger expire time. expire itself will always reflect the proxy decision
339 // (bigger or lower), but m_originalExpireTime determines what is used in future
340 // requests and is only modified if interval too brief
341 if (m_originalExpireTime < e)
342 m_originalExpireTime = e;
343
344 // retry before the expire time.
345 // if the expire time is more than 20 mins, retry 10mins before expiry
346 // if the expire time is less than 20 mins, retry after half of the expiry time
347 if (GetExpire() > 0 && GetState() < Unsubscribing)
348 m_expireTimer.SetInterval(0, (unsigned)(GetExpire() < 20*60 ? GetExpire()/2 : GetExpire()-10*60));
349 }
350
351
WriteSIPHandler(OpalTransport & transport,void * param)352 PBoolean SIPHandler::WriteSIPHandler(OpalTransport & transport, void * param)
353 {
354 return param != NULL && ((SIPHandler *)param)->WriteSIPHandler(transport, true);
355 }
356
357
WriteSIPHandler(OpalTransport & transport,bool forked)358 bool SIPHandler::WriteSIPHandler(OpalTransport & transport, bool forked)
359 {
360 SIPTransaction * transaction = CreateTransaction(transport);
361 if (transaction == NULL) {
362 PTRACE(2, "SIP\tCould not create transaction on " << transport);
363 return false;
364 }
365
366 SIPMIMEInfo & mime = transaction->GetMIME();
367
368 if (forked) {
369 if (m_lastCseq == 0)
370 m_lastCseq = mime.GetCSeqIndex();
371 else
372 transaction->SetCSeq(m_lastCseq);
373 }
374
375 for (PINDEX i = 0; i < m_mime.GetSize(); ++i)
376 mime.SetAt(m_mime.GetKeyAt(i), PString(m_mime.GetDataAt(i)));
377
378 if (GetState() == Unsubscribing)
379 mime.SetExpires(0);
380
381 if (m_authentication != NULL) {
382 SIPAuthenticator auth(*transaction);
383 m_authentication->Authorise(auth); // If already have info from last time, use it!
384 }
385
386 if (transaction->Start()) {
387 m_transactions.Append(transaction);
388 return true;
389 }
390
391 PTRACE(2, "SIP\tDid not start transaction on " << transport);
392 return false;
393 }
394
395
OnReceivedNOTIFY(SIP_PDU &)396 PBoolean SIPHandler::OnReceivedNOTIFY(SIP_PDU & /*response*/)
397 {
398 return PFalse;
399 }
400
401
OnReceivedResponse(SIPTransaction & transaction,SIP_PDU & response)402 void SIPHandler::OnReceivedResponse(SIPTransaction & transaction, SIP_PDU & response)
403 {
404 unsigned responseClass = response.GetStatusCode()/100;
405 if (responseClass < 2)
406 return; // Don't do anything with pending responses.
407
408 // Received a response, so indicate that and collapse the forking on multiple interfaces.
409 m_receivedResponse = true;
410
411 m_transactions.Remove(&transaction); // Take this transaction out of list
412
413 switch (response.GetStatusCode()) {
414 default :
415 if (responseClass != 2)
416 break;
417
418 case SIP_PDU::Failure_UnAuthorised :
419 case SIP_PDU::Failure_ProxyAuthenticationRequired :
420 case SIP_PDU::Failure_IntervalTooBrief :
421 case SIP_PDU::Failure_TemporarilyUnavailable:
422 // End connect mode on the transport
423 PString iface = transaction.GetInterface();
424 PTRACE(4, "SIP\tFinalising handlers interface \"" << iface << '"');
425 m_transport->SetInterface(iface);
426
427 // And kill all the rest
428 PSafePtr<SIPTransaction> transToGo;
429 while ((transToGo = m_transactions.GetAt(0)) != NULL) {
430 m_transactions.Remove(transToGo);
431 transToGo->Abort();
432 }
433 }
434
435 switch (response.GetStatusCode()) {
436 case SIP_PDU::Failure_UnAuthorised :
437 case SIP_PDU::Failure_ProxyAuthenticationRequired :
438 OnReceivedAuthenticationRequired(transaction, response);
439 return;
440
441 case SIP_PDU::Failure_IntervalTooBrief :
442 OnReceivedIntervalTooBrief(transaction, response);
443 break;
444
445 case SIP_PDU::Failure_TemporarilyUnavailable:
446 OnReceivedTemporarilyUnavailable(transaction, response);
447 break;
448
449 default :
450 if (responseClass == 2)
451 OnReceivedOK(transaction, response);
452 else
453 OnFailed(response);
454 }
455
456 m_authenticateErrors = 0;
457 }
458
459
OnReceivedIntervalTooBrief(SIPTransaction &,SIP_PDU & response)460 void SIPHandler::OnReceivedIntervalTooBrief(SIPTransaction & /*transaction*/, SIP_PDU & response)
461 {
462 SetExpire(response.GetMIME().GetMinExpires());
463
464 // Restart the transaction with new authentication handler
465 SendRequest(GetState());
466 }
467
468
OnReceivedTemporarilyUnavailable(SIPTransaction &,SIP_PDU & response)469 void SIPHandler::OnReceivedTemporarilyUnavailable(SIPTransaction & /*transaction*/, SIP_PDU & response)
470 {
471 OnFailed(SIP_PDU::Failure_TemporarilyUnavailable);
472 RetryLater(response.GetMIME().GetInteger("Retry-After", m_offlineExpireTime));
473 }
474
475
OnReceivedAuthenticationRequired(SIPTransaction & transaction,SIP_PDU & response)476 void SIPHandler::OnReceivedAuthenticationRequired(SIPTransaction & transaction, SIP_PDU & response)
477 {
478 // If either username or password blank, try and fine values from other
479 // handlers which might be logged into the realm, or the proxy, if one.
480 SIP_PDU::StatusCodes status = endpoint.HandleAuthentication(m_authentication,
481 m_authenticateErrors,
482 response,
483 GetProxy(),
484 m_username,
485 m_password);
486 if (status != SIP_PDU::Successful_OK) {
487 OnFailed(status);
488 if (GetState() != Unsubscribing && !transaction.IsCanceled())
489 RetryLater(m_offlineExpireTime);
490 return;
491 }
492
493 // If we changed realm (or hadn't got one yet) update the handler database
494 if (m_realm != m_authentication->GetAuthRealm()) {
495 m_realm = m_authentication->GetAuthRealm();
496 PTRACE(3, "SIP\tAuth realm set to " << m_realm);
497 endpoint.UpdateHandlerIndexes(this);
498 }
499
500 // Restart the transaction with new authentication handler
501 SendRequest(GetState());
502 }
503
504
OnReceivedOK(SIPTransaction &,SIP_PDU & response)505 void SIPHandler::OnReceivedOK(SIPTransaction & /*transaction*/, SIP_PDU & response)
506 {
507 response.GetMIME().GetProductInfo(m_productInfo);
508
509 switch (GetState()) {
510 case Unsubscribing :
511 SetState(Unsubscribed);
512 break;
513
514 case Subscribing :
515 case Refreshing :
516 case Restoring :
517 if (GetExpire() == 0)
518 SetState(Unsubscribed);
519 else
520 SetState(Subscribed);
521 break;
522
523 default :
524 PTRACE(2, "SIP\tUnexpected 200 OK in handler with state " << GetState());
525 }
526 }
527
528
OnTransactionFailed(SIPTransaction & transaction)529 void SIPHandler::OnTransactionFailed(SIPTransaction & transaction)
530 {
531 if (m_transactions.Remove(&transaction)) {
532 OnFailed(transaction.GetStatusCode());
533 if (!transaction.IsCanceled())
534 RetryLater(m_offlineExpireTime);
535 }
536 }
537
538
RetryLater(unsigned after)539 void SIPHandler::RetryLater(unsigned after)
540 {
541 if (after == 0 || GetExpire() == 0)
542 return;
543
544 PTRACE(3, "SIP\tRetrying " << GetMethod() << " after " << after << " seconds.");
545 m_expireTimer.SetInterval(0, after); // Keep trying to get it back
546 }
547
548
OnFailed(const SIP_PDU & response)549 void SIPHandler::OnFailed(const SIP_PDU & response)
550 {
551 OnFailed(response.GetStatusCode());
552 }
553
554
OnFailed(SIP_PDU::StatusCodes code)555 void SIPHandler::OnFailed(SIP_PDU::StatusCodes code)
556 {
557 switch (code) {
558 case SIP_PDU::Local_TransportError :
559 case SIP_PDU::Local_Timeout :
560 case SIP_PDU::Failure_RequestTimeout :
561 case SIP_PDU::Local_BadTransportAddress :
562 case SIP_PDU::Failure_TemporarilyUnavailable:
563 if (GetState() != Unsubscribing) {
564 SetState(Unavailable);
565 break;
566 }
567 // Do next case to finalise Unsubscribe even though there was an error
568
569 default :
570 PTRACE(4, "SIP\tNot retrying " << GetMethod() << " due to error response " << code);
571 m_currentExpireTime = 0; // OK, stop trying
572 m_expireTimer.Stop(false);
573 SetState(Unsubscribed); // Allow garbage collection thread to clean up
574 }
575 }
576
577
OnExpireTimeout(PTimer &,INT)578 void SIPHandler::OnExpireTimeout(PTimer &, INT)
579 {
580 PSafeLockReadWrite lock(*this);
581 if (!lock.IsLocked())
582 return;
583
584 switch (GetState()) {
585 case Subscribed :
586 PTRACE(2, "SIP\tStarting " << GetMethod() << " for binding refresh");
587 if (SendRequest(Refreshing))
588 return;
589 break;
590
591 case Unavailable :
592 PTRACE(2, "SIP\tStarting " << GetMethod() << " for offline retry");
593 if (SendRequest(Restoring))
594 return;
595 break;
596
597 default :
598 return;
599 }
600
601 SetState(Unavailable);
602 }
603
604
605 ///////////////////////////////////////////////////////////////////////////////
606
SIPRegisterHandler(SIPEndPoint & endpoint,const SIPRegister::Params & params)607 SIPRegisterHandler::SIPRegisterHandler(SIPEndPoint & endpoint, const SIPRegister::Params & params)
608 : SIPHandler(SIP_PDU::Method_REGISTER, endpoint, params)
609 , m_parameters(params)
610 , m_sequenceNumber(0)
611 {
612 // Foer some bizarre reason, even though REGISTER does not create a dialog,
613 // some registrars insist that you have a from tag ...
614 SIPURL local = params.m_localAddress.IsEmpty() ? params.m_addressOfRecord : params.m_localAddress;
615 local.SetTag();
616 m_parameters.m_localAddress = local.AsQuotedString();
617 m_parameters.m_proxyAddress = m_proxy.AsString();
618 }
619
620
CreateTransaction(OpalTransport & trans)621 SIPTransaction * SIPRegisterHandler::CreateTransaction(OpalTransport & trans)
622 {
623 SIPRegister::Params params = m_parameters;
624
625 if (GetState() == Unsubscribing) {
626 params.m_expire = 0;
627
628 if (params.m_contactAddress.IsEmpty()) {
629 if (m_contactAddresses.empty())
630 params.m_contactAddress = "*";
631 else {
632 for (SIPURLList::iterator contact = m_contactAddresses.begin(); contact != m_contactAddresses.end(); ++contact)
633 contact->GetFieldParameters().Remove("expires");
634 params.m_contactAddress = m_contactAddresses.ToString();
635 }
636 }
637 }
638 else {
639 params.m_expire = GetExpire();
640
641 if (params.m_contactAddress.IsEmpty()) {
642 if (GetState() != Refreshing || m_contactAddresses.empty()) {
643 PString userName = SIPURL(params.m_addressOfRecord).GetUserName();
644 OpalTransportAddressArray interfaces = endpoint.GetInterfaceAddresses(true, &trans);
645 if (params.m_compatibility == SIPRegister::e_CannotRegisterMultipleContacts) {
646 // If translated by STUN then only the external address of the interface is used.
647 SIPURL contact(userName, interfaces[0]);
648 contact.Sanitise(SIPURL::RegContactURI);
649 params.m_contactAddress += contact.AsQuotedString();
650 }
651 else {
652 OpalTransportAddress localAddress = trans.GetLocalAddress(params.m_compatibility != SIPRegister::e_HasApplicationLayerGateway);
653 unsigned qvalue = 1000;
654 for (PINDEX i = 0; i < interfaces.GetSize(); ++i) {
655 /* If fully compliant, put into the contact field all the bound
656 interfaces. If special then we only put into the contact
657 listeners that are on the same interface. If translated by STUN
658 then only the external address of the interface is used. */
659 if (params.m_compatibility == SIPRegister::e_FullyCompliant || localAddress.IsEquivalent(interfaces[i], true)) {
660 SIPURL contact(userName, interfaces[i]);
661 contact.Sanitise(SIPURL::RegContactURI);
662 contact.GetFieldParameters().Set("q", qvalue < 1000 ? psprintf("0.%03u", qvalue) : "1");
663
664 if (!params.m_contactAddress.IsEmpty())
665 params.m_contactAddress += ", ";
666 params.m_contactAddress += contact.AsQuotedString();
667
668 qvalue -= 1000/interfaces.GetSize();
669 }
670 }
671 }
672 }
673 else
674 params.m_contactAddress = m_contactAddresses.ToString();
675 }
676 }
677
678 return new SIPRegister(endpoint, trans, GetCallID(), m_sequenceNumber, params);
679 }
680
681
OnReceivedOK(SIPTransaction & transaction,SIP_PDU & response)682 void SIPRegisterHandler::OnReceivedOK(SIPTransaction & transaction, SIP_PDU & response)
683 {
684 State previousState = GetState();
685 switch (previousState) {
686 case Unsubscribing :
687 SetState(Unsubscribed);
688 SendStatus(SIP_PDU::Successful_OK, Unsubscribing);
689 return;
690
691 case Subscribing :
692 case Refreshing :
693 case Restoring :
694 break;
695
696 default :
697 PTRACE(2, "SIP\tUnexpected 200 OK in handler with state " << previousState);
698 return;
699 }
700
701 SIPMIMEInfo & mime = response.GetMIME();
702
703 mime.GetProductInfo(m_productInfo);
704
705 m_serviceRoute.FromString(mime("Service-Route"));
706
707 SIPURLList requestedContacts;
708 transaction.GetMIME().GetContacts(requestedContacts);
709
710 SIPURLList replyContacts;
711 mime.GetContacts(replyContacts);
712
713 /* See if we are behind NAT and the Via header rport was present. This is
714 a STUN free mechanism for working behind firewalls. Also, some servers
715 will refuse to work unless the Contact header agrees whith where the
716 packet is physically coming from. */
717 OpalTransportAddress externalAddress;
718 if (m_parameters.m_compatibility != SIPRegister::e_HasApplicationLayerGateway)
719 externalAddress = mime.GetViaReceivedAddress();
720
721 /* RFC3261 does say the registrar must send back ALL registrations, however
722 we only deal with replies from the registrar that we actually requested.
723
724 Except! We look for special condition where registrar (e.g. OpenSIPS)
725 tries to be smart and adjusts the Contact field to be the external
726 address as per the Via header rport. IMHO this is a bug as it does not follow
727 what is implied by RFC3261/10.2.4 and 10.3 step 7. It should include the
728 original as well as the extra Contact. But it doesn't, so we have to deal.
729 */
730 for (SIPURLList::iterator reply = replyContacts.begin(); reply != replyContacts.end(); ) {
731 if (reply->GetHostAddress() == externalAddress) {
732 externalAddress.MakeEmpty(); // Clear this so no further action taken
733 m_externalAddress.MakeEmpty();
734 ++reply;
735 }
736 else if (std::find(requestedContacts.begin(), requestedContacts.end(), *reply) != requestedContacts.end())
737 ++reply;
738 else
739 replyContacts.erase(reply++);
740 }
741
742 if (replyContacts.empty() && GetExpire() != 0) {
743 // Huh? Nothing we tried to register, registered! How is that possible?
744 PTRACE(2, "SIP\tREGISTER returned no Contact addresses we requested, not really registered.");
745 SendRequest(Unsubscribing);
746 SendStatus(SIP_PDU::GlobalFailure_NotAcceptable, previousState);
747 return;
748 }
749
750 // If this is the final (possibly one and only) REGISTER, process it
751 if (m_externalAddress == externalAddress) {
752 int minExpiry = INT_MAX;
753 for (SIPURLList::iterator contact = replyContacts.begin(); contact != replyContacts.end(); ++contact) {
754 long expires = contact->GetFieldParameters().GetInteger("expires",
755 mime.GetExpires(endpoint.GetRegistrarTimeToLive().GetSeconds()));
756 if (expires > 0 && minExpiry > expires)
757 minExpiry = expires;
758 }
759 SetExpire(minExpiry);
760
761 m_contactAddresses = replyContacts;
762 SetState(Subscribed);
763 SendStatus(SIP_PDU::Successful_OK, previousState);
764 return;
765 }
766
767 if (GetExpire() == 0) {
768 // If we had discovered we are behind NAT and had unregistered, re-REGISTER with new addresses
769 PTRACE(2, "SIP\tRe-registering NAT address change (" << m_contactAddresses << ") to " << externalAddress);
770 for (SIPURLList::iterator contact = m_contactAddresses.begin(); contact != m_contactAddresses.end(); ++contact)
771 contact->SetHostAddress(externalAddress);
772 m_contactAddresses.unique();
773 SetExpire(m_originalExpireTime);
774 }
775 else {
776 /* If we got here then we have done a successful register, but registrar indicated
777 that we are behind firewall. Unregister what we just registered */
778 for (SIPURLList::iterator contact = replyContacts.begin(); contact != replyContacts.end(); ++contact)
779 contact->GetFieldParameters().Remove("expires");
780 PTRACE(2, "SIP\tRemote indicated change of REGISTER Contact address(s) (" << replyContacts
781 << ") required due to NAT address " << externalAddress << ", previous=" << m_externalAddress);
782 m_contactAddresses = replyContacts;
783 SetExpire(0);
784 }
785
786 // Remember (possibly new) NAT address
787 m_externalAddress == externalAddress;
788
789 SendRequest(Refreshing);
790 SendStatus(SIP_PDU::Information_Trying, previousState);
791 }
792
793
OnFailed(SIP_PDU::StatusCodes r)794 void SIPRegisterHandler::OnFailed(SIP_PDU::StatusCodes r)
795 {
796 SendStatus(r, GetState());
797 SIPHandler::OnFailed(r);
798 }
799
800
SendRequest(SIPHandler::State s)801 PBoolean SIPRegisterHandler::SendRequest(SIPHandler::State s)
802 {
803 SendStatus(SIP_PDU::Information_Trying, s);
804 m_sequenceNumber = endpoint.GetNextCSeq();
805 return SIPHandler::SendRequest(s);
806 }
807
808
SendStatus(SIP_PDU::StatusCodes code,State state)809 void SIPRegisterHandler::SendStatus(SIP_PDU::StatusCodes code, State state)
810 {
811 SIPEndPoint::RegistrationStatus status;
812 status.m_handler = this;
813 status.m_addressofRecord = GetAddressOfRecord().AsString();
814 status.m_productInfo = m_productInfo;
815 status.m_reason = code;
816 status.m_userData = m_parameters.m_userData;
817
818 switch (state) {
819 case Subscribing :
820 status.m_wasRegistering = true;
821 status.m_reRegistering = false;
822 break;
823
824 case Subscribed :
825 case Refreshing :
826 status.m_wasRegistering = true;
827 status.m_reRegistering = true;
828 break;
829
830 case Unsubscribed :
831 case Unavailable :
832 case Restoring :
833 status.m_wasRegistering = true;
834 status.m_reRegistering = code/100 != 2;
835 break;
836
837 case Unsubscribing :
838 status.m_wasRegistering = false;
839 status.m_reRegistering = false;
840 break;
841
842 default :
843 PAssertAlways(PInvalidParameter);
844 }
845
846 endpoint.OnRegistrationStatus(status);
847 }
848
849
UpdateParameters(const SIPRegister::Params & params)850 void SIPRegisterHandler::UpdateParameters(const SIPRegister::Params & params)
851 {
852 if (!params.m_authID.IsEmpty())
853 m_username = m_parameters.m_authID = params.m_authID; // Adjust the authUser if required
854 if (!params.m_realm.IsEmpty())
855 m_realm = m_parameters.m_realm = params.m_realm; // Adjust the realm if required
856 if (!params.m_password.IsEmpty())
857 m_password = m_parameters.m_password = params.m_password; // Adjust the password if required
858
859 if (params.m_expire > 0)
860 SetExpire(m_parameters.m_expire = params.m_expire);
861
862 m_parameters.m_compatibility = params.m_compatibility;
863 m_parameters.m_contactAddress = params.m_contactAddress;
864 m_contactAddresses.clear();
865
866 PTRACE(4, "SIP\tREGISTER parameters updated.");
867 }
868
869
870 /////////////////////////////////////////////////////////////////////////
871
SIPSubscribeHandler(SIPEndPoint & endpoint,const SIPSubscribe::Params & params)872 SIPSubscribeHandler::SIPSubscribeHandler(SIPEndPoint & endpoint, const SIPSubscribe::Params & params)
873 : SIPHandler(SIP_PDU::Method_SUBSCRIBE, endpoint, params)
874 , m_parameters(params)
875 , m_unconfirmed(true)
876 , m_packageHandler(SIPEventPackageFactory::CreateInstance(params.m_eventPackage))
877 , m_previousResponse(NULL)
878 {
879 m_callID = m_dialog.GetCallID();
880
881 m_parameters.m_proxyAddress = m_proxy.AsString();
882
883 if (m_parameters.m_contentType.IsEmpty() && (m_packageHandler != NULL))
884 m_parameters.m_contentType = m_packageHandler->GetContentType();
885 }
886
887
~SIPSubscribeHandler()888 SIPSubscribeHandler::~SIPSubscribeHandler()
889 {
890 delete m_packageHandler;
891 delete m_previousResponse;
892 }
893
894
CreateTransaction(OpalTransport & trans)895 SIPTransaction * SIPSubscribeHandler::CreateTransaction(OpalTransport & trans)
896 {
897 // Do all the following here as must be after we have called GetTransport()
898 // which sets various fields correctly for transmission
899 if (!m_dialog.IsEstablished()) {
900 m_dialog.SetRequestURI(GetAddressOfRecord());
901 if (m_parameters.m_eventPackage.IsWatcher())
902 m_parameters.m_localAddress = GetAddressOfRecord().AsString();
903
904 m_dialog.SetRemoteURI(m_parameters.m_addressOfRecord);
905
906 if (m_parameters.m_localAddress.IsEmpty())
907 m_dialog.SetLocalURI(endpoint.GetRegisteredPartyName(m_parameters.m_addressOfRecord, *m_transport));
908 else
909 m_dialog.SetLocalURI(m_parameters.m_localAddress);
910
911 m_dialog.SetProxy(m_proxy, true);
912 }
913
914 m_parameters.m_expire = GetState() != Unsubscribing ? GetExpire() : 0;
915 return new SIPSubscribe(endpoint, trans, m_dialog, m_parameters);
916 }
917
918
OnFailed(const SIP_PDU & response)919 void SIPSubscribeHandler::OnFailed(const SIP_PDU & response)
920 {
921 SIP_PDU::StatusCodes responseCode = response.GetStatusCode();
922
923 SendStatus(responseCode, GetState());
924
925 if (GetState() != Unsubscribing && responseCode == SIP_PDU::Failure_TransactionDoesNotExist) {
926 // Resubscribe as previous subscription totally lost, but dialog processing
927 // may have altered the target so restore the original target address
928 m_parameters.m_addressOfRecord = GetAddressOfRecord().AsString();
929 PString dummy;
930 endpoint.Subscribe(m_parameters, dummy);
931 }
932
933 SIPHandler::OnFailed(responseCode);
934 }
935
936
SendRequest(SIPHandler::State s)937 PBoolean SIPSubscribeHandler::SendRequest(SIPHandler::State s)
938 {
939 SendStatus(SIP_PDU::Information_Trying, s);
940 return SIPHandler::SendRequest(s);
941 }
942
943
WriteSIPHandler(OpalTransport & transport,bool forked)944 bool SIPSubscribeHandler::WriteSIPHandler(OpalTransport & transport, bool forked)
945 {
946 m_dialog.SetForking(forked);
947 bool ok = SIPHandler::WriteSIPHandler(transport, false);
948 m_dialog.SetForking(false);
949 return ok;
950 }
951
952
SendStatus(SIP_PDU::StatusCodes code,State state)953 void SIPSubscribeHandler::SendStatus(SIP_PDU::StatusCodes code, State state)
954 {
955 SIPEndPoint::SubscriptionStatus status;
956 status.m_handler = this;
957 status.m_addressofRecord = GetAddressOfRecord().AsString();
958 status.m_productInfo = m_productInfo;
959 status.m_reason = code;
960 status.m_userData = m_parameters.m_userData;
961
962 switch (state) {
963 case Subscribing :
964 status.m_wasSubscribing = true;
965 status.m_reSubscribing = false;
966 break;
967
968 case Subscribed :
969 if (m_unconfirmed) {
970 status.m_wasSubscribing = true;
971 status.m_reSubscribing = false;
972 endpoint.OnSubscriptionStatus(status);
973 }
974 // Do next state
975
976 case Refreshing :
977 status.m_wasSubscribing = true;
978 status.m_reSubscribing = true;
979 break;
980
981 case Unsubscribed :
982 case Unavailable :
983 case Restoring :
984 status.m_wasSubscribing = true;
985 status.m_reSubscribing = code/100 != 2;
986 break;
987
988 case Unsubscribing :
989 status.m_wasSubscribing = false;
990 status.m_reSubscribing = false;
991 break;
992
993 default :
994 PAssertAlways(PInvalidParameter);
995 }
996
997 if (!m_parameters.m_onSubcribeStatus.IsNULL())
998 m_parameters.m_onSubcribeStatus(*this, status);
999
1000 endpoint.OnSubscriptionStatus(status);
1001 }
1002
1003
UpdateParameters(const SIPSubscribe::Params & params)1004 void SIPSubscribeHandler::UpdateParameters(const SIPSubscribe::Params & params)
1005 {
1006 if (!params.m_authID.IsEmpty())
1007 m_username = params.m_authID; // Adjust the authUser if required
1008 if (!params.m_realm.IsEmpty())
1009 m_realm = params.m_realm; // Adjust the realm if required
1010 if (!params.m_password.IsEmpty())
1011 m_password = params.m_password; // Adjust the password if required
1012
1013 m_parameters.m_contactAddress = params.m_contactAddress;
1014 m_parameters.m_onSubcribeStatus = params.m_onSubcribeStatus;
1015 m_parameters.m_onNotify = params.m_onNotify;
1016
1017 if (params.m_expire > 0)
1018 SetExpire(params.m_expire);
1019 }
1020
1021
OnReceivedOK(SIPTransaction & transaction,SIP_PDU & response)1022 void SIPSubscribeHandler::OnReceivedOK(SIPTransaction & transaction, SIP_PDU & response)
1023 {
1024 /* An "expire" parameter in the Contact header has no semantics
1025 * for SUBSCRIBE. RFC3265, 3.1.1.
1026 * An answer can only shorten the expires time.
1027 */
1028 SetExpire(response.GetMIME().GetExpires(m_originalExpireTime));
1029 m_dialog.Update(*m_transport, response);
1030
1031 if (GetState() != Unsubscribing)
1032 SIPHandler::OnReceivedOK(transaction, response);
1033 }
1034
1035
OnReceivedNOTIFY(SIP_PDU & request)1036 PBoolean SIPSubscribeHandler::OnReceivedNOTIFY(SIP_PDU & request)
1037 {
1038 if (PAssertNULL(m_transport) == NULL)
1039 return false;
1040
1041 if (m_unconfirmed) {
1042 SendStatus(SIP_PDU::Successful_OK, GetState());
1043 m_unconfirmed = false;
1044 }
1045
1046 SIPMIMEInfo & requestMIME = request.GetMIME();
1047
1048 requestMIME.GetProductInfo(m_productInfo);
1049
1050 // If we received this NOTIFY before, send the previous response
1051 if (m_dialog.IsDuplicateCSeq(requestMIME.GetCSeqIndex())) {
1052
1053 // duplicate CSEQ but no previous response? That's unpossible!
1054 if (m_previousResponse == NULL)
1055 return request.SendResponse(*m_transport, SIP_PDU::Failure_InternalServerError, &endpoint);
1056
1057 /* Make sure our repeat response has the CSeq/Via etc of this request, due
1058 to retries at various protocol layers we can have old and even older
1059 NOTIFY packets still coming in requiring matching responses. */
1060 m_previousResponse->InitialiseHeaders(request);
1061 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1062 }
1063
1064 // remove last response
1065 delete m_previousResponse;
1066 m_previousResponse = new SIP_PDU(request, SIP_PDU::Failure_BadRequest);
1067
1068 PStringToString subscriptionStateInfo;
1069 PCaselessString subscriptionState = requestMIME.GetSubscriptionState(subscriptionStateInfo);
1070 if (subscriptionState.IsEmpty()) {
1071 PTRACE(2, "SIP\tNOTIFY received without Subscription-State, assuming 'active'");
1072 subscriptionState = "active";
1073 }
1074
1075 // Check the susbscription state
1076 if (subscriptionState == "terminated") {
1077 PTRACE(3, "SIP\tSubscription is terminated, state=" << GetState());
1078 m_previousResponse->SetStatusCode(SIP_PDU::Successful_OK);
1079 request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1080
1081 switch (GetState()) {
1082 case Unsubscribed :
1083 break;
1084
1085 case Subscribed :
1086 case Unavailable :
1087 SendRequest(Unsubscribing);
1088 break;
1089
1090 default :
1091 SetState(Unsubscribed); // Allow garbage collection thread to clean up
1092 SendStatus(SIP_PDU::Successful_OK, Unsubscribing);
1093 break;
1094 }
1095
1096 return true;
1097 }
1098
1099 PString requestEvent = requestMIME.GetEvent();
1100 if (m_parameters.m_eventPackage != requestEvent) {
1101 PTRACE(2, "SIP\tNOTIFY received for incorrect event \"" << requestEvent << "\", requires \"" << m_parameters.m_eventPackage << '"');
1102 m_previousResponse->SetStatusCode(SIP_PDU::Failure_BadEvent);
1103 m_previousResponse->GetMIME().SetAt("Allow-Events", m_parameters.m_eventPackage);
1104 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1105 }
1106
1107 // Check any Requires field
1108 PStringSet require = requestMIME.GetRequire();
1109 if (m_parameters.m_eventList)
1110 require -= "eventlist";
1111 if (!require.IsEmpty()) {
1112 PTRACE(2, "SIPPres\tNOTIFY contains unsupported Require field \"" << setfill(',') << require << '"');
1113 m_previousResponse->SetStatusCode(SIP_PDU::Failure_BadExtension);
1114 m_previousResponse->GetMIME().SetUnsupported(require);
1115 m_previousResponse->SetInfo("Unsupported Require");
1116 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1117 }
1118
1119 // check the ContentType
1120 if (!m_parameters.m_contentType.IsEmpty()) {
1121 PCaselessString requestContentType = requestMIME.GetContentType();
1122 if (
1123 (m_parameters.m_contentType.Find(requestContentType) == P_MAX_INDEX) &&
1124 !(m_parameters.m_eventList && (requestContentType == "multipart/related")) &&
1125 !((m_packageHandler != NULL) && m_packageHandler->ValidateContentType(requestContentType, requestMIME))
1126 ) {
1127 PTRACE(2, "SIPPres\tNOTIFY contains unsupported Content-Type \""
1128 << requestContentType << "\", expecting \"" << m_parameters.m_contentType << "\" or multipart/related or other validated type");
1129 m_previousResponse->SetStatusCode(SIP_PDU::Failure_UnsupportedMediaType);
1130 m_previousResponse->GetMIME().SetAt("Accept", m_parameters.m_contentType);
1131 m_previousResponse->SetInfo("Unsupported Content-Type");
1132 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1133 }
1134 }
1135
1136 // Check if we know how to deal with this event
1137 if (m_packageHandler == NULL && m_parameters.m_onNotify.IsNULL()) {
1138 PTRACE(2, "SIP\tNo handler for NOTIFY received for event \"" << requestEvent << '"');
1139 m_previousResponse->SetStatusCode(SIP_PDU::Failure_InternalServerError);
1140 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1141 }
1142
1143 // Adjust timeouts if state is a go
1144 if (subscriptionState == "active" || subscriptionState == "pending") {
1145 PTRACE(3, "SIP\tSubscription is " << GetState());
1146 PString expire = SIPMIMEInfo::ExtractFieldParameter(GetState(), "expire");
1147 if (!expire.IsEmpty())
1148 SetExpire(expire.AsUnsigned());
1149 }
1150
1151 bool sendResponse = true;
1152
1153 PMultiPartList parts;
1154 if (!m_parameters.m_eventList || !requestMIME.DecodeMultiPartList(parts, request.GetEntityBody()))
1155 sendResponse = DispatchNOTIFY(request, *m_previousResponse);
1156 else {
1157 // If GetMultiParts() returns true there as at least one part and that
1158 // part must be the meta list, guranteed by DecodeMultiPartList()
1159 PMultiPartList::iterator iter = parts.begin();
1160
1161 // First part is always Meta Information
1162 if (iter->m_mime.GetString(PMIMEInfo::ContentTypeTag) != "application/rlmi+xml") {
1163 PTRACE(2, "SIP\tNOTIFY received without RLMI as first multipart body");
1164 m_previousResponse->SetInfo("No Resource List Meta-Information");
1165 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1166 }
1167
1168 #if P_EXPAT
1169 PXML xml;
1170 if (!xml.Load(iter->m_textBody)) {
1171 PTRACE(2, "SIP\tNOTIFY received with illegal RLMI\n"
1172 "Line " << xml.GetErrorLine() << ", Column " << xml.GetErrorColumn() << ": " << xml.GetErrorString());
1173 m_previousResponse->SetInfo("Bad Resource List Meta-Information");
1174 return request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1175 }
1176
1177 if (parts.GetSize() == 1)
1178 m_previousResponse->SetStatusCode(SIP_PDU::Successful_OK);
1179 else {
1180 while (++iter != parts.end()) {
1181 SIP_PDU pdu(request.GetMethod());
1182 SIPMIMEInfo & pduMIME = pdu.GetMIME();
1183
1184 pduMIME.AddMIME(iter->m_mime);
1185 pdu.SetEntityBody(iter->m_textBody);
1186
1187 PStringToString cid;
1188 if (iter->m_mime.GetComplex(PMIMEInfo::ContentIdTag, cid)) {
1189 PINDEX index = 0;
1190 PXMLElement * resource;
1191 while ((resource = xml.GetElement("resource", index++)) != NULL) {
1192 SIPURL uri = resource->GetAttribute("uri");
1193 if (!uri.IsEmpty()) {
1194 PXMLElement * instance = resource->GetElement("instance");
1195 if (instance != NULL && instance->GetAttribute("cid") == cid[PString::Empty()]) {
1196 pduMIME.SetSubscriptionState(instance->GetAttribute("state"));
1197 PXMLElement * name = resource->GetElement("name");
1198 if (name != NULL)
1199 uri.SetDisplayName(name->GetData());
1200 pduMIME.SetFrom(uri.AsQuotedString());
1201 pduMIME.SetTo(uri.AsQuotedString());
1202 break;
1203 }
1204 }
1205 }
1206 }
1207
1208 if (DispatchNOTIFY(pdu, *m_previousResponse))
1209 sendResponse = false;
1210 }
1211 }
1212 #else
1213 for ( ; iter != parts.end(); ++iter) {
1214 SIP_PDU pdu(request.GetMethod());
1215 pdu.GetMIME().AddMIME(iter->m_mime);
1216 pdu.SetEntityBody(iter->m_textBody);
1217
1218 if (DispatchNOTIFY(pdu, *m_previousResponse))
1219 sendResponse = false;
1220 }
1221 #endif
1222 }
1223
1224 if (sendResponse)
1225 request.SendResponse(*m_transport, *m_previousResponse, &endpoint);
1226 return true;
1227 }
1228
1229
DispatchNOTIFY(SIP_PDU & request,SIP_PDU & response)1230 bool SIPSubscribeHandler::DispatchNOTIFY(SIP_PDU & request, SIP_PDU & response)
1231 {
1232 if (!m_parameters.m_onNotify.IsNULL()) {
1233 PTRACE(4, "SIP\tCalling NOTIFY callback for AOR \"" << m_addressOfRecord << "\"");
1234 SIPSubscribe::NotifyCallbackInfo status(endpoint, *m_transport, request, response);
1235 m_parameters.m_onNotify(*this, status);
1236 return status.m_sendResponse;
1237 }
1238
1239 if (m_packageHandler != NULL) {
1240 PTRACE(4, "SIP\tCalling package NOTIFY handler for AOR \"" << m_addressOfRecord << "\"");
1241 if (m_packageHandler->OnReceivedNOTIFY(*this, request))
1242 response.SetStatusCode(SIP_PDU::Successful_OK);
1243 return true;
1244 }
1245
1246 PTRACE(2, "SIP\tNo NOTIFY handler for AOR \"" << m_addressOfRecord << "\"");
1247 return true;
1248 }
1249
ValidateContentType(const PString & type,const SIPMIMEInfo & mime)1250 bool SIPEventPackageHandler::ValidateContentType(const PString & type, const SIPMIMEInfo & mime)
1251 {
1252 return type.IsEmpty() && (mime.GetContentLength() == 0);
1253 }
1254
1255 class SIPMwiEventPackageHandler : public SIPEventPackageHandler
1256 {
GetContentType() const1257 virtual PCaselessString GetContentType() const
1258 {
1259 return "application/simple-message-summary";
1260 }
1261
OnReceivedNOTIFY(SIPHandler & handler,SIP_PDU & request)1262 virtual bool OnReceivedNOTIFY(SIPHandler & handler, SIP_PDU & request)
1263 {
1264 PString body = request.GetEntityBody();
1265 if (body.IsEmpty ())
1266 return true;
1267
1268 // Extract the string describing the number of new messages
1269 static struct {
1270 const char * name;
1271 OpalManager::MessageWaitingType type;
1272 } const validMessageClasses[] = {
1273 { "voice-message", OpalManager::VoiceMessageWaiting },
1274 { "fax-message", OpalManager::FaxMessageWaiting },
1275 { "pager-message", OpalManager::PagerMessageWaiting },
1276 { "multimedia-message", OpalManager::MultimediaMessageWaiting },
1277 { "text-message", OpalManager::TextMessageWaiting },
1278 { "none", OpalManager::NoMessageWaiting }
1279 };
1280
1281 PMIMEInfo info(request.GetEntityBody());
1282
1283 const SIPURL & aor = handler.GetAddressOfRecord();
1284 PString account = info.Get("Message-Account");
1285 SIPURL accountURI(account);
1286 if (account.IsEmpty() || aor.GetUserName() == account ||
1287 (accountURI.GetUserName() == "asterisk" && accountURI.GetHostName() == aor.GetHostName()))
1288 account = aor.AsString();
1289
1290 bool nothingSent = true;
1291 for (PINDEX z = 0 ; z < PARRAYSIZE(validMessageClasses); z++) {
1292 if (info.Contains(validMessageClasses[z].name)) {
1293 handler.GetEndPoint().OnMWIReceived(account, validMessageClasses[z].type, info[validMessageClasses[z].name]);
1294 nothingSent = false;
1295 }
1296 }
1297
1298 // Received MWI, but not counts, must be old form. Also make sure we send a
1299 // lower case yes/no to call back function, regardless of what comes down the wire.
1300 if (nothingSent)
1301 handler.GetEndPoint().OnMWIReceived(account, OpalManager::NumMessageWaitingTypes,
1302 (info.Get("Messages-Waiting") *= "yes") ? "yes" : "no");
1303
1304 return true;
1305 }
1306 };
1307
1308 static SIPEventPackageFactory::Worker<SIPMwiEventPackageHandler> mwiEventPackageHandler(SIPSubscribe::MessageSummary);
1309
1310
1311 ///////////////////////////////////////////////////////////////////////////////
1312
1313 #if P_EXPAT
1314
1315 // This package is on for backward compatibility, presence should now use the
1316 // the OpalPresence classes to manage SIP presence.
1317 class SIPPresenceEventPackageHandler : public SIPEventPackageHandler
1318 {
GetContentType() const1319 virtual PCaselessString GetContentType() const
1320 {
1321 return "application/pidf+xml";
1322 }
1323
OnReceivedNOTIFY(SIPHandler & handler,SIP_PDU & request)1324 virtual bool OnReceivedNOTIFY(SIPHandler & handler, SIP_PDU & request)
1325 {
1326 PTRACE(4, "SIP\tProcessing presence NOTIFY using old API");
1327
1328 // support old API
1329 SIPURL from = request.GetMIME().GetFrom();
1330 from.Sanitise(SIPURL::ExternalURI);
1331
1332 SIPURL to = request.GetMIME().GetTo();
1333 to.Sanitise(SIPURL::ExternalURI);
1334
1335 list<SIPPresenceInfo> infoList;
1336
1337 // Check for empty body, if so then is OK, just a ping ...
1338 if (request.GetEntityBody().IsEmpty())
1339 infoList.resize(1);
1340 else {
1341 PString error;
1342 PString body = request.GetEntityBody();
1343 if (handler.GetProductInfo().name.Find("Asterisk") != P_MAX_INDEX) {
1344 PTRACE(4, "SIP\tCompensating for " << handler.GetProductInfo().name << ","
1345 " replacing " << to.AsString() << " with " << from.AsString());
1346 body.Replace(to.AsString(), from.AsString());
1347 }
1348 if (!SIPPresenceInfo::ParseXML(body, infoList, error))
1349 return false;
1350 }
1351
1352 for (list<SIPPresenceInfo>::iterator it = infoList.begin(); it != infoList.end(); ++it) {
1353 it->m_entity = from; // Really should not do this, but put in for backward compatibility
1354 it->m_target = to;
1355 handler.GetEndPoint().OnPresenceInfoReceived(*it);
1356 }
1357 return true;
1358 }
1359 };
1360
1361 static SIPEventPackageFactory::Worker<SIPPresenceEventPackageHandler> presenceEventPackageHandler(SIPSubscribe::Presence);
1362
1363
ParseParticipant(PXMLElement * participantElement,SIPDialogNotification::Participant & participant)1364 static void ParseParticipant(PXMLElement * participantElement, SIPDialogNotification::Participant & participant)
1365 {
1366 if (participantElement == NULL)
1367 return;
1368
1369 PXMLElement * identityElement = participantElement->GetElement("identity");
1370 if (identityElement != NULL) {
1371 participant.m_identity = identityElement->GetData();
1372 participant.m_display = identityElement->GetAttribute("display");
1373 }
1374
1375 PXMLElement * targetElement = participantElement->GetElement("target");
1376 if (targetElement == NULL)
1377 return;
1378
1379 participant.m_URI = targetElement->GetAttribute("uri");
1380
1381 PXMLElement * paramElement;
1382 PINDEX i = 0;
1383 while ((paramElement = targetElement->GetElement("param", i++)) != NULL) {
1384 PCaselessString name = paramElement->GetAttribute("pname");
1385 PCaselessString value = paramElement->GetAttribute("pvalue");
1386 if (name == "appearance" || // draft-anil-sipping-bla-04 version
1387 name == "x-line-id") // draft-anil-sipping-bla-03 version
1388 participant.m_appearance = value.AsUnsigned();
1389 else if (name == "sip.byeless" || name == "+sip.byeless")
1390 participant.m_byeless = value == "true";
1391 else if (name == "sip.rendering" || name == "+sip.rendering") {
1392 if (value == "yes")
1393 participant.m_rendering = SIPDialogNotification::RenderingMedia;
1394 else if (value == "no")
1395 participant.m_rendering = SIPDialogNotification::NotRenderingMedia;
1396 else
1397 participant.m_rendering = SIPDialogNotification::RenderingUnknown;
1398 }
1399 }
1400 }
1401
1402
1403 class SIPDialogEventPackageHandler : public SIPEventPackageHandler
1404 {
1405 public:
SIPDialogEventPackageHandler()1406 SIPDialogEventPackageHandler()
1407 : m_dialogNotifyVersion(1)
1408 {
1409 }
1410
GetContentType() const1411 virtual PCaselessString GetContentType() const
1412 {
1413 return "application/dialog-info+xml";
1414 }
1415
OnReceivedNOTIFY(SIPHandler & handler,SIP_PDU & request)1416 virtual bool OnReceivedNOTIFY(SIPHandler & handler, SIP_PDU & request)
1417 {
1418 // Check for empty body, if so then is OK, just a ping ...
1419 if (request.GetEntityBody().IsEmpty())
1420 return true;
1421
1422 PXML xml;
1423 if (!xml.Load(request.GetEntityBody()))
1424 return false;
1425
1426 PXMLElement * rootElement = xml.GetRootElement();
1427 if (rootElement == NULL || rootElement->GetName() != "dialog-info")
1428 return false;
1429
1430 SIPDialogNotification info(rootElement->GetAttribute("entity"));
1431 if (info.m_entity.IsEmpty())
1432 return false;
1433
1434 PINDEX index = 0;
1435 PXMLElement * dialogElement;
1436 while ((dialogElement = rootElement->GetElement("dialog", index)) != NULL) {
1437 info.m_callId = dialogElement->GetAttribute("call-id");
1438 info.m_local.m_dialogTag = dialogElement->GetAttribute("local-tag");
1439 info.m_remote.m_dialogTag = dialogElement->GetAttribute("remote-tag");
1440
1441 PXMLElement * stateElement = dialogElement->GetElement("state");
1442 if (stateElement == NULL)
1443 info.m_state = SIPDialogNotification::Terminated;
1444 else {
1445 PCaselessString str = stateElement->GetData();
1446 for (info.m_state = SIPDialogNotification::LastState; info.m_state > SIPDialogNotification::FirstState; --info.m_state) {
1447 if (str == info.GetStateName())
1448 break;
1449 }
1450
1451 str = stateElement->GetAttribute("event");
1452 for (info.m_eventType = SIPDialogNotification::LastEvent; info.m_eventType >= SIPDialogNotification::FirstEvent; --info.m_eventType) {
1453 if (str == info.GetEventName())
1454 break;
1455 }
1456
1457 info.m_eventCode = stateElement->GetAttribute("code").AsUnsigned();
1458 }
1459
1460 ParseParticipant(dialogElement->GetElement("local"), info.m_local);
1461 ParseParticipant(dialogElement->GetElement("remote"), info.m_remote);
1462 handler.GetEndPoint().OnDialogInfoReceived(info);
1463 index++;
1464 }
1465
1466 if (index == 0)
1467 handler.GetEndPoint().OnDialogInfoReceived(info);
1468 return true;
1469 }
1470
OnSendNOTIFY(SIPHandler & handler,const PObject * data)1471 virtual PString OnSendNOTIFY(SIPHandler & handler, const PObject * data)
1472 {
1473 PStringStream body;
1474 body << "<?xml version=\"1.0\"?>\r\n"
1475 "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\""
1476 << m_dialogNotifyVersion++ << "\" state=\"partial\" entity=\""
1477 << handler.GetAddressOfRecord() << "\">\r\n";
1478
1479 std::map<PString, SIPDialogNotification>::iterator iter;
1480
1481 const SIPDialogNotification * info = dynamic_cast<const SIPDialogNotification *>(data);
1482 if (info != NULL) {
1483 if (info->m_state != SIPDialogNotification::Terminated)
1484 m_activeDialogs[info->m_callId] = *info;
1485 else {
1486 iter = m_activeDialogs.find(info->m_callId);
1487 if (iter != m_activeDialogs.end())
1488 m_activeDialogs.erase(iter);
1489
1490 body << *info;
1491 }
1492 }
1493
1494 for (iter = m_activeDialogs.begin(); iter != m_activeDialogs.end(); ++iter)
1495 body << iter->second;
1496
1497 body << "</dialog-info>\r\n";
1498 return body;
1499 }
1500
1501 unsigned m_dialogNotifyVersion;
1502 std::map<PString, SIPDialogNotification> m_activeDialogs;
1503 };
1504
1505 static SIPEventPackageFactory::Worker<SIPDialogEventPackageHandler> dialogEventPackageHandler(SIPSubscribe::Dialog);
1506
1507 #endif // P_EXPAT
1508
1509
1510 ///////////////////////////////////////////////////////////////////////////////
1511
SIPDialogNotification(const PString & entity)1512 SIPDialogNotification::SIPDialogNotification(const PString & entity)
1513 : m_entity(entity)
1514 , m_initiator(false)
1515 , m_state(Terminated)
1516 , m_eventType(NoEvent)
1517 , m_eventCode(0)
1518 {
1519 }
1520
1521
GetStateName(States state)1522 PString SIPDialogNotification::GetStateName(States state)
1523 {
1524 static const char * const Names[] = {
1525 "terminated",
1526 "trying",
1527 "proceeding",
1528 "early",
1529 "confirmed"
1530 };
1531 if (state < PARRAYSIZE(Names) && Names[state] != NULL)
1532 return Names[state];
1533
1534 return psprintf("<%u>", state);
1535 }
1536
1537
GetEventName(Events state)1538 PString SIPDialogNotification::GetEventName(Events state)
1539 {
1540 static const char * const Names[] = {
1541 "cancelled",
1542 "rejected",
1543 "replaced",
1544 "local-bye",
1545 "remote-bye",
1546 "error",
1547 "timeout"
1548 };
1549 if (state < PARRAYSIZE(Names) && Names[state] != NULL)
1550 return Names[state];
1551
1552 return psprintf("<%u>", state);
1553 }
1554
1555
OutputParticipant(ostream & strm,const char * name,const SIPDialogNotification::Participant & participant)1556 static void OutputParticipant(ostream & strm, const char * name, const SIPDialogNotification::Participant & participant)
1557 {
1558 if (participant.m_URI.IsEmpty())
1559 return;
1560
1561 strm << " <" << name << ">\r\n";
1562
1563 if (!participant.m_identity.IsEmpty()) {
1564 strm << " <identity";
1565 if (!participant.m_display.IsEmpty())
1566 strm << " display=\"" << participant.m_display << '"';
1567 strm << '>' << participant.m_identity << "</identity>\r\n";
1568 }
1569
1570 strm << " <target uri=\"" << participant.m_URI << "\">\r\n";
1571
1572 if (participant.m_appearance >= 0)
1573 strm << " <param pname=\"appearance\" pval=\"" << participant.m_appearance << "\"/>\r\n"
1574 " <param pname=\"x-line-id\" pval=\"" << participant.m_appearance << "\"/>\r\n";
1575
1576 if (participant.m_byeless)
1577 strm << " <param pname=\"sip.byeless\" pval=\"true\"/>\r\n";
1578
1579 if (participant.m_rendering >= 0)
1580 strm << " <param pname=\"sip.rendering\" pval=\"" << (participant.m_rendering > 0 ? "yes" : "no") << "\"/>\r\n";
1581
1582 strm << " </target>\r\n"
1583 << " </" << name << ">\r\n";
1584 }
1585
1586
PrintOn(ostream & strm) const1587 void SIPDialogNotification::PrintOn(ostream & strm) const
1588 {
1589 if (m_dialogId.IsEmpty())
1590 return;
1591
1592 // Start dialog XML tag
1593 strm << " <dialog id=\"" << m_dialogId << '"';
1594 if (!m_callId)
1595 strm << " call-id=\"" << m_callId << '"';
1596 if (!m_local.m_dialogTag)
1597 strm << " local-tag=\"" << m_local.m_dialogTag << '"';
1598 if (!m_remote.m_dialogTag)
1599 strm << " remote-tag=\"" << m_remote.m_dialogTag << '"';
1600 strm << " direction=\"" << (m_initiator ? "initiator" : "receiver") << "\">\r\n";
1601
1602 // State XML tag & value
1603 strm << " <state";
1604 if (m_eventType > SIPDialogNotification::NoEvent) {
1605 strm << " event=\"" << GetEventName() << '"';
1606 if (m_eventCode > 0)
1607 strm << " code=\"" << m_eventCode << '"';
1608 }
1609 strm << '>' << GetStateName() << "</state>\r\n";
1610
1611 // Participant XML tags (local/remopte)
1612 OutputParticipant(strm, "local", m_local);
1613 OutputParticipant(strm, "remote", m_remote);
1614
1615 // Close out dialog tag
1616 strm << " </dialog>\r\n";
1617 }
1618
1619 /////////////////////////////////////////////////////////////////////////
1620
SIPNotifyHandler(SIPEndPoint & endpoint,const PString & targetAddress,const SIPEventPackage & eventPackage,const SIPDialogContext & dialog)1621 SIPNotifyHandler::SIPNotifyHandler(SIPEndPoint & endpoint,
1622 const PString & targetAddress,
1623 const SIPEventPackage & eventPackage,
1624 const SIPDialogContext & dialog)
1625 : SIPHandler(SIP_PDU::Method_NOTIFY, endpoint, SIPParameters(targetAddress, dialog.GetRemoteURI().AsString()))
1626 , m_eventPackage(eventPackage)
1627 , m_dialog(dialog)
1628 , m_reason(Deactivated)
1629 , m_packageHandler(SIPEventPackageFactory::CreateInstance(eventPackage))
1630 {
1631 m_callID = m_dialog.GetCallID();
1632 }
1633
1634
~SIPNotifyHandler()1635 SIPNotifyHandler::~SIPNotifyHandler()
1636 {
1637 delete m_packageHandler;
1638 }
1639
1640
CreateTransaction(OpalTransport & trans)1641 SIPTransaction * SIPNotifyHandler::CreateTransaction(OpalTransport & trans)
1642 {
1643 PString state;
1644 if (GetExpire() > 0 && GetState() != Unsubscribing)
1645 state.sprintf("active;expires=%u", GetExpire());
1646 else {
1647 state = "terminated;reason=";
1648 static const char * const ReasonNames[] = {
1649 "deactivated",
1650 "probation",
1651 "rejected",
1652 "timeout",
1653 "giveup",
1654 "noresource"
1655 };
1656 state += ReasonNames[m_reason];
1657 }
1658
1659 return new SIPNotify(endpoint, trans, m_dialog, m_eventPackage, state, m_body);
1660 }
1661
1662
SendRequest(SIPHandler::State state)1663 PBoolean SIPNotifyHandler::SendRequest(SIPHandler::State state)
1664 {
1665 // If times out, i.e. Refreshing, then this is actually a time out unsubscribe.
1666 if (state == Refreshing)
1667 m_reason = Timeout;
1668
1669 return SIPHandler::SendRequest(state == Refreshing ? Unsubscribing : state);
1670 }
1671
1672
WriteSIPHandler(OpalTransport & transport,bool forked)1673 bool SIPNotifyHandler::WriteSIPHandler(OpalTransport & transport, bool forked)
1674 {
1675 m_dialog.SetForking(forked);
1676 bool ok = SIPHandler::WriteSIPHandler(transport, false);
1677 m_dialog.SetForking(false);
1678 return ok;
1679 }
1680
1681
SendNotify(const PObject * body)1682 bool SIPNotifyHandler::SendNotify(const PObject * body)
1683 {
1684 if (!LockReadWrite())
1685 return false;
1686
1687 if (m_packageHandler != NULL)
1688 m_body = m_packageHandler->OnSendNOTIFY(*this, body);
1689 else if (body == NULL)
1690 m_body.MakeEmpty();
1691 else {
1692 PStringStream str;
1693 str << *body;
1694 m_body = str;
1695 }
1696
1697 UnlockReadWrite();
1698
1699 return ActivateState(Subscribing);
1700 }
1701
1702
1703 /////////////////////////////////////////////////////////////////////////
1704
SIPPublishHandler(SIPEndPoint & endpoint,const SIPSubscribe::Params & params,const PString & body)1705 SIPPublishHandler::SIPPublishHandler(SIPEndPoint & endpoint,
1706 const SIPSubscribe::Params & params,
1707 const PString & body)
1708 : SIPHandler(SIP_PDU::Method_PUBLISH, endpoint, params)
1709 , m_parameters(params)
1710 , m_body(body)
1711 {
1712 m_parameters.m_proxyAddress = m_proxy.AsString();
1713 }
1714
1715
CreateTransaction(OpalTransport & transport)1716 SIPTransaction * SIPPublishHandler::CreateTransaction(OpalTransport & transport)
1717 {
1718 if (GetState() == Unsubscribing)
1719 return NULL;
1720
1721 m_parameters.m_expire = m_originalExpireTime;
1722 return new SIPPublish(endpoint,
1723 transport,
1724 GetCallID(),
1725 m_sipETag,
1726 m_parameters,
1727 (GetState() == Refreshing) ? PString::Empty() : m_body);
1728 }
1729
1730
OnReceivedOK(SIPTransaction & transaction,SIP_PDU & response)1731 void SIPPublishHandler::OnReceivedOK(SIPTransaction & transaction, SIP_PDU & response)
1732 {
1733 PString newETag = response.GetMIME().GetSIPETag();
1734
1735 if (!newETag.IsEmpty())
1736 m_sipETag = newETag;
1737
1738 SetExpire(response.GetMIME().GetExpires(m_originalExpireTime));
1739
1740 SIPHandler::OnReceivedOK(transaction, response);
1741 }
1742
1743
1744 ///////////////////////////////////////////////////////////////////////
1745
1746 static PAtomicInteger DefaultTupleIdentifier(PRandom::Number());
1747
SIPPresenceInfo(State state)1748 SIPPresenceInfo::SIPPresenceInfo(State state)
1749 : OpalPresenceInfo(state)
1750 , m_tupleId(PString::Printf, "T%08X", ++DefaultTupleIdentifier)
1751 {
1752 }
1753
1754
PrintOn(ostream & strm) const1755 void SIPPresenceInfo::PrintOn(ostream & strm) const
1756 {
1757 if (m_entity.IsEmpty())
1758 return;
1759
1760 if (m_activities.GetSize() > 0)
1761 strm << setfill(',') << m_activities << setfill(' ');
1762 else {
1763 switch (m_state) {
1764 case Unchanged :
1765 strm << "Unchanged";
1766 break;
1767
1768 case NoPresence :
1769 strm << "Closed";
1770 break;
1771
1772 default:
1773 if (m_note.IsEmpty())
1774 strm << "Open";
1775 else
1776 strm << m_note;
1777 }
1778 }
1779 }
1780
1781 // defined in RFC 4480
1782 static const char * const ExtendedSIPActivities[] = {
1783 "appointment",
1784 "away",
1785 "breakfast",
1786 "busy",
1787 "dinner",
1788 "holiday",
1789 "in-transit",
1790 "looking-for-work",
1791 "lunch",
1792 "meal",
1793 "meeting",
1794 "on-the-phone",
1795 "other",
1796 "performance",
1797 "permanent-absence",
1798 "playing",
1799 "presentation",
1800 "shopping",
1801 "sleeping",
1802 "spectator",
1803 "steering",
1804 "travel",
1805 "tv",
1806 "vacation",
1807 "working",
1808 "worship"
1809 };
1810
AsSIPActivityString(State state,PString & str)1811 bool SIPPresenceInfo::AsSIPActivityString(State state, PString & str)
1812 {
1813 if ((state >= Appointment) && (state <= Worship)) {
1814 str = PString(ExtendedSIPActivities[state - Appointment]);
1815 return true;
1816 }
1817
1818 return false;
1819 }
1820
AsSIPActivityString(PString & str) const1821 bool SIPPresenceInfo::AsSIPActivityString(PString & str) const
1822 {
1823 return AsSIPActivityString(m_state, str);
1824 }
1825
FromSIPActivityString(const PString & str)1826 OpalPresenceInfo::State SIPPresenceInfo::FromSIPActivityString(const PString & str)
1827 {
1828 for (size_t i = 0; i < sizeof(ExtendedSIPActivities)/sizeof(ExtendedSIPActivities[0]);++i) {
1829 if (str == ExtendedSIPActivities[i])
1830 return (State)(Appointment + i);
1831 }
1832
1833 return NoPresence;
1834 }
1835
AsXML() const1836 PString SIPPresenceInfo::AsXML() const
1837 {
1838 if (m_entity.IsEmpty() || m_tupleId.IsEmpty()) {
1839 PTRACE(1, "SIP\tCannot encode Presence XML as no address or no id.");
1840 return PString::Empty();
1841 }
1842
1843 PStringStream xml;
1844
1845 xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
1846 "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" "
1847 " xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\""
1848 " xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\""
1849 " entity=\"" << m_entity << "\">\r\n"
1850 " <tuple id=\"" << m_tupleId << "\">\r\n"
1851 " <status>\r\n";
1852 if (m_state != Unchanged)
1853 xml << " <basic>" << (m_state != NoPresence ? "open" : "closed") << "</basic>\r\n";
1854 xml << " </status>\r\n"
1855 " <contact priority=\"1\">";
1856 if (m_contact.IsEmpty())
1857 xml << m_entity;
1858 else
1859 xml << m_contact;
1860 xml << "</contact>\r\n";
1861
1862 if (!m_note.IsEmpty()) {
1863 //xml << " <note xml:lang=\"en\">" << PXML::EscapeSpecialChars(m_note) << "</note>\r\n";
1864 xml << " <note>" << PXML::EscapeSpecialChars(m_note) << "</note>\r\n";
1865 }
1866
1867 xml << " <timestamp>" << PTime().AsString(PTime::RFC3339) << "</timestamp>\r\n"
1868 " </tuple>\r\n";
1869 if (!m_personId.IsEmpty() && (((m_state >= Appointment) && (m_state <= Worship)) || (m_activities.GetSize() > 0))) {
1870 xml << " <dm:person id=\"p" << m_personId << "\">\r\n"
1871 " <rpid:activities>\r\n";
1872 bool doneState = false;
1873 for (PINDEX i = 0; i < m_activities.GetSize(); ++i) {
1874 State s = FromString(m_activities[i]);
1875 if (s >= Appointment) {
1876 if (s == m_state)
1877 doneState = true;
1878 xml << " <rpid:" << ExtendedSIPActivities[s - Appointment] <<"/>\r\n";
1879 }
1880 }
1881 if (!doneState)
1882 xml << " <rpid:" << ExtendedSIPActivities[m_state - Appointment] <<"/>\r\n";
1883
1884 xml << " </rpid:activities>\r\n"
1885 " </dm:person>\r\n";
1886 }
1887
1888 xml << "</presence>\r\n";
1889
1890 return xml;
1891 }
1892
1893
1894 #if P_EXPAT
SetNoteFromElement(PXMLElement * element,PString & note)1895 static void SetNoteFromElement(PXMLElement * element, PString & note)
1896 {
1897 PXMLElement * noteElement = element->GetElement("note");
1898 if (noteElement != NULL)
1899 note = noteElement->GetData();
1900 }
1901
ParseXML(const PString & body,list<SIPPresenceInfo> & infoList,PString & error)1902 bool SIPPresenceInfo::ParseXML(const PString & body,
1903 list<SIPPresenceInfo> & infoList,
1904 PString & error)
1905 {
1906 infoList.clear();
1907
1908 // Check for empty body, if so then is OK, just a ping ...
1909 if (body.IsEmpty()) {
1910 PTRACE(4, "SIPPres\tEmpty body on presence NOTIFY, ignoring");
1911 return true;
1912 }
1913
1914 static PXML::ValidationInfo const StatusValidation[] = {
1915 { PXML::RequiredElement, "basic" },
1916 { PXML::EndOfValidationList }
1917 };
1918
1919 static PXML::ValidationInfo const TupleValidation[] = {
1920 { PXML::RequiredNonEmptyAttribute, "id" },
1921 { PXML::Subtree, "status", { StatusValidation }, 1 },
1922 { PXML::EndOfValidationList }
1923 };
1924
1925 static PXML::ValidationInfo const ActivitiesValidation[] = {
1926 { PXML::OptionalElement, "rpid:busy" },
1927 { PXML::EndOfValidationList }
1928 };
1929
1930 static PXML::ValidationInfo const PersonValidation[] = {
1931 { PXML::Subtree, "rpid:activities", { ActivitiesValidation }, 0, 1 },
1932 { PXML::EndOfValidationList }
1933 };
1934
1935 static PXML::ValidationInfo const PresenceValidation[] = {
1936 { PXML::SetDefaultNamespace, "urn:ietf:params:xml:ns:pidf" },
1937 { PXML::SetNamespace, "dm", { "urn:ietf:params:xml:ns:pidf:data-model" } },
1938 { PXML::SetNamespace, "rpid", { "urn:ietf:params:xml:ns:pidf:rpid" } },
1939 { PXML::ElementName, "presence" },
1940 { PXML::RequiredNonEmptyAttribute, "entity" },
1941 { PXML::Subtree, "tuple", { TupleValidation }, 0 },
1942 { PXML::Subtree, "dm:person", { PersonValidation }, 0, 1 },
1943 { PXML::EndOfValidationList }
1944 };
1945
1946 PXML xml;
1947 if (!xml.LoadAndValidate(body, PresenceValidation, error, PXML::WithNS))
1948 return false;
1949
1950 // Common info to all tuples
1951 PURL entity;
1952 PXMLElement * rootElement = xml.GetRootElement();
1953 if (!entity.Parse(rootElement->GetAttribute("entity"), "pres")) {
1954 error = "Invalid/unsupported entity";
1955 PTRACE(1, "SIPPres\t" << error << " \"" << rootElement->GetAttribute("entity") << '"');
1956 return false;
1957 }
1958
1959 SIPPresenceInfo info;
1960 info.m_tupleId.MakeEmpty();
1961
1962 PTime defaultTimestamp; // Start with "now"
1963
1964 for (PINDEX idx = 0; idx < rootElement->GetSize(); ++idx) {
1965 PXMLElement * element = dynamic_cast<PXMLElement *>(rootElement->GetElement(idx));
1966 if (element == NULL)
1967 continue;
1968
1969 if (element->GetName() == "urn:ietf:params:xml:ns:pidf|tuple") {
1970 PXMLElement * tupleElement = element;
1971
1972 if (!info.m_tupleId.IsEmpty()) {
1973 infoList.push_back(info);
1974 defaultTimestamp = info.m_when - PTimeInterval(0, 1); // One second older
1975 info = SIPPresenceInfo();
1976 }
1977
1978 info.m_entity = entity;
1979 info.m_tupleId = tupleElement->GetAttribute("id");
1980
1981 SetNoteFromElement(rootElement, info.m_note);
1982 SetNoteFromElement(tupleElement, info.m_note);
1983
1984 if ((element = tupleElement->GetElement("status")) != NULL) {
1985 SetNoteFromElement(element, info.m_note);
1986 if ((element = element->GetElement("basic")) != NULL) {
1987 PCaselessString value = element->GetData();
1988 if (value == "open")
1989 info.m_state = Available;
1990 else if (value == "closed")
1991 info.m_state = NoPresence;
1992 }
1993 }
1994
1995 if ((element = tupleElement->GetElement("contact")) != NULL)
1996 info.m_contact = element->GetData();
1997
1998 if ((element = tupleElement->GetElement("timestamp")) == NULL || !info.m_when.Parse(element->GetData()))
1999 info.m_when = defaultTimestamp;
2000 }
2001 else if (element->GetName() == "urn:ietf:params:xml:ns:pidf:data-model|person") {
2002 static PConstCaselessString rpid("urn:ietf:params:xml:ns:pidf:rpid|");
2003 PXMLElement * activities = element->GetElement(rpid + "activities");
2004 if (activities == NULL)
2005 continue;
2006
2007 for (PINDEX i = 0; i < activities->GetSize(); ++i) {
2008 PXMLElement * activity = dynamic_cast<PXMLElement *>(activities->GetElement(i));
2009 if (activity == NULL)
2010 continue;
2011
2012 PCaselessString name(activity->GetName());
2013 if (name.NumCompare(rpid) != PObject::EqualTo)
2014 continue;
2015
2016 name.Delete(0, rpid.GetLength());
2017 info.m_activities.AppendString(name);
2018
2019 State newState = SIPPresenceInfo::FromSIPActivityString(name);
2020 if (newState != SIPPresenceInfo::NoPresence && info.m_state == Available)
2021 info.m_state = newState;
2022 }
2023 }
2024 }
2025
2026 if (!info.m_tupleId.IsEmpty())
2027 infoList.push_back(info);
2028
2029 infoList.sort();
2030
2031 return true;
2032 }
2033 #endif
2034
2035 /////////////////////////////////////////////////////////////////////////
2036
SIPMessageHandler(SIPEndPoint & endpoint,const SIPMessage::Params & params)2037 SIPMessageHandler::SIPMessageHandler(SIPEndPoint & endpoint, const SIPMessage::Params & params)
2038 : SIPHandler(SIP_PDU::Method_MESSAGE, endpoint, params)
2039 , m_parameters(params)
2040 {
2041 m_parameters.m_proxyAddress = m_proxy.AsString();
2042
2043 if (params.m_id.IsEmpty())
2044 m_parameters.m_id = GetCallID();
2045 else
2046 m_callID = params.m_id; // make sure the transation uses the conversation ID, so we can track it
2047
2048 m_offlineExpireTime = 0; // No retries for offline, just give up
2049
2050 SetState(Subscribed);
2051 }
2052
2053
CreateTransaction(OpalTransport & transport)2054 SIPTransaction * SIPMessageHandler::CreateTransaction(OpalTransport & transport)
2055 {
2056 if (GetState() == Unsubscribing)
2057 return NULL;
2058
2059 // If message ID is zero, then it was sent once, don't do it again.
2060 if (m_parameters.m_messageId == 0) {
2061 PTRACE(4, "SIP\tMessage was already sent, not sending again.");
2062 return NULL;
2063 }
2064
2065 SetExpire(m_originalExpireTime);
2066
2067 SIPMessage * msg = new SIPMessage(endpoint, transport, m_parameters);
2068 m_parameters.m_localAddress = msg->GetLocalAddress().AsString();
2069 return msg;
2070 }
2071
2072
OnFailed(SIP_PDU::StatusCodes reason)2073 void SIPMessageHandler::OnFailed(SIP_PDU::StatusCodes reason)
2074 {
2075 SIPHandler::OnFailed(reason);
2076
2077 if (m_parameters.m_messageId != 0) {
2078 endpoint.OnMESSAGECompleted(m_parameters, reason);
2079 m_parameters.m_messageId = 0;
2080 }
2081 }
2082
2083
OnReceivedOK(SIPTransaction & transaction,SIP_PDU & response)2084 void SIPMessageHandler::OnReceivedOK(SIPTransaction & transaction, SIP_PDU & response)
2085 {
2086 SIPHandler::OnReceivedOK(transaction, response);
2087 endpoint.OnMESSAGECompleted(m_parameters, SIP_PDU::Successful_OK);
2088 m_parameters.m_messageId = 0;
2089 }
2090
2091
UpdateParameters(const SIPMessage::Params & params)2092 void SIPMessageHandler::UpdateParameters(const SIPMessage::Params & params)
2093 {
2094 if (params.m_messageId != 0)
2095 m_parameters.m_messageId = params.m_messageId;
2096
2097 if (!params.m_body.IsEmpty()) {
2098 m_parameters.m_body = params.m_body;
2099 m_parameters.m_contentType = params.m_contentType;
2100 }
2101 }
2102
2103
2104 /////////////////////////////////////////////////////////////////////////
2105
SIPOptionsHandler(SIPEndPoint & endpoint,const SIPOptions::Params & params)2106 SIPOptionsHandler::SIPOptionsHandler(SIPEndPoint & endpoint, const SIPOptions::Params & params)
2107 : SIPHandler(SIP_PDU::Method_OPTIONS, endpoint, params)
2108 , m_parameters(params)
2109 {
2110 m_parameters.m_proxyAddress = m_proxy.AsString();
2111
2112 m_offlineExpireTime = 0; // No retries for offline, just give up
2113
2114 /* The "singleton" operation of the OPTION command is executed as though we
2115 are unsubscribing from an existing subscription, so when completed the
2116 handler is disposed of. So, we need to fake the subscribe state. */
2117 SetState(Subscribed);
2118 m_receivedResponse = true;
2119 }
2120
2121
CreateTransaction(OpalTransport & transport)2122 SIPTransaction * SIPOptionsHandler::CreateTransaction(OpalTransport & transport)
2123 {
2124 return new SIPOptions(endpoint, transport, GetCallID(), m_parameters);
2125 }
2126
2127
OnFailed(SIP_PDU::StatusCodes reason)2128 void SIPOptionsHandler::OnFailed(SIP_PDU::StatusCodes reason)
2129 {
2130 SIP_PDU dummy;
2131 dummy.SetStatusCode(reason);
2132 endpoint.OnOptionsCompleted(m_parameters, dummy);
2133 SIPHandler::OnFailed(reason);
2134 }
2135
2136
OnFailed(const SIP_PDU & response)2137 void SIPOptionsHandler::OnFailed(const SIP_PDU & response)
2138 {
2139 endpoint.OnOptionsCompleted(m_parameters, response);
2140 SIPHandler::OnFailed(response.GetStatusCode());
2141 }
2142
2143
OnReceivedOK(SIPTransaction & transaction,SIP_PDU & response)2144 void SIPOptionsHandler::OnReceivedOK(SIPTransaction & transaction, SIP_PDU & response)
2145 {
2146 endpoint.OnOptionsCompleted(m_parameters, response);
2147 SIPHandler::OnReceivedOK(transaction, response);
2148 }
2149
2150
2151 /////////////////////////////////////////////////////////////////////////
2152
SIPPingHandler(SIPEndPoint & endpoint,const PURL & to)2153 SIPPingHandler::SIPPingHandler(SIPEndPoint & endpoint, const PURL & to)
2154 : SIPHandler(SIP_PDU::Method_MESSAGE, endpoint, SIPParameters(to.AsString()))
2155 {
2156 }
2157
2158
CreateTransaction(OpalTransport & transport)2159 SIPTransaction * SIPPingHandler::CreateTransaction(OpalTransport & transport)
2160 {
2161 if (GetState() == Unsubscribing)
2162 return NULL;
2163
2164 return new SIPPing(endpoint, transport, GetAddressOfRecord());
2165 }
2166
2167
2168 //////////////////////////////////////////////////////////////////
2169
2170 /* All of the bwlow search loops run through the list with only
2171 PSafeReference rather than PSafeReadOnly, even though they are
2172 reading fields from the handler instances. We can get away with
2173 this becuase the information being tested, e.g. AOR, is constant
2174 for the life of the handler instance, once constructed.
2175
2176 We need to use PSafeReference as there are some cases where
2177 deadlocks can occur when locked handlers look for information
2178 from other handlers.
2179 */
GetCount(SIP_PDU::Methods meth,const PString & eventPackage) const2180 unsigned SIPHandlersList::GetCount(SIP_PDU::Methods meth, const PString & eventPackage) const
2181 {
2182 unsigned count = 0;
2183 for (PSafePtr<SIPHandler> handler(m_handlersList, PSafeReference); handler != NULL; ++handler)
2184 if (handler->GetState () == SIPHandler::Subscribed &&
2185 handler->GetMethod() == meth &&
2186 (eventPackage.IsEmpty() || handler->GetEventPackage() == eventPackage))
2187 count++;
2188 return count;
2189 }
2190
2191
GetAddresses(bool includeOffline,SIP_PDU::Methods meth,const PString & eventPackage) const2192 PStringList SIPHandlersList::GetAddresses(bool includeOffline, SIP_PDU::Methods meth, const PString & eventPackage) const
2193 {
2194 PStringList addresses;
2195 for (PSafePtr<SIPHandler> handler(m_handlersList, PSafeReference); handler != NULL; ++handler)
2196 if ((includeOffline ? handler->GetState () != SIPHandler::Unsubscribed
2197 : handler->GetState () == SIPHandler::Subscribed) &&
2198 handler->GetMethod() == meth &&
2199 (eventPackage.IsEmpty() || handler->GetEventPackage() == eventPackage))
2200 addresses.AppendString(handler->GetAddressOfRecord().AsString());
2201 return addresses;
2202 }
2203
2204
MakeUrlKey(const PURL & aor,SIP_PDU::Methods method,const PString & eventPackage=PString::Empty ())2205 static PString MakeUrlKey(const PURL & aor, SIP_PDU::Methods method, const PString & eventPackage = PString::Empty())
2206 {
2207 PStringStream key;
2208
2209 key << method << '\n' << aor;
2210
2211 if (!eventPackage.IsEmpty())
2212 key << '\n' << eventPackage;
2213
2214 return key;
2215 }
2216
2217
2218 /**
2219 * called when a handler is added
2220 */
2221
Append(SIPHandler * newHandler)2222 void SIPHandlersList::Append(SIPHandler * newHandler)
2223 {
2224 if (newHandler == NULL)
2225 return;
2226
2227 PWaitAndSignal m(m_extraMutex);
2228
2229 PSafePtr<SIPHandler> handler = m_handlersList.FindWithLock(*newHandler, PSafeReference);
2230 if (handler == NULL)
2231 handler = m_handlersList.Append(newHandler, PSafeReference);
2232
2233 // add entry to call to handler map
2234 handler->m_byCallID = m_byCallID.insert(IndexMap::value_type(handler->GetCallID(), handler));
2235
2236 // add entry to url and package map
2237 handler->m_byAorAndPackage = m_byAorAndPackage.insert(IndexMap::value_type(MakeUrlKey(handler->GetAddressOfRecord(), handler->GetMethod(), handler->GetEventPackage()), handler));
2238
2239 // add entry to username/realm map
2240 PString realm = handler->GetRealm();
2241 if (realm.IsEmpty())
2242 return;
2243
2244 PString username = handler->GetUsername();
2245 if (!username.IsEmpty()) {
2246 handler->m_byAuthIdAndRealm = m_byAuthIdAndRealm.insert(IndexMap::value_type(username + '\n' + realm, handler));
2247 PTRACE_IF(4, !handler->m_byAuthIdAndRealm.second, "Duplicate handler for authId=\"" << username << "\", realm=\"" << realm << '"');
2248 }
2249
2250 username = handler->GetAddressOfRecord().GetUserName();
2251 if (!username.IsEmpty()) {
2252 handler->m_byAorUserAndRealm = m_byAorUserAndRealm.insert(IndexMap::value_type(username + '\n' + realm, handler));
2253 PTRACE_IF(4, !handler->m_byAuthIdAndRealm.second, "Duplicate handler for AOR user=\"" << username << "\", realm=\"" << realm << '"');
2254 }
2255 }
2256
2257
2258 /**
2259 * Called when a handler is removed
2260 */
Remove(SIPHandler * handler)2261 void SIPHandlersList::Remove(SIPHandler * handler)
2262 {
2263 if (handler == NULL)
2264 return;
2265
2266 m_extraMutex.Wait();
2267
2268 if (m_handlersList.Remove(handler))
2269 RemoveIndexes(handler);
2270
2271 m_extraMutex.Signal();
2272 }
2273
2274
Update(SIPHandler * handler)2275 void SIPHandlersList::Update(SIPHandler * handler)
2276 {
2277 if (handler == NULL)
2278 return;
2279
2280 m_extraMutex.Wait();
2281
2282 RemoveIndexes(handler);
2283 Append(handler);
2284
2285 m_extraMutex.Signal();
2286 }
2287
2288
RemoveIndexes(SIPHandler * handler)2289 void SIPHandlersList::RemoveIndexes(SIPHandler * handler)
2290 {
2291 if (handler->m_byAorUserAndRealm.second)
2292 m_byAorUserAndRealm.erase(handler->m_byAorUserAndRealm.first);
2293
2294 if (handler->m_byAuthIdAndRealm.second)
2295 m_byAuthIdAndRealm.erase(handler->m_byAuthIdAndRealm.first);
2296
2297 if (handler->m_byAorAndPackage.second)
2298 m_byAorAndPackage.erase(handler->m_byAorAndPackage.first);
2299
2300 if (handler->m_byCallID.second)
2301 m_byCallID.erase(handler->m_byCallID.first);
2302 }
2303
2304
FindBy(IndexMap & by,const PString & key,PSafetyMode mode)2305 PSafePtr<SIPHandler> SIPHandlersList::FindBy(IndexMap & by, const PString & key, PSafetyMode mode)
2306 {
2307 PSafePtr<SIPHandler> ptr;
2308 {
2309 PWaitAndSignal m(m_extraMutex);
2310
2311 IndexMap::iterator r = by.find(key);
2312 if (r == by.end())
2313 return NULL;
2314
2315 ptr = r->second;
2316 // If above assignement ends up NULL, then entry in IndexMap was deleted
2317 if (ptr == NULL)
2318 return NULL;
2319 }
2320
2321 if (ptr && ptr->GetState() != SIPHandler::Unsubscribed)
2322 return ptr.SetSafetyMode(mode) ? ptr : NULL;
2323
2324 PTRACE(3, "SIP\tHandler " << *ptr << " unsubscribed, awaiting shutdown.");
2325 while (!ptr->ShutDown())
2326 PThread::Sleep(100);
2327
2328 Remove(ptr);
2329 return NULL;
2330 }
2331
2332
FindSIPHandlerByCallID(const PString & callID,PSafetyMode mode)2333 PSafePtr<SIPHandler> SIPHandlersList::FindSIPHandlerByCallID(const PString & callID, PSafetyMode mode)
2334 {
2335 return FindBy(m_byCallID, callID, mode);
2336 }
2337
2338
FindSIPHandlerByUrl(const PURL & aor,SIP_PDU::Methods method,PSafetyMode mode)2339 PSafePtr<SIPHandler> SIPHandlersList::FindSIPHandlerByUrl(const PURL & aor, SIP_PDU::Methods method, PSafetyMode mode)
2340 {
2341 return FindBy(m_byAorAndPackage, MakeUrlKey(aor, method), mode);
2342 }
2343
2344
FindSIPHandlerByUrl(const PURL & aor,SIP_PDU::Methods method,const PString & eventPackage,PSafetyMode mode)2345 PSafePtr<SIPHandler> SIPHandlersList::FindSIPHandlerByUrl(const PURL & aor, SIP_PDU::Methods method, const PString & eventPackage, PSafetyMode mode)
2346 {
2347 return FindBy(m_byAorAndPackage, MakeUrlKey(aor, method, eventPackage), mode);
2348 }
2349
2350
FindSIPHandlerByAuthRealm(const PString & authRealm,PSafetyMode mode)2351 PSafePtr<SIPHandler> SIPHandlersList::FindSIPHandlerByAuthRealm(const PString & authRealm, PSafetyMode mode)
2352 {
2353 // look for a match to realm without users
2354 for (PSafePtr<SIPHandler> handler(m_handlersList, PSafeReference); handler != NULL; ++handler) {
2355 if (handler->GetRealm() == authRealm && handler.SetSafetyMode(mode)) {
2356 PTRACE(4, "SIP\tLocated existing credentials for realm \"" << authRealm << '"');
2357 return handler;
2358 }
2359 }
2360
2361 return NULL;
2362 }
2363
2364
FindSIPHandlerByAuthRealm(const PString & authRealm,const PString & userName,PSafetyMode mode)2365 PSafePtr<SIPHandler> SIPHandlersList::FindSIPHandlerByAuthRealm(const PString & authRealm, const PString & userName, PSafetyMode mode)
2366 {
2367 PSafePtr<SIPHandler> ptr;
2368
2369 // look for a match to exact user name and realm
2370 if ((ptr = FindBy(m_byAuthIdAndRealm, userName + '\n' + authRealm, mode)) != NULL) {
2371 PTRACE(4, "SIP\tLocated existing credentials for ID \"" << userName << "\" at realm \"" << authRealm << '"');
2372 return ptr;
2373 }
2374
2375 // look for a match to exact user name and realm
2376 if ((ptr = FindBy(m_byAorUserAndRealm, userName + '\n' + authRealm, mode)) != NULL) {
2377 PTRACE(4, "SIP\tLocated existing credentials for ID \"" << userName << "\" at realm \"" << authRealm << '"');
2378 return ptr;
2379 }
2380
2381 return NULL;
2382 }
2383
2384
2385 /**
2386 * Find the SIPHandler object with the specified registration host.
2387 * For example, in the above case, the name parameter
2388 * could be "sip.seconix.com" or "seconix.com".
2389 */
FindSIPHandlerByDomain(const PString & name,SIP_PDU::Methods meth,PSafetyMode mode)2390 PSafePtr<SIPHandler> SIPHandlersList::FindSIPHandlerByDomain(const PString & name, SIP_PDU::Methods meth, PSafetyMode mode)
2391 {
2392 for (PSafePtr<SIPHandler> handler(m_handlersList, PSafeReference); handler != NULL; ++handler) {
2393 if ( handler->GetMethod() == meth &&
2394 handler->GetState() != SIPHandler::Unsubscribed &&
2395 (handler->GetAddressOfRecord().GetHostName() == name ||
2396 handler->GetAddressOfRecord().GetHostAddress().IsEquivalent(name)) &&
2397 handler.SetSafetyMode(mode))
2398 return handler;
2399 }
2400 return NULL;
2401 }
2402
2403
2404 #endif // OPAL_SIP
2405