reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
SipXRemoteParticipantDialogSet.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5// sipX includes
6#if (_MSC_VER >= 1600)
7#include <stdint.h> // Use Visual Studio's stdint.h
8#define _MSC_STDINT_H_ // This define will ensure that stdint.h in sipXport tree is not used
9#endif
10#include <CpTopologyGraphInterface.h>
11
13#include "ReconSubsystem.hxx"
16#include "Conversation.hxx"
17#include "UserAgent.hxx"
18#include "MediaStreamEvent.hxx"
20
21// Flowmanager Includes
23#include "reflow/Flow.hxx"
25
28
29#include <rutil/Log.hxx>
30#include <rutil/Logger.hxx>
31#include <rutil/Random.hxx>
32#include <rutil/DnsUtil.hxx>
36
37//#define DISABLE_FLOWMANAGER_IF_NO_NAT_TRAVERSAL
39
40#include <utility>
41
42using namespace recon;
43using namespace resip;
44using namespace std;
45
46#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
47
49 SipXMediaStackAdapter& sipXMediaStackAdapter,
51 std::shared_ptr<ConversationProfile> conversationProfile) :
52 RemoteParticipantDialogSet(conversationManager, forkSelectMode, conversationProfile),
53 mSipXMediaStackAdapter(sipXMediaStackAdapter),
54 mLocalRTPPort(0),
55 mAllocateLocalRTPPortFailed(false),
56 mFlowContext(new FlowContext()),
57 mPeerExpectsSAVPF(false),
58 mNatTraversalMode(flowmanager::MediaStream::NoNatTraversal),
59 mMediaStream(0),
60 mRtpSocket(0),
61 mRtcpSocket(0),
62 mMediaConnectionId(0),
63 mConnectionPortOnBridge(-1)
64{
65
66 InfoLog(<< "SipXRemoteParticipantDialogSet created.");
67}
68
70{
72 InfoLog(<< "SipXRemoteParticipantDialogSet destroyed. mActiveRemoteParticipantHandle=" << getActiveRemoteParticipantHandle());
73}
74
75// Allocates an RTP port from the RTPPortManager, for the media stream to bind it and the RTCP port after
76// it: one that another socket has (eg. another application's) is skipped, as a UDP socket can't share
77// it. TURN over TCP and TLS binds TCP sockets instead - with SO_REUSEADDR, as resip's are - so their
78// ports aren't checked.
79unsigned int
80SipXRemoteParticipantDialogSet::allocateRTPPort()
81{
83 resip_assert(profile);
84 std::shared_ptr<RTPPortManager> portManager = mSipXMediaStackAdapter.getRTPPortManager();
87 {
88 return portManager->allocateRTPPort();
89 }
90 return portManager->allocateRTPPort(profile->sessionCaps().session().connection().getAddress());
91}
92
93unsigned int
95{
96 if(mLocalRTPPort == 0 && !mAllocateLocalRTPPortFailed)
97 {
98 mLocalRTPPort = allocateRTPPort();
99 if(mLocalRTPPort == 0)
100 {
101 WarningLog(<< "Could not allocate a free RTP port for RemoteParticipantDialogSet!");
102 mAllocateLocalRTPPortFailed = true;
103 return 0;
104 }
105 else
106 {
107 InfoLog(<< "Port allocated: " << mLocalRTPPort);
108 }
109
111 resip_assert(profile);
112
113 OsStatus ret;
114 Data connectionAddr = profile->sessionCaps().session().connection().getAddress();
115 DebugLog(<< "getLocalRTPPort: Using local connection address: " << connectionAddr);
116 // Create localBinding Tuple - note: transport may be changed depending on NAT traversal mode
117 StunTuple localBinding(StunTuple::UDP, asio::ip::make_address(connectionAddr.c_str()), mLocalRTPPort);
118
119 switch(profile->natTraversalMode())
120 {
122 // Use straight UDP with Stun Binding discovery
123 mNatTraversalMode = MediaStream::StunBindDiscovery;
124 break;
126 // Use Udp turn media relay
127 mNatTraversalMode = MediaStream::TurnAllocation;
128 break;
130 // Use Tcp turn media relay
131 localBinding.setTransportType(StunTuple::TCP);
132 mNatTraversalMode = MediaStream::TurnAllocation;
133 break;
134#ifdef USE_SSL
136 // Use TLS turn media relay
137 localBinding.setTransportType(StunTuple::TLS);
138 mNatTraversalMode = MediaStream::TurnAllocation;
139 break;
140#endif
142 default:
143 // Use straight UDP
144 mNatTraversalMode = MediaStream::NoNatTraversal;
145 break;
146 }
147
148#ifdef USE_SSL
150 mNatTraversalMode == MediaStream::TurnAllocation)
151 {
152 WarningLog(<< "You cannot use SrtpDtls and a Turn allocation at the same time - disabling SrtpDtls!");
154 }
155 else
156#endif
157 {
160 }
161
162 // Set other Srtp properties
163 mLocalSrtpSessionKey = Random::getCryptoRandom(SRTP_MASTER_KEY_LEN);
165
166 switch(profile->secureMediaDefaultCryptoSuite())
167 {
170 break;
171 default:
173 break;
174 }
175
176#ifdef DISABLE_FLOWMANAGER_IF_NO_NAT_TRAVERSAL
177 if(mNatTraversalMode != MediaStream::NoNatTraversal)
178 {
179#endif
180 mMediaStream = mSipXMediaStackAdapter.getFlowManager().createMediaStream(
181 *this,
182 localBinding,
183 true /* rtcp? */,
184 mNatTraversalMode,
185 profile->natTraversalServerHostname().c_str(),
186 profile->natTraversalServerPort(),
187 profile->stunUsername().c_str(),
188 profile->stunPassword().c_str(),
189 profile->forceCOMedia(),
190 mFlowContext);
191
192 // New Remote Participant - create media Interface connection
193 mRtpSocket = new FlowManagerSipXSocket(mMediaStream->getRtpFlow(), mSipXMediaStackAdapter.mSipXTOSValue);
194 mRtcpSocket = new FlowManagerSipXSocket(mMediaStream->getRtcpFlow(), mSipXMediaStackAdapter.mSipXTOSValue);
195
196 ret = getMediaInterface()->createConnection(mMediaConnectionId, getActiveRemoteParticipantHandle(), mRtpSocket, mRtcpSocket);
197#ifdef DISABLE_FLOWMANAGER_IF_NO_NAT_TRAVERSAL
198 }
199 else
200 {
201 ret = getMediaInterface()->createConnection(mMediaConnectionId, getActiveRemoteParticipantHandle(),
202 connectionAddr.c_str(),
203 mLocalRTPPort);
204 mRtpTuple = localBinding; // Just treat media stream as immediately ready using the localBinding in the SDP
205 }
206#endif
207
208 if(ret == OS_SUCCESS)
209 {
210 // Get the capabilities so that we can ensure there are codecs loaded
211 UtlString rtpHostAddress;
212 int rtpAudioPort;
213 int rtcpAudioPort;
214 int rtpVideoPort;
215 int rtcpVideoPort;
216 SdpCodecList supportedCodecs;
217 SdpSrtpParameters srtpParameters;
218 int bandWidth = 0;
219 int videoBandwidth;
220 int videoFramerate;
221
222 ret = getMediaInterface()->getInterface()->getCapabilities(
223 mMediaConnectionId,
224 rtpHostAddress,
225 rtpAudioPort,
226 rtcpAudioPort,
227 rtpVideoPort,
228 rtcpVideoPort,
229 supportedCodecs,
230 srtpParameters,
231 bandWidth,
232 videoBandwidth,
233 videoFramerate);
234
235 if(ret == OS_SUCCESS)
236 {
237 if(supportedCodecs.getCodecCount() == 0)
238 {
239 ErrLog( << "No supported codecs!!!!!");
240 }
241 }
242 else
243 {
244 ErrLog( << "Error getting connection capabilities, ret=" << ret);
245 }
246 }
247 else
248 {
249 ErrLog( << "Error creating connection, ret=" << ret);
250 }
251
252 //InfoLog(<< "About to get Connection Port on Bridge for MediaConnectionId: " << mMediaConnectionId);
253 ret = getMediaInterface()->getInterface()->getConnectionPortOnBridge(mMediaConnectionId, 0, mConnectionPortOnBridge);
254 InfoLog( << "RTP Port allocated=" << mLocalRTPPort << " (sipXmediaConnectionId=" << mMediaConnectionId << ", BridgePort=" << mConnectionPortOnBridge << ", ret=" << ret << ")");
255 }
256
257 return mLocalRTPPort;
258}
259
260void
261SipXRemoteParticipantDialogSet::processMediaStreamReadyEvent(std::shared_ptr<MediaStreamReadyEvent::StreamParams> streamParams)
262{
264 InfoLog( << "processMediaStreamReadyEvent: streamParams: " << *params);
265 mRtpTuple = params->getRtpTuple();
266 mRtcpTuple = params->getRtcpTuple(); // Check if we had operations pending on the media stream being ready
267
269}
270
271void
272SipXRemoteParticipantDialogSet::onMediaStreamReady(const StunTuple& rtpTuple, const StunTuple& rtcpTuple)
273{
274 // Get event into dum queue, so that callback is on dum thread
275 MediaStreamReadyEvent* event = new MediaStreamReadyEvent(&mConversationManager, mActiveRemoteParticipantHandle, std::make_shared<MediaStreamReadyEvent::ReTurnParams>(rtpTuple, rtcpTuple));
276 mDum.post(event);
277}
278
279void
280SipXRemoteParticipantDialogSet::onMediaStreamError(unsigned int errorCode)
281{
282 // Get event into dum queue, so that callback is on dum thread
284 mDum.post(event);
285}
286
287
288std::shared_ptr<SipXMediaInterface>
289SipXRemoteParticipantDialogSet::getMediaInterface()
290{
291 if(!mMediaInterface)
292 {
293 // Get the media interface from the active participant
295 {
296 mMediaInterface = dynamic_cast<SipXParticipant*>(getUACOriginalRemoteParticipant())->getMediaInterface();
297 }
298 else if(mDialogs.size() > 0)
299 {
300 // All participants in the set will have the same media interface - query from first
301 resip_assert(mDialogs.begin()->second);
302 mMediaInterface = dynamic_cast<SipXParticipant*>(mDialogs.begin()->second)->getMediaInterface();
303 }
304 }
305 resip_assert(mMediaInterface);
306 return mMediaInterface;
307}
308
309int
311{
312 if(mConnectionPortOnBridge==-1)
313 {
314 getLocalRTPPort(); // This call will create a MediaConnection if not already created at this point
315 }
316 return mConnectionPortOnBridge;
317}
318
319void
321{
322 if(mMediaConnectionId)
323 {
324 getMediaInterface()->deleteConnection(mMediaConnectionId);
325 mMediaConnectionId = 0;
326 }
327
328 // Delete custom sockets - Note: Must be done before MediaStream is deleted
329 if(mRtpSocket)
330 {
331 delete mRtpSocket;
332 mRtpSocket = 0;
333 }
334 if(mRtcpSocket)
335 {
336 delete mRtcpSocket;
337 mRtcpSocket = 0;
338 }
339
340 // Delete Media Stream
341 if(mMediaStream)
342 {
343 delete mMediaStream;
344 mMediaStream = 0;
345 }
346
347 // Add the RTP port back to the pool
348 if(mLocalRTPPort)
349 {
350 mSipXMediaStackAdapter.getRTPPortManager()->freeRTPPort(mLocalRTPPort);
351 mLocalRTPPort = 0;
352 }
353}
354
355void
356SipXRemoteParticipantDialogSet::setActiveDestination(const char* address, unsigned short rtpPort, unsigned short rtcpPort)
357{
358#ifdef DISABLE_FLOWMANAGER_IF_NO_NAT_TRAVERSAL
359 if(mNatTraversalMode != MediaStream::NoNatTraversal)
360 {
361#else
362 if(!mMediaStream)
363 WarningLog(<<"mMediaStream == NULL, no RTP will be transmitted");
364#endif
365 if(mMediaStream && mMediaStream->getRtpFlow())
366 {
367 mMediaStream->getRtpFlow()->setActiveDestination(address, rtpPort);
368 }
369 if(mMediaStream && mMediaStream->getRtcpFlow())
370 {
371 mMediaStream->getRtcpFlow()->setActiveDestination(address, rtcpPort);
372 }
373#ifdef DISABLE_FLOWMANAGER_IF_NO_NAT_TRAVERSAL
374 }
375 else
376 {
377 getMediaInterface()->getInterface()->setConnectionDestination(mMediaConnectionId,
378 address,
379 rtpPort, /* audio rtp port */
380 rtcpPort, /* audio rtcp port */
381 -1 /* video rtp port */,
382 -1 /* video rtcp port */);
383 }
384#endif
385}
386
387void
388SipXRemoteParticipantDialogSet::startDtlsClient(const char* address, unsigned short rtpPort, unsigned short rtcpPort)
389{
390#ifdef USE_SSL
391 if(mMediaStream && mMediaStream->getRtpFlow())
392 {
393 mMediaStream->getRtpFlow()->startDtlsClient(address, rtpPort);
394 }
395 if(mMediaStream && mMediaStream->getRtcpFlow())
396 {
397 mMediaStream->getRtcpFlow()->startDtlsClient(address, rtcpPort);
398 }
399#endif
400}
401
402void
404{
405 if(mMediaStream && mMediaStream->getRtpFlow())
406 {
407 mMediaStream->getRtpFlow()->setRemoteSDPFingerprint(hashFunction, fingerprint);
408 }
409 if(mMediaStream && mMediaStream->getRtcpFlow())
410 {
411 mMediaStream->getRtcpFlow()->setRemoteSDPFingerprint(hashFunction, fingerprint);
412 }
413}
414
415bool
416SipXRemoteParticipantDialogSet::createSRTPSession(MediaConstants::SrtpCryptoSuite cryptoSuite, const char* remoteKey, size_t remoteKeyLen)
417{
418 if(mMediaStream)
419 {
420 mSrtpCryptoSuite = cryptoSuite; // update cypto suite to negotiated value
421 mMediaStream->createOutboundSRTPSession(cryptoSuite, mLocalSrtpSessionKey.data(), mLocalSrtpSessionKey.size());
422 return mMediaStream->createInboundSRTPSession(cryptoSuite, remoteKey, remoteKeyLen);
423 }
424 WarningLog(<<"createSRTPSession: can't create SRTP session without media stream, mMediaStream = " << mMediaStream);
425 return false;
426}
427
428AppDialog*
430{
431 if(mFlowContext->getSipCallId().empty())
432 {
433 mFlowContext->setSipCallId(msg.header(h_CallId).value());
434 }
435
437}
438
439void
441{
443 // Maintain MediaInterface mapping if connectionId is already allocated
444 if (mMediaConnectionId > 0)
445 {
446 getMediaInterface()->updateConnectionIdToPartipantHandleMapping(mMediaConnectionId, getActiveRemoteParticipantHandle());
447 }
448}
449
450bool
455
456void
458{
459 if (sdp)
460 {
461 sdp->session().media().front().port() = mRtpTuple.getPort();
462 sdp->session().connection() = SdpContents::Session::Connection(mRtpTuple.getAddress().is_v4() ? SdpContents::IP4 : SdpContents::IP6, mRtpTuple.getAddress().to_string().c_str()); // c=
463 }
464}
465
466
467/* ====================================================================
468
469 Copyright (c) 2021-2026, SIP Spectrum, Inc. http://www.sipspectrum.com
470 Copyright (c) 2021, Daniel Pocock https://danielpocock.com
471 Copyright (c) 2007-2008, Plantronics, Inc.
472 All rights reserved.
473
474 Redistribution and use in source and binary forms, with or without
475 modification, are permitted provided that the following conditions are
476 met:
477
478 1. Redistributions of source code must retain the above copyright
479 notice, this list of conditions and the following disclaimer.
480
481 2. Redistributions in binary form must reproduce the above copyright
482 notice, this list of conditions and the following disclaimer in the
483 documentation and/or other materials provided with the distribution.
484
485 3. Neither the name of Plantronics nor the names of its contributors
486 may be used to endorse or promote products derived from this
487 software without specific prior written permission.
488
489 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
490 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
491 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
492 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
493 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
494 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
495 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
496 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
497 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
498 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
499 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
500
501 ==================================================================== */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
MediaStream * createMediaStream(MediaStreamHandler &mediaStreamHandler, const StunTuple &localBinding, bool rtcpEnabled=true, MediaStream::NatTraversalMode natTraversalMode=MediaStream::NoNatTraversal, const char *natTraversalServerHostname=0, unsigned short natTraversalServerPort=0, const char *stunUsername=0, const char *stunPassword=0, bool forceCOMedia=false, std::shared_ptr< FlowContext > context=nullptr)
void setRemoteSDPFingerprint(const resip::Data &hashFunction, const resip::Data &fingerprint)
This method should be called when remote fingerprint is discovered via SDP negotiation (RFC 8122 a=fi...
Definition Flow.cxx:574
void setActiveDestination(const char *address, unsigned short port)
Used to set where this flow should be sending to.
Definition Flow.cxx:519
void startDtlsClient(const char *address, unsigned short port)
Dtls-Srtp Methods.
Definition Flow.cxx:566
This class represents a media stream, that consists of a series of componenets or flows.
bool createInboundSRTPSession(resip::MediaConstants::SrtpCryptoSuite cryptoSuite, const char *key, size_t keyLen)
bool createOutboundSRTPSession(resip::MediaConstants::SrtpCryptoSuite cryptoSuite, const char *key, size_t keyLen)
TransportType getTransportType() const
Definition StunTuple.hxx:41
const asio::ip::address & getAddress() const
Definition StunTuple.hxx:44
unsigned int getPort() const
Definition StunTuple.hxx:47
void setTransportType(TransportType transport)
Definition StunTuple.hxx:42
This class is one of two main classes of concern to an application using the UserAgent library.
This class extends the resip UserProfile to include Conversation Manager specific settings.
virtual bool & secureMediaRequired()
Get/Set the wether Secure Media is required (default is false).
virtual resip::Data & natTraversalServerHostname()
Get/Set the NAT traversal server hostname that will be used for if natTranversalMode is anything othe...
virtual resip::Data & stunPassword()
Get/Set the STUN password that will be used for if natTranversalMode is anything other than NoNatTrav...
virtual NatTraversalMode & natTraversalMode()
Get/Set the NAT traversal mode that will be used for sending/receiving media packets.
virtual resip::SdpContents & sessionCaps()
Get/Set the session capabilities.
virtual SecureMediaCryptoSuite & secureMediaDefaultCryptoSuite()
Get/Set the secure media default crypto suite.
virtual unsigned short & natTraversalServerPort()
Get/Set the NAT traversal server port that will be used for if natTranversalMode is anything other th...
virtual resip::Data & stunUsername()
Get/Set the STUN username that will be used for if natTranversalMode is anything other than NoNatTrav...
virtual SecureMediaMode & secureMediaMode()
Get/Set the secure media mode that will be used for sending/receiving media packets.
This class represents events from the Media stream.
This class is used by Invite DialogSets.
std::shared_ptr< ConversationProfile > getConversationProfile()
virtual void setActiveRemoteParticipantHandle(ParticipantHandle handle)
virtual resip::AppDialog * createAppDialog(const resip::SipMessage &msg)
virtual ParticipantHandle getActiveRemoteParticipantHandle()
std::map< resip::DialogId, RemoteParticipant * > mDialogs
void setSecureMediaMode(ConversationProfile::SecureMediaMode m)
virtual void processMediaStreamReadyEvent(std::shared_ptr< MediaStreamReadyEvent::StreamParams > streamParams)
This class is one of two main classes of concern to an application using the UserAgent library.
virtual std::shared_ptr< resip::RTPPortManager > getRTPPortManager()
This is the base class for a SipXRemoteParticipant, SipXLocalParticipant and a SipXMediaResourceParti...
void setRemoteSDPFingerprint(const resip::Data &hashFunction, const resip::Data &fingerprint)
void setActiveDestination(const char *address, unsigned short rtpPort, unsigned short rtcpPort)
virtual resip::AppDialog * createAppDialog(const resip::SipMessage &msg)
SipXRemoteParticipantDialogSet(ConversationManager &conversationManager, SipXMediaStackAdapter &sipXMediaStackAdapter, ConversationManager::ParticipantForkSelectMode forkSelectMode=ConversationManager::ForkSelectAutomatic, std::shared_ptr< ConversationProfile > conversationProfile=nullptr)
bool createSRTPSession(resip::MediaConstants::SrtpCryptoSuite cryptoSuite, const char *remoteKey, size_t remoteKeyLen)
virtual void fixUpSdp(resip::SdpContents *sdp)
virtual void setActiveRemoteParticipantHandle(ParticipantHandle handle)
virtual void processMediaStreamReadyEvent(std::shared_ptr< MediaStreamReadyEvent::StreamParams > streamParams)
void startDtlsClient(const char *address, unsigned short rtpPort, unsigned short rtcpPort)
DialogUsageManager & mDum
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
static int getCryptoRandom()
Definition Random.cxx:330
Process c= (connection) lines in SDP.
const Data & getAddress() const
returns the connection address
const Connection & connection() const
return session Connection
const MediumContainer & media() const
return session Media lines
Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
Session & session()
get the parsed SDP
Represents a SIP message.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
This class is used during media sessions that use Dtls-Srtp for a media transport.
Definition ErrorCode.hxx:4
unsigned int ParticipantHandle
dcm! – add UnusedChecking(_enum) below;
H_CallId h_CallId
Definition Headers.cxx:266