reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Flow.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <asio.hpp>
6#ifdef USE_SSL
7#include <asio/ssl.hpp>
8#endif
9
10#include <rutil/Log.hxx>
11#include <rutil/Logger.hxx>
12#include <rutil/Timer.hxx>
13#include <rutil/Lock.hxx>
14
16#include "ErrorCode.hxx"
17#include "Flow.hxx"
18#include "MediaStream.hxx"
20
21#include <memory>
22#include <sstream>
23#include <vector>
24
25using namespace flowmanager;
26using namespace resip;
27
28#ifdef USE_SSL
29using namespace dtls;
30#endif
31
32using namespace std;
33
34int Flow::maxReceiveFifoDuration = 10; // seconds
35int Flow::maxReceiveFifoSize = 100 * maxReceiveFifoDuration; // 1000 = 1 message every 10 ms for 10 seconds - appropriate for RTP
36int Flow::dtlsHandshakeEvictionGrace = 5; // seconds
37
38#define RESIPROCATE_SUBSYSTEM FlowManagerSubsystem::FLOWMANAGER
39
40#define LOG_PREFIX << mLocalBinding << " ComponentId=" << mComponentId << ", CallId=" << (mFlowContext ? mFlowContext->getSipCallId() : "") << ": "
41
42const char* srtp_error_string(srtp_err_status_t error)
43{
44 switch(error)
45 {
46 case srtp_err_status_ok:
47 return "nothing to report";
48 break;
49 case srtp_err_status_fail:
50 return "unspecified failure";
51 break;
52 case srtp_err_status_bad_param:
53 return "unsupported parameter";
54 break;
55 case srtp_err_status_alloc_fail:
56 return "couldn't allocate memory";
57 break;
58 case srtp_err_status_dealloc_fail:
59 return "couldn't deallocate properly";
60 break;
61 case srtp_err_status_init_fail:
62 return "couldn't initialize";
63 break;
64 case srtp_err_status_terminus:
65 return "can't process as much data as requested";
66 break;
67 case srtp_err_status_auth_fail:
68 return "authentication failure";
69 break;
70 case srtp_err_status_cipher_fail:
71 return "cipher failure";
72 break;
73 case srtp_err_status_replay_fail:
74 return "replay check failed (bad index)";
75 break;
76 case srtp_err_status_replay_old:
77 return "replay check failed (index too old)";
78 break;
79 case srtp_err_status_algo_fail:
80 return "algorithm failed test routine";
81 break;
82 case srtp_err_status_no_such_op:
83 return "unsupported operation";
84 break;
85 case srtp_err_status_no_ctx:
86 return "no appropriate context found";
87 break;
88 case srtp_err_status_cant_check:
89 return "unable to perform desired validation";
90 break;
91 case srtp_err_status_key_expired:
92 return "can't use key any more";
93 break;
94 case srtp_err_status_socket_err:
95 return "error in use of socket";
96 break;
97 case srtp_err_status_signal_err:
98 return "error in use POSIX signals";
99 break;
100 case srtp_err_status_nonce_bad:
101 return "nonce check failed";
102 break;
103 case srtp_err_status_read_fail:
104 return "couldn't read data";
105 break;
106 case srtp_err_status_write_fail:
107 return "couldn't write data";
108 break;
109 case srtp_err_status_parse_err:
110 return "error pasring data";
111 break;
112 case srtp_err_status_encode_err:
113 return "error encoding data";
114 break;
115 case srtp_err_status_semaphore_err:
116 return "error while using semaphores";
117 break;
118 case srtp_err_status_pfkey_err:
119 return "error while using pfkey";
120 break;
121 default:
122 return "unrecognized error";
123 }
124}
125
126Flow::Flow(asio::io_context& ioService,
127#ifdef USE_SSL
128 asio::ssl::context& sslContext,
129#endif
130 unsigned int componentId,
131 const StunTuple& localBinding,
132 MediaStream& mediaStream,
133 bool forceCOMedia,
134 std::shared_ptr<RTCPEventLoggingHandler> rtcpEventLoggingHandler,
135 std::shared_ptr<FlowContext> context)
136 : mIOService(ioService),
137#ifdef USE_SSL
138 mSslContext(sslContext),
139#endif
140 mComponentId(componentId),
141 mLocalBinding(localBinding),
142 mMediaStream(mediaStream),
143 mForceCOMedia(forceCOMedia),
144 mRtcpEventLoggingHandler(rtcpEventLoggingHandler),
145 mFlowContext(context),
146 mPrivatePeer(false),
147 mAllocationProps(StunMessage::PropsNone),
148 mReservationToken(0),
149 mSharedMutex(std::make_shared<resip::Mutex>()),
150 mMutex(*mSharedMutex),
151 mActiveDestinationPort(0),
152 mFlowState(Unconnected),
153 mReceivedDataFifo(maxReceiveFifoDuration, maxReceiveFifoSize)
154{
155 InfoLog(LOG_PREFIX << "Flow created");
156
157 if(componentId != RTCP_COMPONENT_ID && mRtcpEventLoggingHandler.get())
158 {
159 ErrLog(LOG_PREFIX << "attempting to set an RTCPEventLoggingHandler for non-RTCP flow");
160 mRtcpEventLoggingHandler.reset();
161 }
162
163 switch(mLocalBinding.getTransportType())
164 {
165 case StunTuple::UDP:
166 mTurnSocket = std::make_shared<TurnAsyncUdpSocket>(mIOService, this, mLocalBinding.getAddress(), mLocalBinding.getPort());
167 break;
168 case StunTuple::TCP:
169 mTurnSocket = std::make_shared<TurnAsyncTcpSocket>(mIOService, this, mLocalBinding.getAddress(), mLocalBinding.getPort());
170 break;
171#ifdef USE_SSL
172 case StunTuple::TLS:
173 mTurnSocket = std::make_shared<TurnAsyncTlsSocket>(mIOService,
174 mSslContext,
175 mMediaStream.mValidateTlsServerHostname, // check the server certificate is for its host name
176 this,
177 mLocalBinding.getAddress(),
178 mLocalBinding.getPort());
179#endif
180 break;
181 default:
182 // Bad Transport type!
183 resip_assert(false);
184 }
185
186 if (mTurnSocket &&
188 !mMediaStream.mStunUsername.empty() &&
189 !mMediaStream.mStunPassword.empty())
190 {
191 mTurnSocket->setUsernameAndPassword(mMediaStream.mStunUsername.c_str(), mMediaStream.mStunPassword.c_str(), false);
192 }
193}
194
196{
197 InfoLog(LOG_PREFIX << "Flow destroyed");
198
199#ifdef USE_SSL
200 // Cleanup DtlsSockets
201 {
202 Lock lock(mMutex);
203 std::map<reTurn::StunTuple, dtls::DtlsSocket*>::iterator it;
204 for(it = mDtlsSockets.begin(); it != mDtlsSockets.end(); it++)
205 {
206 delete it->second;
207 }
208 }
209 #endif //USE_SSL
210
211 // Cleanup TurnSocket
212 if (mTurnSocket)
213 {
214 mTurnSocket->disableTurnAsyncHandler();
215 mTurnSocket->close();
216 }
217}
218
219void
221{
222 mReservationToken = reservationToken;
224}
225
226void
228{
229 mAllocationProps = allocationProps;
230
231 if (mTurnSocket && mTurnSocket->getBindError())
232 {
233 // Eg. another socket has the local port: the flow can't work - its socket would send from a
234 // port the OS picks - so it's not made ready, and the application is told
235 const asio::error_code& e = mTurnSocket->getBindError();
236 ErrLog(LOG_PREFIX << "Unable to bind to the local address and port, error=" << e.value() << "(" << e.message() << ")");
237 mMediaStream.onFlowError(mComponentId, e.value());
238 return;
239 }
240
241 if (mTurnSocket)
242 {
244 !mMediaStream.mNatTraversalServerHostname.empty())
245 {
246 changeFlowState(ConnectingServer);
247 mTurnSocket->connect(mMediaStream.mNatTraversalServerHostname.c_str(),
248 mMediaStream.mNatTraversalServerPort);
249 }
250 else
251 {
252 changeFlowState(Ready);
253 mMediaStream.onFlowReady(mComponentId);
254 }
255 }
256}
257
258unsigned int
260{
261 return mFakeSelectSocketDescriptor.getSocketDescriptor();
262}
263
264unsigned int
266{
267 return mTurnSocket ? mTurnSocket->getSocketDescriptor() : 0;
268}
269
270// Turn Send Methods
271void
272Flow::send(char* buffer, unsigned int size)
273{
274 resip_assert(mTurnSocket.get());
275 if(isReady())
276 {
277 if(processSendData(buffer, size, mTurnSocket->getConnectedAddress(), mTurnSocket->getConnectedPort()))
278 {
279 mTurnSocket->send(buffer, size);
280 }
281 }
282 else
283 {
284 onSendFailure(mTurnSocket->getSocketDescriptor(), asio::error_code(flowmanager::InvalidState, asio::error::misc_category));
285 }
286}
287
288void
289Flow::sendTo(const asio::ip::address& address, unsigned short port, char* buffer, unsigned int size)
290{
291 resip_assert(mTurnSocket.get());
292 if(isReady())
293 {
294 if(processSendData(buffer, size, address, port))
295 {
296 mTurnSocket->sendTo(address, port, buffer, size);
297 }
298 }
299 else
300 {
301 onSendFailure(mTurnSocket->getSocketDescriptor(), asio::error_code(flowmanager::InvalidState, asio::error::misc_category));
302 }
303}
304
305// Note: this fn is used to send raw data to the far end, without attempting to SRTP encrypt it - ie. used for sending DTLS traffic
306void
307Flow::rawSendTo(const asio::ip::address& address, unsigned short port, const char* buffer, unsigned int size)
308{
309 resip_assert(mTurnSocket.get());
310 mTurnSocket->sendTo(address, port, buffer, size);
311}
312
313
314bool
315Flow::processSendData(char* buffer, unsigned int& size, const asio::ip::address& address, unsigned short port)
316{
317 if(mRtcpEventLoggingHandler.get())
318 {
319 Data _buf(Data::Share, buffer, size);
320 StunTuple dest(mLocalBinding.getTransportType(), address, port);
321 mRtcpEventLoggingHandler->outboundEvent(mFlowContext, mLocalBinding, dest, _buf);
322 }
323 if(mMediaStream.mSRTPSessionOutCreated)
324 {
325 srtp_err_status_t status = mMediaStream.srtpProtect((void*)buffer, (int*)&size, mComponentId == RTCP_COMPONENT_ID);
326 if(status != srtp_err_status_ok)
327 {
328 ErrLog(LOG_PREFIX << "Unable to SRTP protect the packet, error code=" << status << "(" << srtp_error_string(status) << ")");
329 onSendFailure(mTurnSocket->getSocketDescriptor(), asio::error_code(flowmanager::SRTPError, asio::error::misc_category));
330 return false;
331 }
332 }
333#ifdef USE_SSL
334 else
335 {
336 Lock lock(mMutex);
337 DtlsSocket* dtlsSocket = getDtlsSocket(StunTuple(mLocalBinding.getTransportType(), address, port));
338 if(dtlsSocket && ((FlowDtlsSocketContext*)dtlsSocket->getSocketContext())->isSrtpInitialized())
339 {
340 srtp_err_status_t status = ((FlowDtlsSocketContext*)dtlsSocket->getSocketContext())->srtpProtect((void*)buffer, (int*)&size, mComponentId == RTCP_COMPONENT_ID);
341 if(status != srtp_err_status_ok)
342 {
343 ErrLog(LOG_PREFIX << "Unable to SRTP protect the packet, error code=" << status << "(" << srtp_error_string(status) << ")");
344 onSendFailure(mTurnSocket->getSocketDescriptor(), asio::error_code(flowmanager::SRTPError, asio::error::misc_category));
345 return false;
346 }
347 }
348 else if(dtlsSocket || !mRemoteSDPFingerprint.empty())
349 {
350 // DTLS-SRTP (negotiated, as the remote SDP fingerprint is set, or under way with this
351 // endpoint): nothing is sent in the clear - not before the handshake has set up SRTP,
352 // nor to an endpoint without one
353 onSendFailure(mTurnSocket->getSocketDescriptor(), asio::error_code(flowmanager::InvalidState, asio::error::misc_category));
354 return false;
355 }
356 }
357#endif //USE_SSL
358
359 return true;
360}
361
362
363
364// Receive Methods
365asio::error_code
366Flow::receiveFrom(const asio::ip::address& address, unsigned short port, char* buffer, unsigned int& size, unsigned int timeout)
367{
368 bool done = false;
369 asio::error_code errorCode;
370
371 uint64_t startTime = Timer::getTimeMs();
372 unsigned int recvTimeout;
373 while(!done)
374 {
375 // We define timeout of 0 differently then TimeLimitFifo - we want 0 to mean no-block at all
376 if(timeout == 0 && mReceivedDataFifo.empty())
377 {
378 // timeout
379 return asio::error_code(flowmanager::ReceiveTimeout, asio::error::misc_category);
380 }
381
382 recvTimeout = timeout ? (unsigned int)(timeout - (Timer::getTimeMs() - startTime)) : 0;
383 if(timeout != 0 && recvTimeout <= 0)
384 {
385 // timeout
386 return asio::error_code(flowmanager::ReceiveTimeout, asio::error::misc_category);
387 }
388 ReceivedData* receivedData = mReceivedDataFifo.getNext(recvTimeout);
389 if(receivedData)
390 {
391 mFakeSelectSocketDescriptor.receive();
392
393 // discard any data not from address/port requested
394 if(address == receivedData->mAddress && port == receivedData->mPort)
395 {
396 errorCode = processReceivedData(buffer, size, receivedData);
397 done = true;
398 }
399 delete receivedData;
400 }
401 else
402 {
403 // timeout
404 errorCode = asio::error_code(flowmanager::ReceiveTimeout, asio::error::misc_category);
405 done = true;
406 }
407 }
408 return errorCode;
409}
410
411asio::error_code
412Flow::receive(char* buffer, unsigned int& size, unsigned int timeout, asio::ip::address* sourceAddress, unsigned short* sourcePort)
413{
414 asio::error_code errorCode;
415
416 //InfoLog(<< "Flow::receive called with buffer size=" << size << ", timeout=" << timeout);
417 // We define timeout of 0 differently then TimeLimitFifo - we want 0 to mean no-block at all
418 if(timeout == 0 && mReceivedDataFifo.empty())
419 {
420 // timeout
421 DebugLog(LOG_PREFIX << "Receive timeout (timeout==0 and fifo empty)!");
422 return asio::error_code(flowmanager::ReceiveTimeout, asio::error::misc_category);
423 }
424 if(mReceivedDataFifo.empty())
425 {
426 WarningLog(LOG_PREFIX << "Receive called when there is no data available!");
427 }
428
429 ReceivedData* receivedData = mReceivedDataFifo.getNext(timeout);
430 if(receivedData)
431 {
432 mFakeSelectSocketDescriptor.receive();
433 errorCode = processReceivedData(buffer, size, receivedData, sourceAddress, sourcePort);
434 delete receivedData;
435 }
436 else
437 {
438 // timeout
439 DebugLog(LOG_PREFIX << "Receive timeout!");
440 errorCode = asio::error_code(flowmanager::ReceiveTimeout, asio::error::misc_category);
441 }
442 return errorCode;
443}
444
445
446asio::error_code
447Flow::processReceivedData(char* buffer, unsigned int& size, ReceivedData* receivedData, asio::ip::address* sourceAddress, unsigned short* sourcePort)
448{
449 asio::error_code errorCode;
450 unsigned int receivedsize = (unsigned int)receivedData->mData->size();
451
452 // SRTP Unprotect (if required): a packet that isn't authentic SRTP - altered, forged, or plain
453 // RTP - isn't passed on
454 if(mMediaStream.mSRTPSessionInCreated)
455 {
456 srtp_err_status_t status = mMediaStream.srtpUnprotect((void*)receivedData->mData->data(), (int*)&receivedsize, mComponentId == RTCP_COMPONENT_ID);
457 if(status != srtp_err_status_ok)
458 {
459 ErrLog(LOG_PREFIX << "Unable to SRTP unprotect the packet, error code=" << status << "(" << srtp_error_string(status) << ")");
460 errorCode = asio::error_code(flowmanager::SRTPError, asio::error::misc_category);
461 }
462 }
463#ifdef USE_SSL
464 else
465 {
466 Lock lock(mMutex);
467 DtlsSocket* dtlsSocket = getDtlsSocket(StunTuple(mLocalBinding.getTransportType(), receivedData->mAddress, receivedData->mPort));
468 if(dtlsSocket && ((FlowDtlsSocketContext*)dtlsSocket->getSocketContext())->isSrtpInitialized())
469 {
470 srtp_err_status_t status = ((FlowDtlsSocketContext*)dtlsSocket->getSocketContext())->srtpUnprotect((void*)receivedData->mData->data(), (int*)&receivedsize, mComponentId == RTCP_COMPONENT_ID);
471 if(status != srtp_err_status_ok)
472 {
473 ErrLog(LOG_PREFIX << "Unable to SRTP unprotect the packet, error code=" << status << "(" << srtp_error_string(status) << ")");
474 errorCode = asio::error_code(flowmanager::SRTPError, asio::error::misc_category);
475 }
476 }
477 else if(dtlsSocket || !mRemoteSDPFingerprint.empty())
478 {
479 // DTLS-SRTP (negotiated, as the remote SDP fingerprint is set, or under way with this
480 // endpoint): only SRTP from an endpoint whose handshake has set it up is passed on
481 DebugLog(LOG_PREFIX << "Discarding media from " << receivedData->mAddress.to_string() << ":" << receivedData->mPort << ", which has no DTLS-SRTP association");
482 errorCode = asio::error_code(flowmanager::InvalidState, asio::error::misc_category);
483 }
484 }
485#endif //USE_SSL
486 if(!errorCode)
487 {
488 if(size > receivedsize)
489 {
490 size = receivedsize;
491 memcpy(buffer, receivedData->mData->data(), size);
492 //InfoLog(<< "Received a buffer of size=" << receivedData->mData.size());
493 }
494 else
495 {
496 // Receive buffer too small
497 InfoLog(LOG_PREFIX << "Receive buffer too small for data size=" << receivedsize);
498 errorCode = asio::error_code(flowmanager::BufferTooSmall, asio::error::misc_category);
499 }
500 if(sourceAddress)
501 {
502 *sourceAddress = receivedData->mAddress;
503 }
504 if(sourcePort)
505 {
506 *sourcePort = receivedData->mPort;
507 }
508 if(mRtcpEventLoggingHandler.get())
509 {
510 Data _buf(Data::Share, buffer, size);
511 StunTuple _source(mLocalBinding.getTransportType(), *sourceAddress, *sourcePort);
512 mRtcpEventLoggingHandler->inboundEvent(mFlowContext, _source, mLocalBinding, _buf);
513 }
514 }
515 return errorCode;
516}
517
518void
519Flow::setActiveDestination(const char* address, unsigned short port)
520{
521 if (mTurnSocket)
522 {
523 asio::ip::address peerAddress = asio::ip::make_address(address);
524
525 {
526 Lock lock(mMutex);
527 // If no changes, then no-op
528 if (peerAddress == mActiveDestinationAddress && port == mActiveDestinationPort)
529 {
530 return;
531 }
532
533 mActiveDestinationAddress = peerAddress;
534 mActiveDestinationPort = port;
535 }
536
537 if(peerAddress.is_v4())
538 {
539 asio::ip::address_v4::bytes_type _bytes = peerAddress.to_v4().to_bytes();
540
541 mPrivatePeer = _bytes[0] == 10 ||
542 (_bytes[0] == 172 && (_bytes[1] & 0xf0) == 16) ||
543 (_bytes[0] == 192 && _bytes[1] == 168);
544 }
545
547 {
548 InfoLog(LOG_PREFIX <<"Connecting socket to remote peer " << address << ":" << port << (mPrivatePeer ? " [PRIVATE]" : ""));
549 changeFlowState(Connecting);
550 mTurnSocket->connect(address, port);
551 }
552 else
553 {
554 InfoLog(LOG_PREFIX <<"Setting TURN destination to remote peer " << address << ":" << port << (mPrivatePeer ? " [PRIVATE]" : ""));
555 mTurnSocket->setActiveDestination(peerAddress, port);
556 }
557 }
558 else
559 {
560 WarningLog(LOG_PREFIX << "No TURN Socket, can't send media to destination");
561 }
562}
563
564#ifdef USE_SSL
565void
566Flow::startDtlsClient(const char* address, unsigned short port)
567{
568 Lock lock(mMutex);
569 createDtlsSocketClient(StunTuple(mLocalBinding.getTransportType(), asio::ip::make_address(address), port));
570}
571#endif
572
573void
574Flow::setRemoteSDPFingerprint(const resip::Data& hashFunction, const resip::Data& fingerprint)
575{
576 Lock lock(mMutex);
577 mRemoteSDPFingerprintHashFunction = hashFunction;
578 mRemoteSDPFingerprint = fingerprint;
579
580#ifdef USE_SSL
581 // Check all existing DtlsSockets: set up SRTP for those that match, and tear it down for those that don't
582 std::map<reTurn::StunTuple, dtls::DtlsSocket*>::iterator it;
583 for(it = mDtlsSockets.begin(); it != mDtlsSockets.end(); it++)
584 {
585 ((FlowDtlsSocketContext*)it->second->getSocketContext())->checkRemoteFingerprint(hashFunction, fingerprint);
586 }
587#endif //USE_SSL
588}
589
590const resip::Data
592{
593 Lock lock(mMutex);
594 return mRemoteSDPFingerprint;
595}
596
597const StunTuple&
599{
600 return mLocalBinding;
601}
602
605{
606 //resip_assert(mFlowState == Ready); setActiveDestination can get called mid-call and send state back to Connecting, exposing a tight race condition...
607 Lock lock(mMutex);
608
610 {
611 return mRelayTuple;
612 }
614 {
615 return mReflexiveTuple;
616 }
617 return mLocalBinding;
618}
619
622{
623 //resip_assert(mFlowState == Ready); setActiveDestination can get called mid-call and send state back to Connecting, exposing a tight race condition...
624 Lock lock(mMutex);
625 return mRelayTuple;
626}
627
630{
631 //resip_assert(mFlowState == Ready); setActiveDestination can get called mid-call and send state back to Connecting, exposing a tight race condition...
632 Lock lock(mMutex);
633 return mReflexiveTuple;
634}
635
638{
639 //resip_assert(mFlowState == Ready); setActiveDestination can get called mid-call and send state back to Connecting, exposing a tight race condition...
640 Lock lock(mMutex);
641 return mReservationToken;
642}
643
644void
645Flow::onConnectSuccess(unsigned int socketDesc, const asio::ip::address& address, unsigned short port)
646{
647 InfoLog(LOG_PREFIX << "Flow::onConnectSuccess: socketDesc=" << socketDesc << ", address=" << address.to_string() << ", port=" << port);
648
649 // Start candidate discovery
650 switch(mMediaStream.mNatTraversalMode)
651 {
653 if(mFlowState == ConnectingServer)
654 {
655 changeFlowState(Binding);
656 mTurnSocket->bindRequest();
657 }
658 else
659 {
660 changeFlowState(Ready);
661 mMediaStream.onFlowReady(mComponentId);
662 }
663 break;
665 changeFlowState(Allocating);
666 mTurnSocket->createAllocation(TurnAsyncSocket::UnspecifiedLifetime,
668 mAllocationProps,
669 mReservationToken != 0 ? mReservationToken : TurnAsyncSocket::UnspecifiedToken,
670 StunTuple::UDP); // Always relay as UDP
671 break;
673 default:
674 changeFlowState(Ready);
675 mMediaStream.onFlowReady(mComponentId);
676 break;
677 }
678}
679
680void
681Flow::onConnectFailure(unsigned int socketDesc, const asio::error_code& e)
682{
683 WarningLog(LOG_PREFIX << "Flow::onConnectFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
684 changeFlowState(Unconnected);
685 mMediaStream.onFlowError(mComponentId, e.value()); // TODO define different error code?
686}
687
688void
689Flow::onSharedSecretSuccess(unsigned int socketDesc, const char* username, unsigned int usernameSize, const char* password, unsigned int passwordSize)
690{
691 InfoLog(LOG_PREFIX << "Flow::onSharedSecretSuccess: socketDesc=" << socketDesc << ", username=" << username << ", password=" << password);
692}
693
694void
695Flow::onSharedSecretFailure(unsigned int socketDesc, const asio::error_code& e)
696{
697 WarningLog(LOG_PREFIX << "Flow::onSharedSecretFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
698}
699
700void
701Flow::onBindSuccess(unsigned int socketDesc, const StunTuple& reflexiveTuple, const StunTuple& stunServerTuple)
702{
703 InfoLog(LOG_PREFIX << "Flow::onBindingSuccess: socketDesc=" << socketDesc << ", reflexive=" << reflexiveTuple);
704 {
705 Lock lock(mMutex);
706 mReflexiveTuple = reflexiveTuple;
707 }
708 changeFlowState(Ready);
709 mMediaStream.onFlowReady(mComponentId);
710}
711
712void
713Flow::onBindFailure(unsigned int socketDesc, const asio::error_code& e, const StunTuple& stunServerTuple)
714{
715 WarningLog(LOG_PREFIX << "Flow::onBindingFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
716 changeFlowState(Connected);
717 mMediaStream.onFlowError(mComponentId, e.value()); // TODO define different error code?
718}
719
720void
721Flow::onAllocationSuccess(unsigned int socketDesc, const StunTuple& reflexiveTuple, const StunTuple& relayTuple, unsigned int lifetime, unsigned int bandwidth, uint64_t reservationToken)
722{
723 InfoLog(LOG_PREFIX << "Flow::onAllocationSuccess: socketDesc=" << socketDesc <<
724 ", reflexive=" << reflexiveTuple <<
725 ", relay=" << relayTuple <<
726 ", lifetime=" << lifetime <<
727 ", bandwidth=" << bandwidth <<
728 ", reservationToken=" << reservationToken);
729 {
730 Lock lock(mMutex);
731 mReflexiveTuple = reflexiveTuple;
732 mRelayTuple = relayTuple;
733 mReservationToken = reservationToken;
734 }
735 changeFlowState(Ready);
736 mMediaStream.onFlowReady(mComponentId);
737}
738
739void
740Flow::onAllocationFailure(unsigned int socketDesc, const asio::error_code& e)
741{
742 WarningLog(LOG_PREFIX << "Flow::onAllocationFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
743 changeFlowState(Connected);
744 mMediaStream.onFlowError(mComponentId, e.value()); // TODO define different error code?
745}
746
747void
748Flow::onRefreshSuccess(unsigned int socketDesc, unsigned int lifetime)
749{
750 InfoLog(LOG_PREFIX << "Flow::onRefreshSuccess: socketDesc=" << socketDesc << ", lifetime=" << lifetime);
751 if(lifetime == 0)
752 {
753 changeFlowState(Connected);
754 }
755}
756
757void
758Flow::onRefreshFailure(unsigned int socketDesc, const asio::error_code& e)
759{
760 WarningLog(LOG_PREFIX << "Flow::onRefreshFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
761}
762
763void
764Flow::onSetActiveDestinationSuccess(unsigned int socketDesc)
765{
766 InfoLog(LOG_PREFIX << "Flow::onSetActiveDestinationSuccess: socketDesc=" << socketDesc);
767}
768
769void
770Flow::onSetActiveDestinationFailure(unsigned int socketDesc, const asio::error_code& e)
771{
772 WarningLog(LOG_PREFIX << "Flow::onSetActiveDestinationFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
773}
774
775void
776Flow::onClearActiveDestinationSuccess(unsigned int socketDesc)
777{
778 InfoLog(LOG_PREFIX << "Flow::onClearActiveDestinationSuccess: socketDesc=" << socketDesc);
779}
780
781void
782Flow::onClearActiveDestinationFailure(unsigned int socketDesc, const asio::error_code& e)
783{
784 WarningLog(LOG_PREFIX << "Flow::onClearActiveDestinationFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
785}
786
787void
788Flow::onChannelBindRequestSent(unsigned int socketDesc, unsigned short channelNumber)
789{
790 InfoLog(LOG_PREFIX << "Flow::onChannelBindRequestSent: socketDesc=" << socketDesc << ", channelNumber=" << channelNumber);
791}
792
793void
794Flow::onChannelBindSuccess(unsigned int socketDesc, unsigned short channelNumber)
795{
796 InfoLog(LOG_PREFIX << "Flow::onChannelBindSuccess: socketDesc=" << socketDesc << ", channelNumber=" << channelNumber);
797}
798
799void
800Flow::onChannelBindFailure(unsigned int socketDesc, const asio::error_code& e)
801{
802 WarningLog(LOG_PREFIX << "Flow::onChannelBindFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
803}
804
805void
806Flow::onSendSuccess(unsigned int socketDesc)
807{
808 //InfoLog(<< "Flow::onSendSuccess: socketDesc=" << socketDesc);
809}
810
811void
812Flow::onSendFailure(unsigned int socketDesc, const asio::error_code& e)
813{
814 if(e.value() == InvalidState)
815 {
816 // Note: if setActiveDestination is called it can take some time to "connect" the socket to the destination
817 // and send requests during this time, will be discarded - this can be considered normal
818 InfoLog(LOG_PREFIX << "Flow::onSendFailure: socketDesc=" << socketDesc << " socket is not in correct state to send yet, state=" << flowStateToString(mFlowState));
819 }
820 else
821 {
822 WarningLog(LOG_PREFIX << "Flow::onSendFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
823 }
824}
825
826void
827Flow::onReceiveSuccess(unsigned int socketDesc, const asio::ip::address& address, unsigned short port, const std::shared_ptr<reTurn::DataBuffer>& data)
828{
829 StackLog(LOG_PREFIX << "Flow::onReceiveSuccess: socketDesc=" << socketDesc << ", fromAddress=" << address.to_string() << ", fromPort=" << port << ", size=" << data->size());
830
831 if(address != mTurnSocket->getConnectedAddress() || port != mTurnSocket->getConnectedPort())
832 {
833 if(mForceCOMedia && isReady() && mPrivatePeer)
834 {
835 DebugLog(<<"Peer with private IP " << mTurnSocket->getConnectedAddress() << ":" << mTurnSocket->getConnectedPort()
836 << " appears to be sending from " << address << ":" << port);
837 setActiveDestination(address.to_string().c_str(), port);
838 }
839 }
840
841#ifdef USE_SSL
842 // Check if packet is a dtls packet - if so then process it
843 // Note: Stun messaging should be picked off by the reTurn library - so we only need to tell the difference between DTLS and SRTP here
844 if(DtlsFactory::demuxPacket((const unsigned char*) data->data(), (unsigned int)data->size()) == DtlsFactory::dtls)
845 {
846 Lock lock(mMutex);
847
848 StunTuple endpoint(mLocalBinding.getTransportType(), address, port);
849 DtlsSocket* dtlsSocket = getDtlsSocket(endpoint);
850 if(dtlsSocket)
851 {
852 dtlsSocket->handlePacketMaybe((const unsigned char*) data->data(), data->size());
853 }
854 else
855 {
856 // If don't have a socket already for this endpoint and we are receiving data, then assume we are the server side of the DTLS connection
857 acceptDtlsSocketServer(endpoint, (const unsigned char*) data->data(), data->size());
858 }
859
860 // Packet was a DTLS packet - do not queue for app
861 return;
862 }
863#endif
864
865 ReceivedData* receivedData = new ReceivedData(address, port, data);
866 if(!mReceivedDataFifo.add(receivedData, ReceivedDataFifo::EnforceTimeDepth))
867 {
868 WarningLog(LOG_PREFIX << "Flow::onReceiveSuccess: TimeLimitFifo is full (countDepth=" << mReceivedDataFifo.getCountDepth() << ", timeDepth=" << mReceivedDataFifo.getTimeDepth() << ") - discarding data! socketDesc=" << socketDesc << ", fromAddress=" << address.to_string() << ", fromPort=" << port << ", size=" << data->size());
869 delete receivedData;
870 }
871 else
872 {
873 mFakeSelectSocketDescriptor.send();
874 }
875}
876
877void
878Flow::onReceiveFailure(unsigned int socketDesc, const asio::error_code& e)
879{
880 // Make sure we keep receiving if we get an ICMP error on a UDP socket
881 if (mLocalBinding.getTransportType() == StunTuple::UDP &&
882 (e.value() == asio::error::connection_reset ||
883 e.value() == asio::error::connection_refused))
884 {
885 DebugLog(LOG_PREFIX << "Flow::onReceiveFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
886 resip_assert(mTurnSocket.get());
887 mTurnSocket->turnReceive();
888 }
889 else
890 {
891 WarningLog(<< "Flow::onReceiveFailure: socketDesc=" << socketDesc << " error=" << e.value() << "(" << e.message() << ")");
892 }
893}
894
895void
896Flow::onIncomingBindRequestProcessed(unsigned int socketDesc, const StunTuple& sourceTuple)
897{
898 InfoLog(LOG_PREFIX << "Flow::onIncomingBindRequestProcessed: socketDesc=" << socketDesc << ", sourceTuple=" << sourceTuple);
899 // TODO - handle
900}
901
902void
903Flow::changeFlowState(FlowState newState)
904{
905 InfoLog(LOG_PREFIX << "Flow::changeState: oldState=" << flowStateToString(mFlowState) << ", newState=" << flowStateToString(newState));
906 mFlowState = newState;
907}
908
909const char*
910Flow::flowStateToString(FlowState state)
911{
912 switch(state)
913 {
914 case Unconnected:
915 return "Unconnected";
916 case ConnectingServer:
917 return "ConnectingServer";
918 case Connecting:
919 return "Connecting";
920 case Binding:
921 return "Binding";
922 case Allocating:
923 return "Allocating";
924 case Connected:
925 return "Connected";
926 case Ready:
927 return "Ready";
928 default:
929 resip_assert(false);
930 return "Unknown";
931 }
932}
933
934#ifdef USE_SSL
936Flow::getDtlsSocket(const StunTuple& endpoint)
937{
938 std::map<reTurn::StunTuple, dtls::DtlsSocket*>::iterator it = mDtlsSockets.find(endpoint);
939 if(it != mDtlsSockets.end())
940 {
941 return it->second;
942 }
943 return 0;
944}
945
947Flow::createDtlsSocketClient(const StunTuple& endpoint)
948{
949 DtlsSocket* dtlsSocket = getDtlsSocket(endpoint);
950 if(!dtlsSocket && mMediaStream.mDtlsFactory)
951 {
952 InfoLog(LOG_PREFIX << "Creating DTLS Client socket");
953 std::unique_ptr<DtlsSocketContext> socketContext(new FlowDtlsSocketContext(*this, endpoint.getAddress(), endpoint.getPort()));
954 dtlsSocket = mMediaStream.mDtlsFactory->createClient(std::move(socketContext));
955 dtlsSocket->startClient();
956 mDtlsSockets[endpoint] = dtlsSocket;
957 }
958
959 return dtlsSocket;
960}
961
963Flow::acceptDtlsSocketServer(const StunTuple& endpoint, const unsigned char* data, size_t len)
964{
965 if(!mMediaStream.mDtlsFactory)
966 {
967 return 0;
968 }
969
970 std::map<reTurn::StunTuple, dtls::DtlsSocket*>::iterator evict = mDtlsSockets.end();
971 if(mDtlsSockets.size() >= MaxDtlsSockets)
972 {
973 // Make room by dropping the sockets that will never carry media: those whose handshake
974 // failed, and those whose handshake completed but have no SRTP although the remote SDP
975 // fingerprint is known - their certificate didn't match it (eg. forks that lost, or a
976 // peer that was rejected), or SRTP couldn't be set up. The socket carrying SRTP, and ones
977 // still handshaking or waiting for the SDP fingerprint, are kept.
978 for(std::map<reTurn::StunTuple, dtls::DtlsSocket*>::iterator it = mDtlsSockets.begin(); it != mDtlsSockets.end();)
979 {
980 dtls::DtlsSocket* socket = it->second;
981 const bool rejected = socket->handshakeCompleted() && !mRemoteSDPFingerprint.empty() &&
982 !((FlowDtlsSocketContext*)socket->getSocketContext())->isSrtpInitialized();
983 if(socket->handshakeFailed() || rejected)
984 {
985 DebugLog(LOG_PREFIX << "Dropping DTLS socket for " << it->first << " (" << (rejected ? "no SRTP" : "handshake failed") << ") to make room");
986 delete it->second;
987 it = mDtlsSockets.erase(it);
988 }
989 else
990 {
991 ++it;
992 }
993 }
994 if(mDtlsSockets.size() >= MaxDtlsSockets)
995 {
996 // Still full: the oldest server handshake that has been in progress for longer than a
997 // real one takes (dtlsHandshakeEvictionGrace) - stalled, perhaps to hold its place - makes
998 // way, once the new endpoint has completed the cookie exchange
999 for(std::map<reTurn::StunTuple, dtls::DtlsSocket*>::iterator it = mDtlsSockets.begin(); it != mDtlsSockets.end(); ++it)
1000 {
1001 dtls::DtlsSocket* socket = it->second;
1002 if(socket->getSocketType() == DtlsSocket::Server && !socket->handshakeCompleted() && !socket->handshakeFailed() &&
1003 socket->getAge() > std::chrono::seconds(dtlsHandshakeEvictionGrace) &&
1004 (evict == mDtlsSockets.end() || socket->getAge() > evict->second->getAge()))
1005 {
1006 evict = it;
1007 }
1008 }
1009 if(evict == mDtlsSockets.end())
1010 {
1011 if(!mDtlsSocketLimitLogged)
1012 {
1013 WarningLog(LOG_PREFIX << "Already " << mDtlsSockets.size() << " DTLS sockets, ignoring DTLS from new endpoints, eg. " << endpoint);
1014 mDtlsSocketLimitLogged = true;
1015 }
1016 return 0;
1017 }
1018 }
1019 }
1020
1021 if(!mDtlsListener)
1022 {
1023 mDtlsListener = mMediaStream.mDtlsFactory->createListener();
1024 }
1025
1026 // The cookie is bound to the endpoint's address and port
1027 std::ostringstream peer;
1028 peer << endpoint.getAddress().to_string() << ":" << endpoint.getPort();
1029
1030 std::vector<unsigned char> response;
1031 DtlsSocket* dtlsSocket = mDtlsListener->handlePacket(data, len, peer.str(), response, [this, &endpoint]()
1032 {
1033 return std::unique_ptr<DtlsSocketContext>(new FlowDtlsSocketContext(*this, endpoint.getAddress(), endpoint.getPort()));
1034 });
1035 if(!response.empty())
1036 {
1037 // A HelloVerifyRequest, carrying the cookie
1038 rawSendTo(endpoint.getAddress(), endpoint.getPort(), (const char*)response.data(), (unsigned int)response.size());
1039 }
1040 if(dtlsSocket)
1041 {
1042 if(evict != mDtlsSockets.end())
1043 {
1044 WarningLog(LOG_PREFIX << "Dropping the DTLS socket for " << evict->first << ", whose handshake has been in progress for "
1045 << std::chrono::duration_cast<std::chrono::seconds>(evict->second->getAge()).count() << " seconds, to make room for " << endpoint);
1046 delete evict->second;
1047 mDtlsSockets.erase(evict);
1048 }
1049 InfoLog(LOG_PREFIX << "Created DTLS Server socket for " << endpoint);
1050 mDtlsSockets[endpoint] = dtlsSocket;
1051 }
1052 return dtlsSocket;
1053}
1054
1055#endif
1056
1057/* ====================================================================
1058
1059 Copyright (c) 2007-2026, SIP Spectrum, Inc. http://sipspectrum.com
1060 Copyright (c) 2007-2008, Plantronics, Inc.
1061 All rights reserved.
1062
1063 Redistribution and use in source and binary forms, with or without
1064 modification, are permitted provided that the following conditions are
1065 met:
1066
1067 1. Redistributions of source code must retain the above copyright
1068 notice, this list of conditions and the following disclaimer.
1069
1070 2. Redistributions in binary form must reproduce the above copyright
1071 notice, this list of conditions and the following disclaimer in the
1072 documentation and/or other materials provided with the distribution.
1073
1074 3. Neither the name of Plantronics nor the names of its contributors
1075 may be used to endorse or promote products derived from this
1076 software without specific prior written permission.
1077
1078 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1079 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1080 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1081 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1082 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1083 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1084 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1085 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1086 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1087 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1088 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1089
1090 ==================================================================== */
const char * srtp_error_string(srtp_err_status_t error)
Definition Flow.cxx:42
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define RTCP_COMPONENT_ID
#define resip_assert(x)
This file needs to work for both C and C++ code.
DtlsSocket * createClient(std::unique_ptr< DtlsSocketContext > context)
static PacketType demuxPacket(const unsigned char *buf, size_t len)
std::unique_ptr< DtlsListener > createListener()
bool handshakeFailed() const
std::chrono::steady_clock::duration getAge() const
SocketType getSocketType()
DtlsSocketContext * getSocketContext()
bool handlePacketMaybe(const unsigned char *bytes, size_t len)
bool handshakeCompleted()
const resip::Data getRemoteSDPFingerprint()
Retrieves the stored remote SDP Fingerprint.
Definition Flow.cxx:591
StunTuple getReflexiveTuple()
Definition Flow.cxx:629
uint64_t getReservationToken()
Definition Flow.cxx:637
Flow(asio::io_context &ioService, asio::ssl::context &sslContext, unsigned int componentId, const StunTuple &localBinding, MediaStream &mediaStream, bool forceCOMedia, std::shared_ptr< RTCPEventLoggingHandler > rtcpEventLoggingHandler=nullptr, std::shared_ptr< FlowContext > context=nullptr)
Definition Flow.cxx:126
bool isReady()
Definition Flow.hxx:80
const StunTuple & getLocalTuple()
Definition Flow.cxx:598
asio::error_code receiveFrom(const asio::ip::address &address, unsigned short port, char *buffer, unsigned int &size, unsigned int timeout)
Definition Flow.cxx:366
unsigned int getSocketDescriptor()
Definition Flow.cxx:265
friend class FlowDtlsSocketContext
Definition Flow.hxx:133
void send(char *buffer, unsigned int size)
Turn Send Methods WARNING - if using Secure media, then there must be room at the end of the passed i...
Definition Flow.cxx:272
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 rawSendTo(const asio::ip::address &address, unsigned short port, const char *buffer, unsigned int size)
Definition Flow.cxx:307
void setActiveDestination(const char *address, unsigned short port)
Used to set where this flow should be sending to.
Definition Flow.cxx:519
static int maxReceiveFifoDuration
Definition Flow.hxx:48
static int dtlsHandshakeEvictionGrace
Seconds after which a server DTLS handshake still in progress gives up its place, when a flow already...
Definition Flow.hxx:54
StunTuple getSessionTuple()
Definition Flow.cxx:604
void sendTo(const asio::ip::address &address, unsigned short port, char *buffer, unsigned int size)
Definition Flow.cxx:289
static int maxReceiveFifoSize
Definition Flow.hxx:49
asio::error_code receive(char *buffer, unsigned int &size, unsigned int timeout, asio::ip::address *sourceAddress=0, unsigned short *sourcePort=0)
Receive Methods.
Definition Flow.cxx:412
unsigned int getSelectSocketDescriptor()
Returns a socket descriptor that can be used in a select call WARNING - this descriptor should not be...
Definition Flow.cxx:259
void startDtlsClient(const char *address, unsigned short port)
Dtls-Srtp Methods.
Definition Flow.cxx:566
StunTuple getRelayTuple()
Definition Flow.cxx:621
void activateFlow(uint8_t allocationProps=StunMessage::PropsNone)
Definition Flow.cxx:227
This class represents a media stream, that consists of a series of componenets or flows.
unsigned short mNatTraversalServerPort
NatTraversalMode mNatTraversalMode
srtp_err_status_t srtpProtect(void *data, int *size, bool rtcp)
volatile bool mSRTPSessionInCreated
srtp_err_status_t srtpUnprotect(void *data, int *size, bool rtcp)
dtls::DtlsFactory * mDtlsFactory
volatile bool mSRTPSessionOutCreated
resip::Data mNatTraversalServerHostname
static const uint8_t PropsNone
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
static unsigned int UnspecifiedBandwidth
static unsigned int UnspecifiedLifetime
bool empty() const
is the queue empty?
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
@ Share
The Data instance will use the buffer in a read-only mode.
Definition Data.hxx:266
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
virtual size_t getCountDepth() const
gets the depth of the FIFO
Msg * getNext()
Returns the first message available.
virtual time_t getTimeDepth() const
Return the time depth of the queue.
bool add(Msg *msg, DepthUsage usage)
Add a message to the fifo.
static uint64_t getTimeMs()
Returns the current clock time in milliseconds.
Definition Timer.hxx:72
This class is used during media sessions that use Dtls-Srtp for a media transport.
Definition ErrorCode.hxx:4
static const ErrorType ReceiveTimeout
Definition ErrorCode.hxx:14
static const ErrorType InvalidState
Definition ErrorCode.hxx:15
static const ErrorType BufferTooSmall
Definition ErrorCode.hxx:13
static const ErrorType SRTPError
Definition ErrorCode.hxx:16
dcm! – add UnusedChecking(_enum) below;
std::mutex Mutex
A semaphore that can be locked by only one thread at a time.
Definition Mutex.hxx:37
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Definition Lock.hxx:28
unsigned char uint8_t
Definition stdint.h:83
unsigned __int64 uint64_t
Definition stdint.h:95