/[resiprocate]/main/resip/recon/UserAgent.cxx
ViewVC logotype

Contents of /main/resip/recon/UserAgent.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9493 - (show annotations) (download)
Sat Apr 7 10:56:50 2012 UTC (7 years, 9 months ago) by dpocock
File MIME type: text/plain
File size: 19760 byte(s)
Include config.h from even more places where it may be needed
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "UserAgent.hxx"
6 #include "UserAgentDialogSetFactory.hxx"
7 #include "UserAgentCmds.hxx"
8 #include "UserAgentServerAuthManager.hxx"
9 #include "UserAgentClientSubscription.hxx"
10 #include "UserAgentRegistration.hxx"
11 #include "ReconSubsystem.hxx"
12
13 #include "FlowManagerSubsystem.hxx"
14
15 #include <ReTurnSubsystem.hxx>
16
17 #include <rutil/Log.hxx>
18 #include <rutil/Logger.hxx>
19 #include <resip/dum/ClientAuthManager.hxx>
20 #include <resip/dum/ClientSubscription.hxx>
21 #include <resip/dum/ServerSubscription.hxx>
22 #include <resip/dum/ClientRegistration.hxx>
23 #include <resip/dum/KeepAliveManager.hxx>
24 #include <resip/dum/AppDialogSet.hxx>
25 #if defined(USE_SSL)
26 #include <resip/stack/ssl/Security.hxx>
27 #endif
28 #include <rutil/WinLeakCheck.hxx>
29
30 using namespace recon;
31 using namespace resip;
32 using namespace std;
33
34 #define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
35
36 UserAgent::UserAgent(ConversationManager* conversationManager, SharedPtr<UserAgentMasterProfile> profile, AfterSocketCreationFuncPtr socketFunc) :
37 mCurrentSubscriptionHandle(1),
38 mCurrentConversationProfileHandle(1),
39 mDefaultOutgoingConversationProfileHandle(0),
40 mConversationManager(conversationManager),
41 mProfile(profile),
42 #if defined(USE_SSL)
43 mSecurity(new Security(profile->certPath())),
44 #else
45 mSecurity(0),
46 #endif
47 mStack(mSecurity, profile->getAdditionalDnsServers(), &mSelectInterruptor, false /* stateless */, socketFunc),
48 mDum(mStack),
49 mStackThread(mStack, mSelectInterruptor),
50 mDumShutdown(false)
51 {
52 assert(mConversationManager);
53 mConversationManager->setUserAgent(this);
54
55 addTransports();
56
57 // Set Enum Suffixes
58 mStack.setEnumSuffixes(profile->getEnumSuffixes());
59
60 // Enable/Disable Statistics Manager
61 mStack.statisticsManagerEnabled() = profile->statisticsManagerEnabled();
62
63 // Install Handlers
64 mDum.setMasterProfile(mProfile);
65 mDum.setClientRegistrationHandler(this);
66 mDum.setClientAuthManager(std::auto_ptr<ClientAuthManager>(new ClientAuthManager));
67 mDum.setKeepAliveManager(std::auto_ptr<KeepAliveManager>(new KeepAliveManager));
68 mDum.setRedirectHandler(mConversationManager);
69 mDum.setInviteSessionHandler(mConversationManager);
70 mDum.setDialogSetHandler(mConversationManager);
71 mDum.addOutOfDialogHandler(OPTIONS, mConversationManager);
72 mDum.addOutOfDialogHandler(REFER, mConversationManager);
73 mDum.addClientSubscriptionHandler("refer", mConversationManager);
74 mDum.addServerSubscriptionHandler("refer", mConversationManager);
75
76 //mDum.addClientSubscriptionHandler(Symbols::Presence, this);
77 //mDum.addClientPublicationHandler(Symbols::Presence, this);
78 //mDum.addOutOfDialogHandler(NOTIFY, this);
79 //mDum.addServerSubscriptionHandler("message-summary", this);
80
81 // Set AppDialogSetFactory
82 auto_ptr<AppDialogSetFactory> dsf(new UserAgentDialogSetFactory(*mConversationManager));
83 mDum.setAppDialogSetFactory(dsf);
84
85 // Set UserAgentServerAuthManager
86 SharedPtr<ServerAuthManager> uasAuth( new UserAgentServerAuthManager(*this));
87 mDum.setServerAuthManager(uasAuth);
88 }
89
90 UserAgent::~UserAgent()
91 {
92 shutdown();
93 }
94
95 void
96 UserAgent::startup()
97 {
98 mStackThread.run();
99 }
100
101 SubscriptionHandle
102 UserAgent::getNewSubscriptionHandle()
103 {
104 Lock lock(mSubscriptionHandleMutex);
105 return mCurrentSubscriptionHandle++;
106 }
107
108 void
109 UserAgent::registerSubscription(UserAgentClientSubscription *subscription)
110 {
111 mSubscriptions[subscription->getSubscriptionHandle()] = subscription;
112 }
113
114 void
115 UserAgent::unregisterSubscription(UserAgentClientSubscription *subscription)
116 {
117 mSubscriptions.erase(subscription->getSubscriptionHandle());
118 }
119
120 ConversationProfileHandle
121 UserAgent::getNewConversationProfileHandle()
122 {
123 Lock lock(mConversationProfileHandleMutex);
124 return mCurrentConversationProfileHandle++;
125 }
126
127 void
128 UserAgent::registerRegistration(UserAgentRegistration *registration)
129 {
130 mRegistrations[registration->getConversationProfileHandle()] = registration;
131 }
132
133 void
134 UserAgent::unregisterRegistration(UserAgentRegistration *registration)
135 {
136 mRegistrations.erase(registration->getConversationProfileHandle());
137 }
138
139 void
140 UserAgent::process(int timeoutMs)
141 {
142 mDum.process(timeoutMs);
143 }
144
145 void
146 UserAgent::shutdown()
147 {
148 UserAgentShutdownCmd* cmd = new UserAgentShutdownCmd(this);
149 mDum.post(cmd);
150
151 // Wait for Dum to shutdown
152 while(!mDumShutdown)
153 {
154 process(100);
155 }
156
157 mStackThread.shutdown();
158 mStackThread.join();
159 }
160
161 void
162 UserAgent::logDnsCache()
163 {
164 mStack.logDnsCache();
165 }
166
167 void
168 UserAgent::clearDnsCache()
169 {
170 mStack.clearDnsCache();
171 }
172
173 void
174 UserAgent::post(ApplicationMessage& message, unsigned int ms)
175 {
176 if(ms > 0)
177 {
178 mStack.postMS(message, ms, &mDum);
179 }
180 else
181 {
182 mDum.post(&message);
183 }
184 }
185
186 void
187 UserAgent::setLogLevel(Log::Level level, LoggingSubsystem subsystem)
188 {
189 switch(subsystem)
190 {
191 case SubsystemAll:
192 Log::setLevel(level);
193 break;
194 case SubsystemContents:
195 Log::setLevel(level, Subsystem::CONTENTS);
196 break;
197 case SubsystemDns:
198 Log::setLevel(level, Subsystem::DNS);
199 break;
200 case SubsystemDum:
201 Log::setLevel(level, Subsystem::DUM);
202 break;
203 case SubsystemSdp:
204 Log::setLevel(level, Subsystem::SDP);
205 break;
206 case SubsystemSip:
207 Log::setLevel(level, Subsystem::SIP);
208 break;
209 case SubsystemTransaction:
210 Log::setLevel(level, Subsystem::TRANSACTION);
211 break;
212 case SubsystemTransport:
213 Log::setLevel(level, Subsystem::TRANSPORT);
214 break;
215 case SubsystemStats:
216 Log::setLevel(level, Subsystem::STATS);
217 break;
218 case SubsystemRecon:
219 Log::setLevel(level, ReconSubsystem::RECON);
220 break;
221 case SubsystemFlowManager:
222 Log::setLevel(level, FlowManagerSubsystem::FLOWMANAGER);
223 break;
224 case SubsystemReTurn:
225 Log::setLevel(level, ReTurnSubsystem::RETURN);
226 break;
227 }
228 }
229
230 ConversationProfileHandle
231 UserAgent::addConversationProfile(SharedPtr<ConversationProfile> conversationProfile, bool defaultOutgoing)
232 {
233 ConversationProfileHandle handle = getNewConversationProfileHandle();
234 AddConversationProfileCmd* cmd = new AddConversationProfileCmd(this, handle, conversationProfile, defaultOutgoing);
235 mDum.post(cmd);
236 return handle;
237 }
238
239 void
240 UserAgent::setDefaultOutgoingConversationProfile(ConversationProfileHandle handle)
241 {
242 SetDefaultOutgoingConversationProfileCmd* cmd = new SetDefaultOutgoingConversationProfileCmd(this, handle);
243 mDum.post(cmd);
244 }
245
246 void
247 UserAgent::destroyConversationProfile(ConversationProfileHandle handle)
248 {
249 DestroyConversationProfileCmd* cmd = new DestroyConversationProfileCmd(this, handle);
250 mDum.post(cmd);
251 }
252
253 SubscriptionHandle
254 UserAgent::createSubscription(const Data& eventType, const NameAddr& target, unsigned int subscriptionTime, const Mime& mimeType)
255 {
256 SubscriptionHandle handle = getNewSubscriptionHandle();
257 CreateSubscriptionCmd* cmd = new CreateSubscriptionCmd(this, handle, eventType, target, subscriptionTime, mimeType);
258 mDum.post(cmd);
259 return handle;
260 }
261
262 void
263 UserAgent::destroySubscription(SubscriptionHandle handle)
264 {
265 DestroySubscriptionCmd* cmd = new DestroySubscriptionCmd(this, handle);
266 mDum.post(cmd);
267 }
268
269
270 SharedPtr<ConversationProfile>
271 UserAgent::getDefaultOutgoingConversationProfile()
272 {
273 if(mDefaultOutgoingConversationProfileHandle != 0)
274 {
275 return mConversationProfiles[mDefaultOutgoingConversationProfileHandle];
276 }
277 else
278 {
279 assert(false);
280 ErrLog( << "getDefaultOutgoingConversationProfile: something is wrong - no profiles to return");
281 return SharedPtr<ConversationProfile>((ConversationProfile*)0);
282 }
283 }
284
285 SharedPtr<ConversationProfile>
286 UserAgent::getIncomingConversationProfile(const SipMessage& msg)
287 {
288 assert(msg.isRequest());
289
290 // Examine the sip message, and select the most appropriate conversation profile
291
292 // Check if request uri matches registration contact
293 const Uri& requestUri = msg.header(h_RequestLine).uri();
294 RegistrationMap::iterator regIt;
295 for(regIt = mRegistrations.begin(); regIt != mRegistrations.end(); regIt++)
296 {
297 const NameAddrs& contacts = regIt->second->getContactAddresses();
298 NameAddrs::const_iterator naIt;
299 for(naIt = contacts.begin(); naIt != contacts.end(); naIt++)
300 {
301 InfoLog( << "getIncomingConversationProfile: comparing requestUri=" << requestUri << " to contactUri=" << (*naIt).uri());
302 if((*naIt).uri() == requestUri)
303 {
304 ConversationProfileMap::iterator conIt = mConversationProfiles.find(regIt->first);
305 if(conIt != mConversationProfiles.end())
306 {
307 return conIt->second;
308 }
309 }
310 }
311 }
312
313 // Check if To header matches default from
314 Data toAor = msg.header(h_To).uri().getAor();
315 ConversationProfileMap::iterator conIt;
316 for(conIt = mConversationProfiles.begin(); conIt != mConversationProfiles.end(); conIt++)
317 {
318 InfoLog( << "getIncomingConversationProfile: comparing toAor=" << toAor << " to defaultFromAor=" << conIt->second->getDefaultFrom().uri().getAor());
319 if(isEqualNoCase(toAor, conIt->second->getDefaultFrom().uri().getAor()))
320 {
321 return conIt->second;
322 }
323 }
324
325 // If can't find any matches, then return the default outgoing profile
326 InfoLog( << "getIncomingConversationProfile: no matching profile found, falling back to default outgoing profile");
327 return getDefaultOutgoingConversationProfile();
328 }
329
330 SharedPtr<UserAgentMasterProfile>
331 UserAgent::getUserAgentMasterProfile()
332 {
333 return mProfile;
334 }
335
336 DialogUsageManager&
337 UserAgent::getDialogUsageManager()
338 {
339 return mDum;
340 }
341
342 ConversationManager*
343 UserAgent::getConversationManager()
344 {
345 return mConversationManager;
346 }
347
348 void
349 UserAgent::onDumCanBeDeleted()
350 {
351 mDumShutdown = true;
352 }
353
354 void
355 UserAgent::addTransports()
356 {
357 const std::vector<UserAgentMasterProfile::TransportInfo>& transports = mProfile->getTransports();
358 std::vector<UserAgentMasterProfile::TransportInfo>::const_iterator i;
359 for(i = transports.begin(); i != transports.end(); i++)
360 {
361 try
362 {
363 switch((*i).mProtocol)
364 {
365 #ifdef USE_SSL
366 case TLS:
367 #ifdef USE_DTLS
368 case DTLS:
369 #endif
370 mDum.addTransport((*i).mProtocol, (*i).mPort, (*i).mIPVersion, (*i).mIPInterface, (*i).mSipDomainname, Data::Empty, (*i).mSslType);
371 break;
372 #endif
373 case UDP:
374 case TCP:
375 mDum.addTransport((*i).mProtocol, (*i).mPort, (*i).mIPVersion, (*i).mIPInterface);
376 break;
377 default:
378 WarningLog (<< "Failed to add " << Tuple::toData((*i).mProtocol) << " transport - unsupported type");
379 }
380 }
381 catch (BaseException& e)
382 {
383 WarningLog (<< "Caught: " << e);
384 WarningLog (<< "Failed to add " << Tuple::toData((*i).mProtocol) << " transport on " << (*i).mPort);
385 }
386 }
387 }
388
389 void
390 UserAgent::startApplicationTimer(unsigned int timerId, unsigned int durationMs, unsigned int seqNumber)
391 {
392 UserAgentTimeout t(*this, timerId, durationMs, seqNumber);
393 post(t, durationMs);
394 }
395
396 void
397 UserAgent::onApplicationTimer(unsigned int timerId, unsigned int durationMs, unsigned int seqNumber)
398 {
399 // Default implementation is to do nothing - application should override this
400 }
401
402 void
403 UserAgent::onSubscriptionTerminated(SubscriptionHandle handle, unsigned int statusCode)
404 {
405 // Default implementation is to do nothing - application should override this
406 }
407
408 void
409 UserAgent::onSubscriptionNotify(SubscriptionHandle handle, const Data& notifyData)
410 {
411 // Default implementation is to do nothing - application should override this
412 }
413
414 void
415 UserAgent::shutdownImpl()
416 {
417 mDum.shutdown(this);
418
419 // End all subscriptions
420 SubscriptionMap tempSubs = mSubscriptions; // Create copy for safety, since ending Subscriptions can immediately remove themselves from map
421 SubscriptionMap::iterator i;
422 for(i = tempSubs.begin(); i != tempSubs.end(); i++)
423 {
424 i->second->end();
425 }
426
427 // Unregister all registrations
428 RegistrationMap tempRegs = mRegistrations; // Create copy for safety, since ending can immediately remove themselves from map
429 RegistrationMap::iterator j;
430 for(j = tempRegs.begin(); j != tempRegs.end(); j++)
431 {
432 j->second->end();
433 }
434
435 mConversationManager->shutdown();
436 }
437
438 void
439 UserAgent::addConversationProfileImpl(ConversationProfileHandle handle, SharedPtr<ConversationProfile> conversationProfile, bool defaultOutgoing)
440 {
441 // Store new profile
442 mConversationProfiles[handle] = conversationProfile;
443 conversationProfile->setHandle(handle);
444
445 #ifdef USE_SSL
446 // If this is the first profile ever set - then use the aor defined in it as the aor used in
447 // the DTLS certificate for the DtlsFactory - TODO - improve this sometime so that we can change the aor in
448 // the cert at runtime to equal the aor in the default conversation profile
449 if(!mDefaultOutgoingConversationProfileHandle)
450 {
451 mConversationManager->getFlowManager().initializeDtlsFactory(conversationProfile->getDefaultFrom().uri().getAor().c_str());
452 }
453 #endif
454
455 // Set the default outgoing if requested to do so, or we don't have one yet
456 if(defaultOutgoing || mDefaultOutgoingConversationProfileHandle == 0)
457 {
458 setDefaultOutgoingConversationProfileImpl(handle);
459 }
460
461 // Register new profile
462 if(conversationProfile->getDefaultRegistrationTime() != 0)
463 {
464 UserAgentRegistration *registration = new UserAgentRegistration(*this, mDum, handle);
465 mDum.send(mDum.makeRegistration(conversationProfile->getDefaultFrom(), conversationProfile, registration));
466 }
467 }
468
469 void
470 UserAgent::setDefaultOutgoingConversationProfileImpl(ConversationProfileHandle handle)
471 {
472 mDefaultOutgoingConversationProfileHandle = handle;
473 }
474
475 void
476 UserAgent::destroyConversationProfileImpl(ConversationProfileHandle handle)
477 {
478 // Remove matching registration if found
479 RegistrationMap::iterator it = mRegistrations.find(handle);
480 if(it != mRegistrations.end())
481 {
482 it->second->end();
483 }
484
485 // Remove from ConversationProfile map
486 mConversationProfiles.erase(handle);
487
488 // If this Conversation Profile was the default - select the first item in the map as the new default
489 if(handle == mDefaultOutgoingConversationProfileHandle)
490 {
491 ConversationProfileMap::iterator it = mConversationProfiles.begin();
492 if(it != mConversationProfiles.end())
493 {
494 setDefaultOutgoingConversationProfileImpl(it->first);
495 }
496 else
497 {
498 setDefaultOutgoingConversationProfileImpl(0);
499 }
500 }
501 }
502
503 void
504 UserAgent::createSubscriptionImpl(SubscriptionHandle handle, const Data& eventType, const NameAddr& target, unsigned int subscriptionTime, const Mime& mimeType)
505 {
506 // Ensure we have a client subscription handler for this event type
507 if(!mDum.getClientSubscriptionHandler(eventType))
508 {
509 mDum.addClientSubscriptionHandler(eventType, this);
510 }
511 // Ensure that the request Mime type is supported in the dum profile
512 if(!mProfile->isMimeTypeSupported(NOTIFY, mimeType))
513 {
514 mProfile->addSupportedMimeType(NOTIFY, mimeType);
515 }
516
517 UserAgentClientSubscription *subscription = new UserAgentClientSubscription(*this, mDum, handle);
518 mDum.send(mDum.makeSubscription(target, getDefaultOutgoingConversationProfile(), eventType, subscriptionTime, subscription));
519 }
520
521 void
522 UserAgent::destroySubscriptionImpl(SubscriptionHandle handle)
523 {
524 SubscriptionMap::iterator it = mSubscriptions.find(handle);
525 if(it != mSubscriptions.end())
526 {
527 it->second->end();
528 }
529 }
530
531 ////////////////////////////////////////////////////////////////////////////////
532 // Registration Handler ////////////////////////////////////////////////////////
533 ////////////////////////////////////////////////////////////////////////////////
534 void
535 UserAgent::onSuccess(ClientRegistrationHandle h, const SipMessage& msg)
536 {
537 dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onSuccess(h, msg);
538 }
539
540 void
541 UserAgent::onFailure(ClientRegistrationHandle h, const SipMessage& msg)
542 {
543 dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onFailure(h, msg);
544 }
545
546 void
547 UserAgent::onRemoved(ClientRegistrationHandle h, const SipMessage&msg)
548 {
549 dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onRemoved(h, msg);
550 }
551
552 int
553 UserAgent::onRequestRetry(ClientRegistrationHandle h, int retryMinimum, const SipMessage& msg)
554 {
555 return dynamic_cast<UserAgentRegistration *>(h->getAppDialogSet().get())->onRequestRetry(h, retryMinimum, msg);
556 }
557
558 ////////////////////////////////////////////////////////////////////////////////
559 // ClientSubscriptionHandler ///////////////////////////////////////////////////
560 ////////////////////////////////////////////////////////////////////////////////
561 void
562 UserAgent::onUpdatePending(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
563 {
564 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onUpdatePending(h, msg, outOfOrder);
565 }
566
567 void
568 UserAgent::onUpdateActive(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
569 {
570 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onUpdateActive(h, msg, outOfOrder);
571 }
572
573 void
574 UserAgent::onUpdateExtension(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
575 {
576 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onUpdateExtension(h, msg, outOfOrder);
577 }
578
579 void
580 UserAgent::onTerminated(ClientSubscriptionHandle h, const SipMessage* msg)
581 {
582 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onTerminated(h, msg);
583 }
584
585 void
586 UserAgent::onNewSubscription(ClientSubscriptionHandle h, const SipMessage& msg)
587 {
588 dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onNewSubscription(h, msg);
589 }
590
591 int
592 UserAgent::onRequestRetry(ClientSubscriptionHandle h, int retryMinimum, const SipMessage& msg)
593 {
594 return dynamic_cast<UserAgentClientSubscription *>(h->getAppDialogSet().get())->onRequestRetry(h, retryMinimum, msg);
595 }
596
597
598 /* ====================================================================
599
600 Copyright (c) 2007-2008, Plantronics, Inc.
601 All rights reserved.
602
603 Redistribution and use in source and binary forms, with or without
604 modification, are permitted provided that the following conditions are
605 met:
606
607 1. Redistributions of source code must retain the above copyright
608 notice, this list of conditions and the following disclaimer.
609
610 2. Redistributions in binary form must reproduce the above copyright
611 notice, this list of conditions and the following disclaimer in the
612 documentation and/or other materials provided with the distribution.
613
614 3. Neither the name of Plantronics nor the names of its contributors
615 may be used to endorse or promote products derived from this
616 software without specific prior written permission.
617
618 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
619 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
620 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
621 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
622 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
623 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
624 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
625 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
626 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
627 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
628 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
629
630 ==================================================================== */

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27