reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
RemoteIMPagerParticipant.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
6#include "Conversation.hxx"
7#include "UserAgent.hxx"
8#include "ReconSubsystem.hxx"
9
10#include <rutil/Log.hxx>
11#include <rutil/Logger.hxx>
12#include <rutil/DnsUtil.hxx>
13#include <rutil/Random.hxx>
18
20
21#include <utility>
22
23using namespace recon;
24using namespace resip;
25using namespace std;
26
27#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
28
29// For incoming
31 ConversationManager& conversationManager) :
32 IMParticipantBase(false /* prependSenderInfoToIMs? */),
33 Participant(partHandle, ConversationManager::ParticipantType_RemoteIMPager, conversationManager),
34 AppDialogSet(conversationManager.getUserAgent()->getDialogUsageManager()),
35 mDum(conversationManager.getUserAgent()->getDialogUsageManager()),
36 mNumOutstandingSends(0),
37 mDelayedDestroyPending(false)
38{
39 InfoLog(<< "RemoteIMPagerParticipant created, handle=" << mHandle);
40 mConversationProfile = nullptr;
41}
42
43// For createRemoteIMPagerParticipant
45 const NameAddr& destination, std::shared_ptr<ConversationProfile> conversationProfile) :
46 IMParticipantBase(true /* prependSenderInfoToIMs? */),
47 Participant(partHandle, ConversationManager::ParticipantType_RemoteIMPager, conversationManager),
48 AppDialogSet(conversationManager.getUserAgent()->getDialogUsageManager()),
49 mDum(conversationManager.getUserAgent()->getDialogUsageManager())
50{
51 InfoLog(<< "RemoteIMPagerParticipant created, handle=" << mHandle);
52 mRemoteUri = destination;
53 mRemoteAorNoPort = mRemoteUri.uri().getAorNoPort();
54
55 if (conversationProfile == nullptr)
56 {
58 }
59 else
60 {
61 mConversationProfile = conversationProfile;
62 }
63
64 mLocalAorNoPort = mConversationProfile->getDefaultFrom().uri().getAorNoPort();
65}
66
68{
69 // Note: Ideally this call would exist in the Participant Base class - but this call requires
70 // dynamic_casts and virtual methods to function correctly during destruction.
71 // If the call is placed in the base Participant class then these things will not
72 // function as desired because a classes type changes as the descructors unwind.
73 // See https://stackoverflow.com/questions/10979250/usage-of-this-in-destructor.
75
76 InfoLog(<< "RemoteIMPagerParticipant destroyed, handle=" << mHandle);
77}
78
79void
81{
82 if (mNumOutstandingSends > 0)
83 {
84 // If we have some outstanding sends, delay the destruction...
85 mDelayedDestroyPending = true;
86 return;
87 }
88
89 try
90 {
91 if (mServerPagerMessageHandle.isValid())
92 {
93 mServerPagerMessageHandle->send(mServerPagerMessageHandle->reject(410 /* Gone */)); // This will also delete the ServerPagerMessage object
94 }
95 if (mClientPagerMessageHandle.isValid())
96 {
97 mClientPagerMessageHandle->end();
98 }
99 else
100 {
101 delete this;
102 }
103 }
104 catch (BaseException& e)
105 {
106 WarningLog(<< "RemoteIMPagerParticipant::destroyParticipant exception: " << e);
107 }
108 catch (...)
109 {
110 WarningLog(<< "RemoteIMPagerParticipant::destroyParticipant unknown exception");
111 }
112}
113
114void
115RemoteIMPagerParticipant::sendInstantMessage(std::unique_ptr<Contents> contents)
116{
117 if (!mClientPagerMessageHandle.isValid())
118 {
119 // If we don't have a ClientPagerMessageHandle yet then we need to create it
120 mClientPagerMessageHandle = mDum.makePagerMessage(mRemoteUri, mConversationProfile, this);
121 }
122 mClientPagerMessageHandle->page(std::move(contents));
123 mNumOutstandingSends++; // Increment until onSuccess or onFailure responses arrive
124}
125
126void
128{
129 try
130 {
131 if (mServerPagerMessageHandle.isValid())
132 {
133 mServerPagerMessageHandle->send(mServerPagerMessageHandle->accept());
134
135 // notify of new message on participant
136 bool relay = false;
137 if (mHandle) relay = mConversationManager.onReceiveIMFromParticipant(mHandle, mInitialIncomingMessage);
138
139 // Relay to others in our conversations, if requested to do so
140 if (relay)
141 {
142 relayInstantMessageToConversations(mInitialIncomingMessage);
143 }
144 }
145 }
146 catch(BaseException &e)
147 {
148 WarningLog(<< "RemoteIMPagerParticipant::accept exception: " << e);
149 }
150 catch(...)
151 {
152 WarningLog(<< "RemoteIMPagerParticipant::accept unknown exception");
153 }
154}
155
156void
157RemoteIMPagerParticipant::reject(unsigned int rejectCode)
158{
159 try
160 {
161 if (mServerPagerMessageHandle.isValid())
162 {
163 mServerPagerMessageHandle->send(mServerPagerMessageHandle->reject(rejectCode));
164 resip_assert(!mClientPagerMessageHandle.isValid());
165 delete this;
166 }
167 }
168 catch(BaseException &e)
169 {
170 WarningLog(<< "RemoteIMPagerParticipant::reject exception: " << e);
171 }
172 catch(...)
173 {
174 WarningLog(<< "RemoteIMPagerParticipant::reject unknown exception");
175 }
176}
177
178bool
180{
181 Data messageToAor = message.header(h_To).uri().getAorNoPort();
182 Data messageFromAor = message.header(h_From).uri().getAorNoPort();
183 bool matches = mLocalAorNoPort == messageToAor && mRemoteAorNoPort == messageFromAor;
184
185 DebugLog(<< "RemoteIMPagerParticipant::doesMessageMatch: partHandle=" << mHandle << ", LocalAor=" << mLocalAorNoPort << ", msgTo=" << messageToAor << ", RemoteAor=" << mRemoteAorNoPort << ", msgFrom=" << messageFromAor << (matches ? " - YES" : " - NO"));
186
187 return matches;
188}
189
191// ClientPagerMessageHandler ///////////////////////////////////////////////////
193void
195{
196 // Note: there is an odd case where we have delayed destruction (ie: mDelayedDestroyPending)
197 // and we execute the delayed destroy before mNumOutstandingSends reaches 0 (because of a
198 // onFailure). In this case we may have artificially set mNumOutstandingSends to 0 in the
199 // onFailure callback, and it's possible that another onSuccess or onFailure callback arrives
200 // before DUM can complete the destruction of this dialogset.
201 if (mNumOutstandingSends > 0)
202 {
203 mNumOutstandingSends--;
204 }
205 if (mDelayedDestroyPending && mNumOutstandingSends == 0)
206 {
207 // Reset mDelayedDestroyPending flag to avoid possibily calling destoryParticipant a 2nd time
208 mDelayedDestroyPending = false;
209
210 // All sends are complete. If we delayed a destroy because messages were pending, it's now safe to destroy.
212 }
213 // TODO: Do we want/need a callback for this?
214}
215
216void
217RemoteIMPagerParticipant::onFailure(ClientPagerMessageHandle h, const SipMessage& status, std::unique_ptr<Contents> contents)
218{
219 // Note: there is an odd case where we have delayed destruction (ie: mDelayedDestroyPending)
220 // and we execute the delayed destroy before mNumOutstandingSends reaches 0 (because of a
221 // onFailure). In this case we may have artificially set mNumOutstandingSends to 0 in the
222 // onFailure callback, and it's possible that another onSuccess or onFailure callback arrives
223 // before DUM can complete the destruction of this dialogset.
224 if (mNumOutstandingSends > 0)
225 {
226 mNumOutstandingSends--;
227 }
228
229 if (mHandle) mConversationManager.onParticipantSendIMFailure(mHandle, status, std::move(contents));
230
231 // Regardless of whether all sends are complete, we execute any delayed destroy now, since one
232 // error likely means more, and we don't want to delay destruction for a long time (ie: while a bunch of
233 // sends timeout and fail).
234 if (mDelayedDestroyPending)
235 {
236 // Reset mNumOutstandingSends so that destoryParticipant will go through
237 mNumOutstandingSends = 0;
238
239 // Reset mDelayedDestroyPending flag to avoid a subsequent onFailure callback, arriving before
240 // destruction is complete, from calling destoryParticipant a 2nd time
241 mDelayedDestroyPending = false;
242
244 }
245}
246
247
249// ServerPagerMessageHandler ///////////////////////////////////////////////////
251void
253{
254 InfoLog(<< "RemoteIMPagerParticipant::onMessageArrived: handle=" << mHandle << ", " << msg.brief());
255
256 mServerPagerMessageHandle = h;
257
258 // Set Remote Display Name if not already set. Note: we only do this when receiving an inbound message, since
259 // that's the only time we can expect that From header display name will be properly filled out.
260 if (mRemoteDisplayName.empty())
261 {
262 mRemoteDisplayName = msg.header(h_From).displayName();
263 if (mRemoteDisplayName.empty())
264 {
265 // If no display name present then use user field
266 mRemoteDisplayName = msg.header(h_From).uri().user();
267 }
268 }
269
270 if (mConversationProfile == nullptr)
271 {
272 // This is the first message
273 mConversationProfile = std::dynamic_pointer_cast<ConversationProfile>(h->getUserProfile());
274 resip_assert(mConversationProfile != nullptr);
275 mInitialIncomingMessage = msg;
276 mRemoteUri = NameAddr(msg.header(h_From).uri());
277 mRemoteAorNoPort = mRemoteUri.uri().getAorNoPort();
278 mLocalAorNoPort = msg.header(h_To).uri().getAorNoPort();
279
280 // notify of new participant
281 if (mHandle) mConversationManager.onIncomingIMPagerParticipant(mHandle, msg, *mConversationProfile);
282 }
283 else
284 {
285 // Automatically accept any subsequent messages received after initial one
286 h->send(h->accept());
287
288 // notify of new message on existing participant
289 bool relay = false;
291
292 // Relay to others in our conversations, if requested to do so
293 if (relay)
294 {
295 relayInstantMessageToConversations(msg);
296 }
297 }
298}
299
300void
301RemoteIMPagerParticipant::relayInstantMessageToConversations(const SipMessage& msg)
302{
303 // Don't relay if sending the message to ourselves, this could end up in an infinite loop if both clients are using recon
304 if (msg.header(h_To).uri().getAOR(false) != msg.header(h_From).uri().getAOR(false))
305 {
306 ConversationMap::iterator it;
307 for (it = mConversations.begin(); it != mConversations.end(); it++)
308 {
309 it->second->relayInstantMessageToRemoteParticipants(mHandle, mRemoteDisplayName, msg);
310 }
311 }
312}
313
314
315/* ====================================================================
316
317 Copyright (c) 2021, SIP Spectrum, Inc. www.sipspectrum.com
318 All rights reserved.
319
320 Redistribution and use in source and binary forms, with or without
321 modification, are permitted provided that the following conditions are
322 met:
323
324 1. Redistributions of source code must retain the above copyright
325 notice, this list of conditions and the following disclaimer.
326
327 2. Redistributions in binary form must reproduce the above copyright
328 notice, this list of conditions and the following disclaimer in the
329 documentation and/or other materials provided with the distribution.
330
331 3. Neither the name of Plantronics nor the names of its contributors
332 may be used to endorse or promote products derived from this
333 software without specific prior written permission.
334
335 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
336 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
337 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
338 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
339 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
340 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
341 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
342 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
343 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
344 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
345 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
346
347 ==================================================================== */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define resip_assert(x)
This file needs to work for both C and C++ code.
This class is one of two main classes of concern to an application using the UserAgent library.
virtual void onParticipantSendIMFailure(ParticipantHandle partHandle, const resip::SipMessage &status, std::unique_ptr< resip::Contents > contents)
Notifies an application that a send IM call has failed.
virtual void onIncomingIMPagerParticipant(ParticipantHandle partHandle, const resip::SipMessage &msg, ConversationProfile &conversationProfile)
Notifies an application about a new remote IM pager mode participant that has sent a message.
virtual bool onReceiveIMFromParticipant(ParticipantHandle partHandle, const resip::SipMessage &msg)
Notifies an application about a subsequent message from remote and existing IM participant.
This class represents base functionality for a participant that supports IMs.
This is the base class for a RemoteParticipant, LocalParticipant and a MediaResourceParticipant.
ConversationMap mConversations
virtual void unregisterFromAllConversations()
ParticipantHandle mHandle
ConversationManager & mConversationManager
virtual void reject(unsigned int rejectCode)
virtual void sendInstantMessage(std::unique_ptr< resip::Contents > contents) override
RemoteIMPagerParticipant(ParticipantHandle partHandle, ConversationManager &conversationManager)
virtual void onMessageArrived(resip::ServerPagerMessageHandle, const resip::SipMessage &message)
virtual void onSuccess(resip::ClientPagerMessageHandle, const resip::SipMessage &status)
virtual bool doesMessageMatch(resip::SipMessage message)
virtual void onFailure(resip::ClientPagerMessageHandle, const resip::SipMessage &status, std::unique_ptr< resip::Contents > contents)
std::shared_ptr< ConversationProfile > getDefaultOutgoingConversationProfile()
The abstract base-class for all exceptions thrown by resip code.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
ClientPagerMessageHandle makePagerMessage(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, AppDialogSet *=nullptr)
bool isValid() const
Definition Handle.hxx:25
virtual Brief brief() const
return a facet for brief encoding of message
Definition Message.cxx:16
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
const Uri & uri() const
Represents a SIP message.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
Data getAorNoPort() const
Definition Uri.cxx:1087
Data getAOR(bool addPort) const
Definition Uri.cxx:999
Data & user()
Definition Uri.hxx:42
unsigned int ParticipantHandle
dcm! – add UnusedChecking(_enum) below;