/[resiprocate]/main/sip/resiprocate/dum/DialogUsageManager.cxx
ViewVC logotype

Contents of /main/sip/resiprocate/dum/DialogUsageManager.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3483 - (show annotations) (download)
Thu Nov 18 19:21:15 2004 UTC (15 years, 2 months ago) by jason
File size: 40826 byte(s)
minor changes related to clearing and setting Contact header. added some assertions related to contact header. 
1 #include "resiprocate/Helper.hxx"
2 #include "resiprocate/SipFrag.hxx"
3 #include "resiprocate/SipMessage.hxx"
4 #include "resiprocate/SipStack.hxx"
5 #include "resiprocate/ShutdownMessage.hxx"
6 #include "resiprocate/dum/AppDialog.hxx"
7 #include "resiprocate/dum/AppDialogSet.hxx"
8 #include "resiprocate/dum/AppDialogSetFactory.hxx"
9 #include "resiprocate/dum/BaseUsage.hxx"
10 #include "resiprocate/dum/ClientAuthManager.hxx"
11 #include "resiprocate/dum/ClientInviteSession.hxx"
12 #include "resiprocate/dum/ClientOutOfDialogReq.hxx"
13 #include "resiprocate/dum/ClientPagerMessage.hxx"
14 #include "resiprocate/dum/ClientPublication.hxx"
15 #include "resiprocate/dum/ClientRegistration.hxx"
16 #include "resiprocate/dum/ClientSubscription.hxx"
17 #include "resiprocate/dum/DefaultServerReferHandler.hxx"
18 #include "resiprocate/dum/Dialog.hxx"
19 #include "resiprocate/dum/DialogUsageManager.hxx"
20 #include "resiprocate/dum/DumException.hxx"
21 #include "resiprocate/dum/DumShutdownHandler.hxx"
22 #include "resiprocate/dum/InviteSessionCreator.hxx"
23 #include "resiprocate/dum/InviteSessionHandler.hxx"
24 #include "resiprocate/dum/OutOfDialogReqCreator.hxx"
25 #include "resiprocate/dum/PagerMessageCreator.hxx"
26 #include "resiprocate/dum/Profile.hxx"
27 #include "resiprocate/dum/PublicationCreator.hxx"
28 #include "resiprocate/dum/RedirectManager.hxx"
29 #include "resiprocate/dum/RegistrationCreator.hxx"
30 #include "resiprocate/dum/ServerAuthManager.hxx"
31 #include "resiprocate/dum/ServerInviteSession.hxx"
32 #include "resiprocate/dum/ServerSubscription.hxx"
33 #include "resiprocate/dum/SubscriptionCreator.hxx"
34 #include "resiprocate/dum/SubscriptionHandler.hxx"
35 #include "resiprocate/os/Inserter.hxx"
36 #include "resiprocate/os/Logger.hxx"
37
38 #if defined(WIN32) && defined(_DEBUG) && defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio
39 #define _CRTDBG_MAP_ALLOC
40 #include <stdlib.h>
41 #include <crtdbg.h>
42 #define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
43 #endif // defined(WIN32) && defined(_DEBUG)
44
45 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
46
47 using namespace resip;
48 using namespace std;
49
50 DialogUsageManager::DialogUsageManager(std::auto_ptr<SipStack> stack) :
51 mProfile(0),
52 mRedirectManager(new RedirectManager()),
53 mInviteSessionHandler(0),
54 mClientRegistrationHandler(0),
55 mServerRegistrationHandler(0),
56 mRedirectHandler(0),
57 mDialogSetHandler(0),
58 mClientPagerMessageHandler(0),
59 mServerPagerMessageHandler(0),
60 mAppDialogSetFactory(new AppDialogSetFactory()),
61 mStack(stack),
62 mStackThread(*mStack),
63 mDumShutdownHandler(0),
64 mShutdownState(Running)
65 {
66 addServerSubscriptionHandler("refer", DefaultServerReferHandler::Instance());
67 }
68
69 DialogUsageManager::~DialogUsageManager()
70 {
71 mShutdownState = Destroying;
72 InfoLog ( << "~DialogUsageManager" );
73 while(!mDialogSetMap.empty())
74 {
75 delete mDialogSetMap.begin()->second;
76 }
77 InfoLog ( << "~DialogUsageManager done" );
78 }
79
80 bool
81 DialogUsageManager::addTransport( TransportType protocol,
82 int port,
83 IpVersion version,
84 const Data& ipInterface)
85 {
86 return mStack->addTransport(protocol, port, version, ipInterface);
87 }
88
89 Data
90 DialogUsageManager::getHostAddress()
91 {
92 return mStack->getHostAddress();
93 }
94
95 void
96 DialogUsageManager::shutdown()
97 {
98 if (mDumShutdownHandler)
99 {
100 switch (mShutdownState)
101 {
102 case ShutdownRequested:
103 mShutdownState = ShuttingDownStack;
104 InfoLog (<< "shutdown SipStack");
105 mStack->shutdown();
106 break;
107 case ShuttingDownStack:
108 InfoLog (<< "Finished dum shutdown");
109 mShutdownState = Shutdown;
110 mDumShutdownHandler->onDumCanBeDeleted();
111 break;
112 default:
113 break;
114 }
115 }
116 }
117
118
119 void
120 DialogUsageManager::shutdown(DumShutdownHandler* h, unsigned long giveUpSeconds)
121 {
122 mDumShutdownHandler = h;
123 mShutdownState = ShutdownRequested;
124 shutdownWhenEmpty();
125 }
126
127 void
128 DialogUsageManager::shutdownIfNoUsages(DumShutdownHandler* h, unsigned long giveUpSeconds)
129 {
130 mDumShutdownHandler = h;
131 mShutdownState = ShutdownRequested;
132 assert(0);
133 }
134
135 void
136 DialogUsageManager::forceShutdown(DumShutdownHandler* h)
137 {
138 mDumShutdownHandler = h;
139 //HandleManager::shutdown(); // clear out usages
140 mShutdownState = ShutdownRequested;
141 DialogUsageManager::shutdown();
142 }
143
144 void DialogUsageManager::setAppDialogSetFactory(std::auto_ptr<AppDialogSetFactory> factory)
145 {
146 mAppDialogSetFactory = factory;
147 }
148
149 Profile*
150 DialogUsageManager::getProfile()
151 {
152 return mProfile;
153 }
154
155 void DialogUsageManager::setProfile(Profile* profile)
156 {
157 mProfile = profile;
158 }
159
160 void DialogUsageManager::setRedirectManager(std::auto_ptr<RedirectManager> manager)
161 {
162 mRedirectManager = manager;
163 }
164
165 void DialogUsageManager::setRedirectHandler(RedirectHandler* handler)
166 {
167 mRedirectHandler = handler;
168 }
169
170 RedirectHandler* DialogUsageManager::getRedirectHandler()
171 {
172 return mRedirectHandler;
173 }
174
175 void
176 DialogUsageManager::setClientAuthManager(std::auto_ptr<ClientAuthManager> manager)
177 {
178 mClientAuthManager = manager;
179 }
180
181 void
182 DialogUsageManager::setServerAuthManager(std::auto_ptr<ServerAuthManager> manager)
183 {
184 mServerAuthManager = manager;
185 }
186
187 void
188 DialogUsageManager::setClientRegistrationHandler(ClientRegistrationHandler* handler)
189 {
190 assert(!mClientRegistrationHandler);
191 mClientRegistrationHandler = handler;
192 }
193
194 void
195 DialogUsageManager::setServerRegistrationHandler(ServerRegistrationHandler* handler)
196 {
197 assert(!mServerRegistrationHandler);
198 mServerRegistrationHandler = handler;
199 }
200
201 void
202 DialogUsageManager::setDialogSetHandler(DialogSetHandler* handler)
203 {
204 mDialogSetHandler = handler;
205 }
206
207 void
208 DialogUsageManager::setInviteSessionHandler(InviteSessionHandler* handler)
209 {
210 assert(!mInviteSessionHandler);
211 mInviteSessionHandler = handler;
212 }
213
214 void
215 DialogUsageManager::addTimer(DumTimeout::Type type, unsigned long duration,
216 BaseUsageHandle target, int cseq, int rseq)
217 {
218 DumTimeout t(type, duration, target, cseq, rseq);
219 mStack->post(t, duration);
220 }
221
222 void
223 DialogUsageManager::addTimerMs(DumTimeout::Type type, unsigned long duration,
224 BaseUsageHandle target, int cseq, int rseq)
225 {
226 DumTimeout t(type, duration, target, cseq, rseq);
227 mStack->postMS(t, duration);
228 }
229
230 void
231 DialogUsageManager::addClientSubscriptionHandler(const Data& eventType, ClientSubscriptionHandler* handler)
232 {
233 assert(handler);
234 assert(mClientSubscriptionHandlers.count(eventType) == 0);
235 mClientSubscriptionHandlers[eventType] = handler;
236 }
237
238 void
239 DialogUsageManager::addServerSubscriptionHandler(const Data& eventType, ServerSubscriptionHandler* handler)
240 {
241 assert(handler);
242 //default do-nothing server side refer handler can be replaced
243 if (eventType == "refer")
244 {
245 delete mServerSubscriptionHandlers[eventType];
246 }
247 else
248 {
249 assert(mServerSubscriptionHandlers.count(eventType) == 0);
250 }
251 mServerSubscriptionHandlers[eventType] = handler;
252 }
253
254 void
255 DialogUsageManager::addClientPublicationHandler(const Data& eventType, ClientPublicationHandler* handler)
256 {
257 assert(handler);
258 assert(mClientPublicationHandlers.count(eventType) == 0);
259 mClientPublicationHandlers[eventType] = handler;
260 }
261
262 void
263 DialogUsageManager::addServerPublicationHandler(const Data& eventType, ServerPublicationHandler* handler)
264 {
265 assert(handler);
266 assert(mServerPublicationHandlers.count(eventType) == 0);
267 mServerPublicationHandlers[eventType] = handler;
268 }
269
270 void
271 DialogUsageManager::addOutOfDialogHandler(MethodTypes type, OutOfDialogHandler* handler)
272 {
273 assert(handler);
274 assert(mOutOfDialogHandlers.count(type) == 0);
275 mOutOfDialogHandlers[type] = handler;
276 }
277
278 void
279 DialogUsageManager::setClientPagerMessageHandler(ClientPagerMessageHandler* handler)
280 {
281 mClientPagerMessageHandler = handler;
282 }
283
284 void
285 DialogUsageManager::setServerPagerMessageHandler(ServerPagerMessageHandler* handler)
286 {
287 mServerPagerMessageHandler = handler;
288 }
289
290 DialogSet*
291 DialogUsageManager::makeUacDialogSet(BaseCreator* creator, AppDialogSet* appDs)
292 {
293 if (mDumShutdownHandler)
294 {
295 throw DumException("Cannot create new sessions when DUM is shutting down.", __FILE__, __LINE__);
296 }
297
298 if (appDs == 0)
299 {
300 appDs = new AppDialogSet(*this);
301 }
302 prepareInitialRequest(creator->getLastRequest());
303 DialogSet* ds = new DialogSet(creator, *this);
304
305 appDs->mDialogSetId = ds->getId();
306 ds->mAppDialogSet = appDs;
307
308 DebugLog ( << "************* Adding DialogSet ***************" );
309 DebugLog ( << "Before: " << Inserter(mDialogSetMap) );
310 mDialogSetMap[ds->getId()] = ds;
311 DebugLog ( << "After: " << Inserter(mDialogSetMap) );
312 return ds;
313 }
314
315 SipMessage&
316 DialogUsageManager::makeNewSession(BaseCreator* creator, AppDialogSet* appDs)
317 {
318 makeUacDialogSet(creator, appDs);
319 return creator->getLastRequest();
320 }
321
322 void
323 DialogUsageManager::makeResponse(SipMessage& response,
324 const SipMessage& request,
325 int responseCode,
326 const Data& reason) const
327 {
328 assert(request.isRequest());
329 Helper::makeResponse(response, request, responseCode, reason);
330 }
331
332 void
333 DialogUsageManager::sendResponse(SipMessage& response)
334 {
335 assert(response.isResponse());
336 mStack->send(response);
337 }
338
339
340 SipMessage&
341 DialogUsageManager::makeInviteSession(const NameAddr& target, const NameAddr& from, const SdpContents* initialOffer, AppDialogSet* appDs)
342 {
343 SipMessage& inv = makeNewSession(new InviteSessionCreator(*this, target, from, initialOffer), appDs);
344 return inv;
345 }
346
347 SipMessage&
348 DialogUsageManager::makeInviteSessionFromRefer(const SipMessage& refer,
349 ServerSubscriptionHandle serverSub,
350 const SdpContents* initialOffer,
351 AppDialogSet* appDs)
352 {
353 //generate and send 100
354 SipFrag contents;
355 contents.message().header(h_StatusLine).statusCode() = 100;
356 contents.message().header(h_StatusLine).reason() = "Trying";
357 //will be cloned...ServerSub may not have the most efficient API possible
358 serverSub->setSubscriptionState(Active);
359 SipMessage& notify = serverSub->update(&contents);
360 // mInviteSessionHandler->onReadyToSend(InviteSessionHandle::NotValid(), notify);
361 serverSub->send(notify);
362
363 //19.1.5
364 NameAddr target = refer.header(h_ReferTo);
365 target.uri().embedded() = SipMessage();
366 target.uri().remove(p_method);
367
368 //could pass dummy target, then apply merge rules from 19.1.5...or
369 //makeNewSession would use rules from 19.1.5
370 NameAddr from = serverSub->mDialog.mLocalNameAddr;
371 from.remove(p_tag);
372
373 SipMessage& inv = makeNewSession(new InviteSessionCreator(*this,
374 target, from,
375 initialOffer, serverSub), appDs);
376
377 if (refer.exists(h_ReferredBy))
378 {
379 inv.header(h_ReferredBy) = refer.header(h_ReferredBy);
380 }
381
382 const Uri& referTo = refer.header(h_ReferTo).uri();
383 //19.1.5
384 if (referTo.hasEmbedded() && referTo.embedded().exists(h_Replaces))
385 {
386 inv.header(h_Replaces) = referTo.embedded().header(h_Replaces);
387 }
388 return inv;
389 }
390
391
392
393 SipMessage&
394 DialogUsageManager::makeSubscription(const NameAddr& target, const NameAddr& from, const Data& eventType, AppDialogSet* appDs)
395 {
396 return makeNewSession(new SubscriptionCreator(*this, target, from, eventType, getProfile()->getDefaultSubscriptionTime()), appDs);
397 }
398
399 SipMessage&
400 DialogUsageManager::makeSubscription(const NameAddr& target, const NameAddr& from, const Data& eventType,
401 int subscriptionTime, AppDialogSet* appDs)
402 {
403 return makeNewSession(new SubscriptionCreator(*this, target, from, eventType, subscriptionTime), appDs);
404 }
405
406 SipMessage&
407 DialogUsageManager::makeSubscription(const NameAddr& target, const NameAddr& from, const Data& eventType,
408 int subscriptionTime, int refreshInterval, AppDialogSet* appDs)
409 {
410 return makeNewSession(new SubscriptionCreator(*this, target, from, eventType, subscriptionTime, refreshInterval), appDs);
411 }
412
413 SipMessage&
414 DialogUsageManager::makeRegistration(const NameAddr& target, AppDialogSet* appDs)
415 {
416 return makeNewSession(new RegistrationCreator(*this, target, getProfile()->getDefaultRegistrationTime()), appDs);
417 }
418
419 SipMessage&
420 DialogUsageManager::makeRegistration(const NameAddr& target, int registrationTime, AppDialogSet* appDs)
421 {
422 return makeNewSession(new RegistrationCreator(*this, target, registrationTime), appDs);
423 }
424
425 SipMessage&
426 DialogUsageManager::makePublication(const NameAddr& targetDocument,
427 const NameAddr& from,
428 const Contents& body,
429 const Data& eventType,
430 unsigned expiresSeconds,
431 AppDialogSet* appDs)
432 {
433 return makeNewSession(new PublicationCreator(*this, targetDocument, from, body, eventType, expiresSeconds), appDs);
434 }
435
436 SipMessage&
437 DialogUsageManager::makeOutOfDialogRequest(const NameAddr& target, const NameAddr& from, const MethodTypes meth, AppDialogSet* appDs)
438 {
439 return makeNewSession(new OutOfDialogReqCreator(*this, meth, target, from), appDs);
440 }
441
442 ClientPagerMessageHandle
443 DialogUsageManager::makePagerMessage(const NameAddr& target, const NameAddr& from, AppDialogSet* appDs)
444 {
445 if (!mClientPagerMessageHandler)
446 {
447 throw DumException("Cannot send MESSAGE messages without a ClientPagerMessageHandler", __FILE__, __LINE__);
448 }
449 DialogSet* ds = makeUacDialogSet(new PagerMessageCreator(*this, target, from), appDs);
450 ClientPagerMessage* cpm = new ClientPagerMessage(*this, *ds);
451 ds->mClientPagerMessage = cpm;
452 return cpm->getHandle();
453 }
454
455 void
456 DialogUsageManager::send(SipMessage& msg)
457 {
458 DebugLog (<< "SEND: " << msg);
459 if (msg.isRequest())
460 {
461 if (getProfile()->hasUserAgent())
462 {
463 msg.header(h_UserAgent).value() = getProfile()->getUserAgent();
464 }
465
466 //this is all very scary and error-prone, as the TU has some retramissions
467 if (msg.header(h_RequestLine).method() != CANCEL &&
468 msg.header(h_RequestLine).method() != ACK &&
469 msg.exists(h_Vias))
470 {
471 msg.header(h_Vias).front().param(p_branch).reset();
472 }
473
474 if (msg.exists(h_Vias) && !mProfile->rportEnabled())
475 {
476 msg.header(h_Vias).front().remove(p_rport);
477 }
478
479 if (mClientAuthManager.get() && msg.header(h_RequestLine).method() != ACK)
480 {
481 mClientAuthManager->addAuthentication(msg);
482 }
483
484 //copy message if processStrictRoute will modify it
485 if (msg.exists(h_Routes) &&
486 !msg.header(h_Routes).empty() &&
487 !msg.header(h_Routes).front().uri().exists(p_lr))
488 {
489 SipMessage copyOfMessage(msg);
490 Helper::processStrictRoute(copyOfMessage);
491 sendUsingOutboundIfAppropriate(copyOfMessage);
492 }
493 else
494 {
495 sendUsingOutboundIfAppropriate(msg);
496 }
497 }
498 else
499 {
500 sendResponse(msg);
501 }
502 }
503
504 void
505 DialogUsageManager::sendUsingOutboundIfAppropriate(SipMessage& msg)
506 {
507 //a little inefficient, branch parameter might be better
508 DialogId id(msg);
509 if (getProfile()->hasOutboundProxy() && !findDialog(id))
510 {
511 DebugLog ( << "Using outbound proxy");
512 mStack->sendTo(msg, getProfile()->getOutboundProxy().uri());
513 }
514 else
515 {
516 mStack->send(msg);
517 }
518 }
519
520
521 void
522 DialogUsageManager::cancel(DialogSetId setid)
523 {
524 DialogSet* ds = findDialogSet(setid);
525 if (ds == 0)
526 {
527 throw Exception("Request no longer exists", __FILE__, __LINE__);
528 }
529 else
530 {
531 ds->cancel();
532 }
533 }
534
535
536 // !jf! maybe this should just be a handler that the application can provide
537 // (one or more of) to futz with the request before it goes out
538 void
539 DialogUsageManager::prepareInitialRequest(SipMessage& request)
540 {
541 // !jf!
542 //request.header(h_Supporteds) = mProfile->getSupportedOptionTags();
543 //request.header(h_Allows) = mProfile->getAllowedMethods();
544 }
545
546 void
547 DialogUsageManager::buildFdSet(FdSet& fdset)
548 {
549 mStack->buildFdSet(fdset);
550 }
551
552 int
553 DialogUsageManager::getTimeTillNextProcessMS()
554 {
555 return mStack->getTimeTillNextProcessMS();
556 }
557
558 Dialog*
559 DialogUsageManager::findDialog(const DialogId& id)
560 {
561 DialogSet* ds = findDialogSet(id.getDialogSetId());
562 if (ds)
563 {
564 return ds->findDialog(id);
565 }
566 else
567 {
568 return 0;
569 }
570 }
571
572
573 InviteSessionHandle
574 DialogUsageManager::findInviteSession(DialogId id)
575 {
576 Dialog* dialog = findDialog(id);
577 if (dialog && dialog->mInviteSession)
578 {
579 return dialog->mInviteSession->getSessionHandle();
580 }
581 else
582 {
583 return InviteSessionHandle::NotValid();
584 }
585 }
586
587 pair<InviteSessionHandle, int>
588 DialogUsageManager::findInviteSession(CallId replaces)
589 {
590 //486/481/603 decision making logic where? App may not wish to keep track of
591 //invitesession state
592 // !slg! Logic is here for now.
593 InviteSessionHandle is = findInviteSession(DialogId(replaces.value(),
594 replaces.param(p_toTag),
595 replaces.param(p_fromTag)));
596 int ErrorStatusCode = 481; // Call/Transaction Does Not Exist
597
598 // If we matched a session - Do RFC3891 Section 3 Processing
599 if(!(is == InviteSessionHandle::NotValid()))
600 {
601 // Note some missing checks are:
602 // 1. If the Replaces header field matches more than one dialog, the UA must act as
603 // if no match was found
604 // 2. Verify that the initiator of the new Invite is authorized
605 if(is->mState == InviteSession::Terminated || is->mState == InviteSession::Cancelled)
606 {
607 ErrorStatusCode = 603; // Declined
608 is = InviteSessionHandle::NotValid();
609 }
610 else if(is->mState == InviteSession::Connected || is->mState == InviteSession::ReInviting) // Confirmed dialog
611 {
612 // Check if early-only flag is present in replaces header
613 if(replaces.exists(p_earlyOnly))
614 {
615 ErrorStatusCode = 486; // Busy Here
616 is = InviteSessionHandle::NotValid();
617 }
618 }
619 else if(is->mState != InviteSession::Early)
620 {
621 // replaces can't be used on early dialogs that were not initiated by this UA - ie. InviteSession::Proceeding state
622 ErrorStatusCode = 481; // Call/Transaction Does Not Exist
623 is = InviteSessionHandle::NotValid();
624 }
625 }
626 return make_pair(is, ErrorStatusCode);
627 }
628
629 void microsoftPreprocess(SipMessage& request)
630 {
631 MethodTypes meth = request.header(h_RequestLine).getMethod();
632
633 if (meth == SUBSCRIBE || meth == NOTIFY || meth == PUBLISH)
634 {
635 if (!request.exists(h_SubscriptionState))
636 {
637 request.header(h_SubscriptionState).value() = "active";
638 }
639 if (!request.exists(h_Event))
640 {
641 SipMessage& ncRequest = const_cast<SipMessage&> (request);
642 ncRequest.header(h_Event).value() = "presence";
643 }
644 }
645 }
646
647 void
648 DialogUsageManager::run()
649 {
650 mStackThread.run();
651 }
652
653 bool
654 DialogUsageManager::process()
655 {
656 // After a Stack ShutdownMessage has been received, don't do anything else in dum
657 if (mShutdownState == Shutdown)
658 {
659 return false;
660 }
661
662 try
663 {
664 std::auto_ptr<Message> msg( mStack->receiveAny() );
665 if (msg.get())
666 {
667 InfoLog (<< "Got: " << msg->brief());
668
669 SipMessage* sipMsg = dynamic_cast<SipMessage*>(msg.get());
670 if (sipMsg)
671 {
672 DebugLog ( << "DialogUsageManager::process: " << sipMsg->brief());
673 if (sipMsg->isRequest())
674 {
675 if( !validateRequestURI(*sipMsg) )
676 {
677 DebugLog (<< "Failed RequestURI validation " << *sipMsg);
678 return true;
679 }
680 if( !validateRequiredOptions(*sipMsg) )
681 {
682 DebugLog (<< "Failed required options validation " << *sipMsg);
683 return true;
684 }
685 if( mProfile->validateContentEnabled() && !validateContent(*sipMsg) )
686 {
687 DebugLog (<< "Failed content validation " << *sipMsg);
688 return true;
689 }
690 if( mProfile->validateAcceptEnabled() && !validateAccept(*sipMsg) )
691 {
692 DebugLog (<< "Failed accept validation " << *sipMsg);
693 return true;
694 }
695 // if ( !validateTo(*sipMsg) )
696 // {
697 // DebugLog (<< "Failed to validation " << *sipMsg);
698 // return true;
699 // }
700 if (sipMsg->header(h_From).exists(p_tag))
701 {
702 if (mergeRequest(*sipMsg) )
703 {
704 InfoLog (<< "Merged request: " << *sipMsg);
705 return true;
706 }
707 }
708
709 if ( mServerAuthManager.get() )
710 {
711 if ( mServerAuthManager->handle(*sipMsg) )
712 {
713 return true;
714 }
715 }
716 //!dcm! -- make this generic and pluggable
717 microsoftPreprocess(*sipMsg);
718 processRequest(*sipMsg);
719 }
720 else if (sipMsg->isResponse())
721 {
722 processResponse(*sipMsg);
723 }
724 return true;
725 }
726
727 DumTimeout* dumMsg = dynamic_cast<DumTimeout*>(msg.get());
728 if (dumMsg )
729 {
730 if ( !dumMsg->getBaseUsage().isValid())
731 {
732 return true;
733 }
734
735 dumMsg->getBaseUsage()->dispatch(*dumMsg);
736 return true;
737 }
738
739 StatisticsMessage* stats = dynamic_cast<StatisticsMessage*>(msg.get());
740 if (stats)
741 {
742 stats->loadOut(mStatsPayload);
743 stats->logStats(RESIPROCATE_SUBSYSTEM, mStatsPayload);
744 }
745
746 ShutdownMessage* end = dynamic_cast<ShutdownMessage*>(msg.get());
747 if (end)
748 {
749 InfoLog (<< "Shutting down stack thread");
750 mStackThread.shutdown();
751 mStackThread.join();
752 DialogUsageManager::shutdown();
753 }
754
755 // !jf! might want to do something with StatisticsMessage
756 //ErrLog(<<"Unknown message received." << msg->brief());
757 //assert(0);
758 return true;
759 }
760 }
761 catch(BaseException& e)
762 {
763 //unparseable, bad 403 w/ 2543 trans it from FWD, etc
764 ErrLog(<<"Illegal message rejected: " << e.getMessage());
765 }
766 return false;
767 }
768
769 void
770 DialogUsageManager::process(FdSet& fdset)
771 {
772 try
773 {
774 mStack->process(fdset);
775 process();
776 }
777 catch(BaseException& e)
778 {
779 //unparseable, bad 403 w/ 2543 trans it from FWD, etc
780 ErrLog(<<"Illegal message rejected: " << e.getMessage());
781 }
782 }
783
784
785 bool
786 DialogUsageManager::validateRequestURI(const SipMessage& request)
787 {
788 // RFC3261 - 8.2.1
789 if (!mProfile->isMethodSupported(request.header(h_RequestLine).getMethod()))
790 {
791 InfoLog (<< "Received an unsupported method: " << request.brief());
792
793 SipMessage failure;
794 makeResponse(failure, request, 405);
795 failure.header(h_Allows) = mProfile->getAllowedMethods();
796 sendResponse(failure);
797
798 return false;
799 }
800
801 // RFC3261 - 8.2.2
802 if (!mProfile->isSchemeSupported(request.header(h_RequestLine).uri().scheme()))
803 {
804 InfoLog (<< "Received an unsupported scheme: " << request.brief());
805 SipMessage failure;
806 makeResponse(failure, request, 416);
807 sendResponse(failure);
808
809 return false;
810 }
811
812 return true;
813 }
814
815
816 bool
817 DialogUsageManager::validateRequiredOptions(const SipMessage& request)
818 {
819 // RFC 2162 - 8.2.2
820 if(request.exists(h_Requires) && // Don't check requires if method is ACK or CANCEL
821 (request.header(h_RequestLine).getMethod() != ACK ||
822 request.header(h_RequestLine).getMethod() != CANCEL))
823 {
824 Tokens unsupported = mProfile->getUnsupportedOptionsTags(request.header(h_Requires));
825 if (!unsupported.empty())
826 {
827 InfoLog (<< "Received an unsupported option tag(s): " << request.brief());
828
829 SipMessage failure;
830 makeResponse(failure, request, 420);
831 failure.header(h_Unsupporteds) = unsupported;
832 sendResponse(failure);
833
834 return false;
835 }
836 }
837
838 return true;
839 }
840
841 bool
842 DialogUsageManager::validateContent(const SipMessage& request)
843 {
844 // RFC3261 - 8.2.3
845 // Don't need to validate content headers if they are specified as optional in the content-disposition
846 if (!(request.exists(h_ContentDisposition) &&
847 request.header(h_ContentDisposition).exists(p_handling) &&
848 isEqualNoCase(request.header(h_ContentDisposition).param(p_handling), Symbols::Optional)))
849 {
850 if (request.exists(h_ContentType) && !mProfile->isMimeTypeSupported(request.header(h_ContentType)))
851 {
852 InfoLog (<< "Received an unsupported mime type: " << request.header(h_ContentType) << " for " << request.brief());
853
854 SipMessage failure;
855 makeResponse(failure, request, 415);
856 failure.header(h_Accepts) = mProfile->getSupportedMimeTypes();
857 sendResponse(failure);
858
859 return false;
860 }
861
862 if (request.exists(h_ContentEncoding) && !mProfile->isContentEncodingSupported(request.header(h_ContentEncoding)))
863 {
864 InfoLog (<< "Received an unsupported mime type: " << request.header(h_ContentEncoding) << " for " << request.brief());
865 SipMessage failure;
866 makeResponse(failure, request, 415);
867 failure.header(h_AcceptEncodings) = mProfile->getSupportedEncodings();
868 sendResponse(failure);
869
870 return false;
871 }
872
873 if (mProfile->validateContentLanguageEnabled() &&
874 request.exists(h_ContentLanguages) && !mProfile->isLanguageSupported(request.header(h_ContentLanguages)))
875 {
876 InfoLog (<< "Received an unsupported language: " << request.header(h_ContentLanguages).front() << " for " << request.brief());
877
878 SipMessage failure;
879 makeResponse(failure, request, 415);
880 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
881 sendResponse(failure);
882
883 return false;
884 }
885 }
886
887 return true;
888 }
889
890 bool
891 DialogUsageManager::validateAccept(const SipMessage& request)
892 {
893 // checks for Accept to comply with SFTF test case 216
894 if(request.exists(h_Accepts))
895 {
896 for (Mimes::const_iterator i = request.header(h_Accepts).begin();
897 i != request.header(h_Accepts).end(); i++)
898 {
899 if (!mProfile->isMimeTypeSupported(*i))
900 {
901 InfoLog (<< "Received an unsupported mime type in accept header: " << request.brief());
902
903 SipMessage failure;
904 makeResponse(failure, request, 406);
905 failure.header(h_Accepts) = mProfile->getSupportedMimeTypes();
906 sendResponse(failure);
907
908 return false;
909 }
910 }
911 }
912 else // If no Accept header then application/sdp should be assumed
913 {
914 if (!mProfile->isMimeTypeSupported(Mime("application", "sdp")))
915 {
916 InfoLog (<< "Received an unsupported default mime type application/sdp for accept header: " << request.brief());
917
918 SipMessage failure;
919 makeResponse(failure, request, 406);
920 failure.header(h_Accepts) = mProfile->getSupportedMimeTypes();
921 sendResponse(failure);
922
923 return false;
924 }
925 }
926
927 return true;
928 }
929
930 bool
931 DialogUsageManager::validateTo(const SipMessage& request)
932 {
933 // !jf! check that the request is targeted at me!
934 // will require support in profile
935 // This should check the Request-Uri (not the To)
936 return true;
937 }
938
939 bool
940 DialogUsageManager::mergeRequest(const SipMessage& request)
941 {
942 assert(request.isRequest());
943 assert(request.isExternal());
944
945 if (!request.header(h_To).exists(p_tag))
946 {
947 if (mMergedRequests.count(MergedRequestKey(request)))
948 {
949 SipMessage failure;
950 makeResponse(failure, request, 482, "Merged Request");
951 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
952 sendResponse(failure);
953 return true;
954 }
955 }
956
957 return false;
958 }
959
960 void
961 DialogUsageManager::processRequest(const SipMessage& request)
962 {
963 DebugLog ( << "DialogUsageManager::processRequest: " << request.brief());
964
965 assert(mAppDialogSetFactory.get());
966 //!dcm! -- fix to use findDialog
967 if (!request.header(h_To).exists(p_tag))
968 {
969 switch (request.header(h_RequestLine).getMethod())
970 {
971 case ACK:
972 DebugLog (<< "Discarding request: " << request.brief());
973 break;
974
975 case PRACK:
976 case BYE:
977 case UPDATE:
978 //case INFO: // !rm! in an ideal world
979 //case NOTIFY: // !rm! in an ideal world
980 {
981 SipMessage failure;
982 makeResponse(failure, request, 481);
983 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
984 sendResponse(failure);
985 break;
986 }
987 case CANCEL:
988 {
989 // find the appropropriate ServerInvSession
990 DialogSet* ds = findDialogSet(DialogSetId(request));
991 if (ds == 0)
992 {
993 //!dcm! -- temporary hack...do a map by TID?
994 for (DialogSetMap::iterator it = mDialogSetMap.begin(); it != mDialogSetMap.end(); it++)
995 {
996 if (it->second->getId().getCallId() == request.header(h_CallID).value())
997 {
998 it->second->dispatch(request);
999 return;
1000 }
1001 }
1002 InfoLog (<< "Received a CANCEL on a non-existent transaction ");
1003 SipMessage failure;
1004 makeResponse(failure, request, 481);
1005 sendResponse(failure);
1006 }
1007 else
1008 {
1009 ds->dispatch(request);
1010 }
1011 break;
1012 }
1013
1014 case SUBSCRIBE:
1015 case PUBLISH:
1016 if (!checkEventPackage(request))
1017 {
1018 InfoLog (<< "Rejecting request (unsupported package) " << request.brief());
1019 return;
1020 }
1021 case NOTIFY : // handle unsolicited (illegal) NOTIFYs
1022 case INVITE: // new INVITE
1023 case REFER: // out-of-dialog REFER
1024 case INFO : // handle non-dialog (illegal) INFOs
1025 case OPTIONS : // handle non-dialog OPTIONS
1026 case MESSAGE :
1027 {
1028 {
1029 DialogSetId id(request);
1030 //cryptographically dangerous
1031 assert(mDialogSetMap.find(id) == mDialogSetMap.end());
1032 }
1033 if (mDumShutdownHandler)
1034 {
1035 SipMessage forbidden;
1036 makeResponse(forbidden, request, 480);
1037 forbidden.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
1038 sendResponse(forbidden);
1039 return;
1040 }
1041 try
1042 {
1043 DialogSet* dset = new DialogSet(request, *this);
1044
1045 DebugLog ( << "*********** Calling AppDialogSetFactory *************" );
1046 AppDialogSet* appDs = mAppDialogSetFactory->createAppDialogSet(*this, request);
1047 appDs->mDialogSetId = dset->getId();
1048 dset->mAppDialogSet = appDs;
1049
1050 DebugLog ( << "************* Adding DialogSet ***************" );
1051 DebugLog ( << "Before: " << Inserter(mDialogSetMap) );
1052 mDialogSetMap[dset->getId()] = dset;
1053 DebugLog ( << "After: " << Inserter(mDialogSetMap) );
1054
1055 dset->dispatch(request);
1056 }
1057 catch (BaseException& e)
1058 {
1059 SipMessage failure;
1060 makeResponse(failure, request, 400, e.getMessage());
1061 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
1062 sendResponse(failure);
1063 }
1064
1065 break;
1066 }
1067 case REGISTER:
1068 {
1069 SipMessage failure;
1070 makeResponse(failure, request, 405);
1071 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
1072 sendResponse(failure);
1073 }
1074 break;
1075 case RESPONSE:
1076 case SERVICE:
1077 assert(false);
1078 break;
1079 case UNKNOWN:
1080 case MAX_METHODS:
1081 assert(false);
1082 break;
1083 }
1084 }
1085 else // in a specific dialog
1086 {
1087 switch (request.header(h_RequestLine).getMethod())
1088 {
1089 case REGISTER:
1090 {
1091 SipMessage failure;
1092 makeResponse(failure, request, 400, "rjs says, Go to hell");
1093 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
1094 sendResponse(failure);
1095 break;
1096 }
1097
1098 default:
1099 {
1100 DialogSet* ds = findDialogSet(DialogSetId(request));
1101 if (ds == 0)
1102 {
1103 SipMessage failure;
1104 makeResponse(failure, request, 481);
1105 failure.header(h_AcceptLanguages) = mProfile->getSupportedLanguages();
1106 InfoLog (<< "Rejected request (which was in a dialog) " << request.brief());
1107 sendResponse(failure);
1108 }
1109 else
1110 {
1111 InfoLog (<< "Handling in-dialog request: " << request.brief());
1112 ds->dispatch(request);
1113 }
1114 }
1115 }
1116 }
1117 }
1118
1119 void
1120 DialogUsageManager::processResponse(const SipMessage& response)
1121 {
1122 DebugLog ( << "DialogUsageManager::processResponse: " << response);
1123 if (/*response.header(h_StatusLine).statusCode() > 100 && */
1124 response.header(h_CSeq).method() != CANCEL)
1125 {
1126 DialogSet* ds = findDialogSet(DialogSetId(response));
1127
1128 if (ds)
1129 {
1130 DebugLog ( << "DialogUsageManager::processResponse: " << response.brief());
1131 ds->dispatch(response);
1132 }
1133 else
1134 {
1135 InfoLog (<< "Throwing away stray response: " << response.brief());
1136 }
1137 }
1138 }
1139
1140 bool
1141 DialogUsageManager::checkEventPackage(const SipMessage& request)
1142 {
1143 int failureCode = 0;
1144 MethodTypes method = request.header(h_RequestLine).method();
1145
1146 // || (method == NOTIFY && !request.exists(h_SubscriptionState)))
1147
1148 if (!request.exists(h_Event))
1149 {
1150 failureCode = 400;
1151 }
1152 else
1153 {
1154 switch(method)
1155 {
1156 case SUBSCRIBE:
1157 if (!getServerSubscriptionHandler(request.header(h_Event).value()))
1158 {
1159 failureCode = 489;
1160 }
1161 break;
1162 case NOTIFY:
1163 if (!getClientSubscriptionHandler(request.header(h_Event).value()))
1164 {
1165 failureCode = 489;
1166 }
1167 break;
1168 case PUBLISH:
1169 assert(0);
1170 default:
1171 assert(0);
1172 }
1173 }
1174
1175 if (failureCode > 0)
1176 {
1177 SipMessage response;
1178 makeResponse(response, request, failureCode);
1179 send(response);
1180 return false;
1181 }
1182 return true;
1183 }
1184
1185 DialogSet*
1186 DialogUsageManager::findDialogSet(const DialogSetId& id)
1187 {
1188 DebugLog ( << "Looking for dialogSet: " << id << " in map:" );
1189 DebugLog ( << Inserter(mDialogSetMap) );
1190 DialogSetMap::const_iterator it = mDialogSetMap.find(id);
1191
1192 if (it == mDialogSetMap.end())
1193 {
1194 return 0;
1195 }
1196 else
1197 {
1198 return it->second;
1199 }
1200 }
1201
1202 BaseCreator*
1203 DialogUsageManager::findCreator(const DialogId& id)
1204 {
1205 DialogSet* ds = findDialogSet(id.getDialogSetId());
1206 if (ds)
1207 {
1208 return ds->getCreator();
1209 }
1210 else
1211 {
1212 return 0;
1213 }
1214 }
1215
1216 void
1217 DialogUsageManager::removeDialogSet(const DialogSetId& dsId)
1218 {
1219 DebugLog ( << "************* Removing DialogSet ***************" );
1220 DebugLog ( << "Before: " << Inserter(mDialogSetMap) );
1221 mDialogSetMap.erase(dsId);
1222 DebugLog ( << "After: " << Inserter(mDialogSetMap) );
1223 if (mRedirectManager.get())
1224 {
1225 mRedirectManager->removeDialogSet(dsId);
1226 }
1227 }
1228
1229 ClientSubscriptionHandler*
1230 DialogUsageManager::getClientSubscriptionHandler(const Data& eventType)
1231 {
1232 map<Data, ClientSubscriptionHandler*>::iterator res = mClientSubscriptionHandlers.find(eventType);
1233 if (res != mClientSubscriptionHandlers.end())
1234 {
1235 return res->second;
1236 }
1237 else
1238 {
1239 return 0;
1240 }
1241 }
1242
1243 ServerSubscriptionHandler*
1244 DialogUsageManager::getServerSubscriptionHandler(const Data& eventType)
1245 {
1246 map<Data, ServerSubscriptionHandler*>::iterator res = mServerSubscriptionHandlers.find(eventType);
1247 if (res != mServerSubscriptionHandlers.end())
1248 {
1249 return res->second;
1250 }
1251 else
1252 {
1253 return 0;
1254 }
1255 }
1256
1257 ClientPublicationHandler*
1258 DialogUsageManager::getClientPublicationHandler(const Data& eventType)
1259 {
1260 map<Data, ClientPublicationHandler*>::iterator res = mClientPublicationHandlers.find(eventType);
1261 if (res != mClientPublicationHandlers.end())
1262 {
1263 return res->second;
1264 }
1265 else
1266 {
1267 return 0;
1268 }
1269 }
1270
1271 ServerPublicationHandler*
1272 DialogUsageManager::getServerPublicationHandler(const Data& eventType)
1273 {
1274 map<Data, ServerPublicationHandler*>::iterator res = mServerPublicationHandlers.find(eventType);
1275 if (res != mServerPublicationHandlers.end())
1276 {
1277 return res->second;
1278 }
1279 else
1280 {
1281 return 0;
1282 }
1283 }
1284
1285 OutOfDialogHandler*
1286 DialogUsageManager::getOutOfDialogHandler(const MethodTypes type)
1287 {
1288 map<MethodTypes, OutOfDialogHandler*>::iterator res = mOutOfDialogHandlers.find(type);
1289 if (res != mOutOfDialogHandlers.end())
1290 {
1291 return res->second;
1292 }
1293 else
1294 {
1295 return 0;
1296 }
1297 }
1298
1299
1300
1301
1302
1303 /* ====================================================================
1304 * The Vovida Software License, Version 1.0
1305 *
1306 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1307 *
1308 * Redistribution and use in source and binary forms, with or without
1309 * modification, are permitted provided that the following conditions
1310 * are met:
1311 *
1312 * 1. Redistributions of source code must retain the above copyright
1313 * notice, this list of conditions and the following disclaimer.
1314 *
1315 * 2. Redistributions in binary form must reproduce the above copyright
1316 * notice, this list of conditions and the following disclaimer in
1317 * the documentation and/or other materials provided with the
1318 * distribution.
1319 *
1320 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1321 * and "Vovida Open Communication Application Library (VOCAL)" must
1322 * not be used to endorse or promote products derived from this
1323 * software without prior written permission. For written
1324 * permission, please contact vocal@vovida.org.
1325 *
1326 * 4. Products derived from this software may not be called "VOCAL", nor
1327 * may "VOCAL" appear in their name, without prior written
1328 * permission of Vovida Networks, Inc.
1329 *
1330 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1331 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1332 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1333 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1334 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1335 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1336 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1337 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1338 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1339 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1340 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1341 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1342 * DAMAGE.
1343 *
1344 * ====================================================================
1345 *
1346 * This software consists of voluntary contributions made by Vovida
1347 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1348 * Inc. For more information on Vovida Networks, Inc., please see
1349 * <http://www.vovida.org/>.
1350 *
1351 */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27