1 //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
2 #include "ice_session.h"
3 #include "steamwebrtc_internal.h"
4
5 #include <mutex>
6 #include <string.h>
7
8 #include <string>
9
10 #include <absl/types/optional.h>
11 #include <absl/memory/memory.h>
12 #include <api/async_resolver_factory.h>
13 #include <api/turn_customizer.h>
14 #include <rtc_base/network_route.h>
15 #include <rtc_base/bind.h>
16 #include <rtc_base/physical_socket_server.h>
17 #include <rtc_base/ssl_adapter.h>
18
19 #include <api/jsep.h>
20 #include <p2p/base/p2p_transport_channel.h>
21 #include <p2p/base/basic_packet_socket_factory.h>
22 #include <p2p/client/basic_port_allocator.h>
23
24 #include <pc/webrtc_sdp.h>
25
26 #ifdef _WIN32
27 #define WIN32_LEAN_AND_MEAN
28 #include <windows.h>
29 #else
30 #include <pthread.h>
31 #endif
32
33 #ifdef _MSC_VER
34 #define strcasecmp _stricmp
35 #define strncasecmp _strnicmp
36 #endif
37
38 extern "C"
39 {
40 static void (*g_fnWriteEvent_setsockopt)( int slevel, int sopt, int value ) = nullptr;
41 static void (*g_fnWriteEvent_send)( int length ) = nullptr;
42 static void (*g_fnWriteEvent_sendto)( void *addr, int length ) = nullptr;
43 }
44
45 extern "C"
46 {
47 STEAMWEBRTC_DECLSPEC IICESession *CreateWebRTCICESession( const ICESessionConfig &cfg, IICESessionDelegate *pDelegate, int nInterfaceVersion );
48 }
49
50 //-----------------------------------------------------------------------------
51 // Class to represent an ICE connection
52 //-----------------------------------------------------------------------------
53 class CICESession final : public IICESession, public sigslot::has_slots<>, private rtc::MessageHandler
54 {
55 public:
56 CICESession( IICESessionDelegate *pDelegate );
57 virtual ~CICESession();
58
59 bool BInitialize( const ICESessionConfig &cfg );
60 bool BInitializeOnSocketThread( const ICESessionConfig &cfg );
61 void DestroyOnSocketThread();
BShuttingDown() const62 bool BShuttingDown() const { return m_bShuttingDown; }
63
64 //
65 // IICESession
66 //
67 virtual void Destroy() override;
68 virtual bool BSendData( const void *pData, size_t nSize ) override;
69 virtual void SetRemoteAuth( const char *pszUserFrag, const char *pszPwdFrag ) override;
70 virtual EICECandidateType AddRemoteIceCandidate( const char *pszCandidate ) override;
71 virtual bool GetWritableState() override;
72 virtual int GetPing() override;
73 virtual bool GetRoute( EICECandidateType &eLocalCandidate, EICECandidateType &eRemoteCandidate, CandidateAddressString &szRemoteAddress ) override;
SetWriteEvent_setsockopt(void (* fn)(int slevel,int sopt,int value))74 virtual void SetWriteEvent_setsockopt( void (*fn)( int slevel, int sopt, int value ) ) override { g_fnWriteEvent_setsockopt = fn; }
SetWriteEvent_send(void (* fn)(int length))75 virtual void SetWriteEvent_send( void (*fn)( int length ) ) override { g_fnWriteEvent_send = fn; }
SetWriteEvent_sendto(void (* fn)(void * addr,int length))76 virtual void SetWriteEvent_sendto( void (*fn)( void *addr, int length ) ) override { g_fnWriteEvent_sendto = fn; }
77
78 // rtc::MessageHandler
79 virtual void OnMessage( rtc::Message* msg ) override;
80
81
82 private:
83 static std::mutex s_mutex;
84 static int s_nInstaneCount;
85 static rtc::Thread *s_pSocketThread;
86 static rtc::PhysicalSocketServer *s_pSocketServer;
87
88 int m_nAllowedCandidateTypes;
89
90 bool m_bShuttingDown = false;
91 IICESessionDelegate *m_pDelegate = nullptr;
92 bool writable_ = false;
93 std::unique_ptr<cricket::P2PTransportChannel> ice_transport_;
94 std::unique_ptr<rtc::BasicNetworkManager> default_network_manager_;
95 std::unique_ptr<rtc::BasicPacketSocketFactory> default_socket_factory_;
96 std::unique_ptr< cricket::BasicPortAllocator > port_allocator_;
97
98 void CacheRouteAndPing();
99 int m_nCachedPing = -1;
100 bool m_bCachedRouteValid = false;
101 EICECandidateType m_eCachedRouteLocalCandidate;
102 EICECandidateType m_eCachedRouteRemoteCandidate;
103 CandidateAddressString m_szCachedRouteRemoteAddress;
104
105 // ICE signals
106 void OnTransportGatheringState_n(cricket::IceTransportInternal* transport);
107 void OnTransportCandidateGathered_n(cricket::IceTransportInternal* transport, const cricket::Candidate& candidate);
108 void OnTransportCandidatesRemoved_n(cricket::IceTransportInternal* transport, const cricket::Candidates& candidates);
109 void OnTransportRoleConflict_n(cricket::IceTransportInternal* transport);
110 void OnTransportStateChanged_n(cricket::IceTransportInternal* transport);
111 void OnWritableState(rtc::PacketTransportInternal* transport);
112 void OnReadPacket(
113 rtc::PacketTransportInternal* transport,
114 const char* data,
115 size_t size,
116 const int64_t& packet_time,
117 int flags);
118 void OnSentPacket(rtc::PacketTransportInternal* transport, const rtc::SentPacket& sent_packet);
119 void OnReadyToSend(rtc::PacketTransportInternal* transport);
120 void OnReceivingState(rtc::PacketTransportInternal* transport);
121 void OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route);
122 };
123
124
125 //-----------------------------------------------------------------------------
126 //
127 //-----------------------------------------------------------------------------
CreateWebRTCICESession(const ICESessionConfig & cfg,IICESessionDelegate * pDelegate,int nInterfaceVersion)128 IICESession *CreateWebRTCICESession( const ICESessionConfig &cfg, IICESessionDelegate *pDelegate, int nInterfaceVersion )
129 {
130 if ( nInterfaceVersion != ICESESSION_INTERFACE_VERSION )
131 {
132 return nullptr;
133 }
134
135 CICESession *pSession = new CICESession( pDelegate );
136 if ( !pSession->BInitialize( cfg ) )
137 {
138 pSession->Destroy();
139 return nullptr;
140 }
141 return pSession;
142 }
143
144 std::mutex CICESession::s_mutex;
145 int CICESession::s_nInstaneCount = 0;
146 rtc::Thread *CICESession::s_pSocketThread = nullptr;
147 rtc::PhysicalSocketServer *CICESession::s_pSocketServer = nullptr;
148
149 //-----------------------------------------------------------------------------
150 // Constructor
151 //-----------------------------------------------------------------------------
CICESession(IICESessionDelegate * pDelegate)152 CICESession::CICESession( IICESessionDelegate *pDelegate ) :
153 m_pDelegate( pDelegate )
154 {
155 s_mutex.lock();
156 if ( ++s_nInstaneCount == 1 )
157 {
158 rtc::InitializeSSL();
159 assert( s_pSocketServer == nullptr );
160 s_pSocketServer = new rtc::PhysicalSocketServer;
161
162 assert( s_pSocketThread == nullptr );
163 s_pSocketThread = new rtc::Thread( s_pSocketServer );
164 s_pSocketThread->Start();
165 }
166 s_mutex.unlock();
167 }
168
169
170 //-----------------------------------------------------------------------------
171 // Destructor
172 //-----------------------------------------------------------------------------
~CICESession()173 CICESession::~CICESession()
174 {
175 s_pSocketThread->Invoke<void>( RTC_FROM_HERE, rtc::Bind( &CICESession::DestroyOnSocketThread, this ) );
176
177 s_mutex.lock();
178 if ( --s_nInstaneCount == 0 )
179 {
180 s_pSocketThread->Quit();
181 delete s_pSocketThread;
182 s_pSocketThread = nullptr;
183
184 delete s_pSocketServer;
185 s_pSocketServer = nullptr;
186
187 rtc::CleanupSSL();
188 }
189 s_mutex.unlock();
190 }
191
192
193 //-----------------------------------------------------------------------------
194 //
195 //-----------------------------------------------------------------------------
BInitialize(const ICESessionConfig & cfg)196 bool CICESession::BInitialize( const ICESessionConfig &cfg )
197 {
198 return s_pSocketThread->Invoke<bool>( RTC_FROM_HERE, rtc::Bind( &CICESession::BInitializeOnSocketThread, this, cfg ) );
199 }
200
201
202 //-----------------------------------------------------------------------------
203 //
204 //-----------------------------------------------------------------------------
BInitializeOnSocketThread(const ICESessionConfig & cfg)205 bool CICESession::BInitializeOnSocketThread( const ICESessionConfig &cfg )
206 {
207 #ifdef _WIN32
208 ::SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
209 #elif !defined(WEBRTC_MARVELL) // Don't change priority on Steam Link hardware
210 struct sched_param sched;
211 int policy;
212 pthread_t thread = pthread_self();
213
214 if (pthread_getschedparam(thread, &policy, &sched) == 0) {
215 sched.sched_priority = sched_get_priority_max(policy);
216 pthread_setschedparam(thread, policy, &sched);
217 }
218 #endif
219
220 m_nAllowedCandidateTypes = cfg.m_nCandidateTypes;
221
222 default_network_manager_.reset(new rtc::BasicNetworkManager());
223 default_socket_factory_.reset(
224 new rtc::BasicPacketSocketFactory( s_pSocketThread ));
225
226 webrtc::TurnCustomizer *turn_customizer = nullptr;
227
228 port_allocator_ = absl::make_unique<cricket::BasicPortAllocator>(
229 default_network_manager_.get(), default_socket_factory_.get(),
230 turn_customizer );
231
232 // See PeerConnection::InitializePortAllocator_n
233 port_allocator_->Initialize();
234
235 // To handle both internal and externally created port allocator, we will
236 // enable BUNDLE here.
237 uint32_t port_allocator_flags_ = port_allocator_->flags();
238 port_allocator_flags_ |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
239 port_allocator_flags_ |= cricket::PORTALLOCATOR_DISABLE_TCP;
240
241 uint32_t candidate_filter = cricket::CF_NONE;
242
243 cricket::ServerAddresses stun_servers;
244 if ( cfg.m_nCandidateTypes & k_EICECandidate_Any_Reflexive )
245 {
246 candidate_filter |= cricket::CF_REFLEXIVE;
247 for ( int i = 0 ; i < cfg.m_nStunServers ; ++i )
248 {
249 const char *pszStun = cfg.m_pStunServers[i];
250
251 // Skip "stun:" prefix, if present
252 if ( strncasecmp( pszStun, "stun:", 5 ) == 0 )
253 pszStun += 5;
254
255 rtc::SocketAddress address;
256 if ( !address.FromString( std::string( pszStun ) ) )
257 {
258 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "Invalid STUN server address '%s'\n", pszStun );
259 return false;
260 }
261 if ( address.port() == 0 )
262 address.SetPort( 3478 ); // default STUN port
263
264 stun_servers.insert( address );
265 }
266 }
267 else
268 {
269 port_allocator_flags_ |= cricket::PORTALLOCATOR_DISABLE_STUN;
270 }
271
272 if ( cfg.m_nCandidateTypes & (k_EICECandidate_Any_HostPrivate|k_EICECandidate_Any_HostPublic) )
273 candidate_filter |= cricket::CF_HOST;
274 if ( cfg.m_nCandidateTypes & k_EICECandidate_Any_Relay )
275 candidate_filter |= cricket::CF_RELAY;
276 port_allocator_flags_ |= cricket::PORTALLOCATOR_DISABLE_LINK_LOCAL_NETWORKS;
277 if ( cfg.m_nCandidateTypes & k_EICECandidate_Any_IPv6 )
278 {
279 port_allocator_flags_ |=
280 cricket::PORTALLOCATOR_ENABLE_IPV6 |
281 cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI;
282 }
283
284 std::vector<cricket::RelayServerConfig> turn_servers;
285 if ( cfg.m_nCandidateTypes & (k_EICECandidate_Any_Reflexive|k_EICECandidate_Any_Relay) )
286 {
287 candidate_filter |= cricket::CF_REFLEXIVE | cricket::CF_RELAY;
288 for ( int i = 0 ; i < cfg.m_nTurnServers ; ++i )
289 {
290 const ICESessionConfig::TurnServer *pTurn = &cfg.m_pTurnServers[i];
291
292 if ( !pTurn || !pTurn->m_pszHost || !pTurn->m_pszPwd || !pTurn->m_pszUsername ) {
293 continue;
294 }
295
296 const char *pszTurn = pTurn->m_pszHost;
297
298 // Skip "turn:" prefix, if present
299 if ( strncasecmp( pszTurn, "turn:", 5 ) == 0 )
300 pszTurn += 5;
301
302 rtc::SocketAddress address;
303 if ( !address.FromString( std::string( pszTurn ) ) )
304 {
305 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "Invalid Turn server address '%s'\n", pszTurn );
306 return false;
307 }
308 if ( address.port() == 0 )
309 address.SetPort( 3478 ); // default STUN port
310
311 switch( pTurn->m_protocolType ) {
312 case k_EProtocolTypeUDP:
313 case k_EProtocolTypeTCP:
314 case k_EProtocolTypeSSLTCP:
315 case k_EProtocolTypeTLS:
316 default:
317 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "Invalid Turn server protocol type '%d'\n", (int) pTurn->m_protocolType );
318 return false;
319 }
320
321 cricket::RelayServerConfig turn(address.hostname(), address.port(),
322 pTurn->m_pszUsername, pTurn->m_pszPwd, (cricket::ProtocolType) pTurn->m_protocolType);
323 turn_servers.push_back( turn );
324 }
325 }
326
327 port_allocator_->set_flags(port_allocator_flags_);
328
329 // No step delay is used while allocating ports.
330 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
331
332 port_allocator_->set_candidate_filter( candidate_filter );
333
334 //port_allocator_->set_max_ipv6_networks(configuration.max_ipv6_networks);
335
336 int ice_candidate_pool_size = 0; // ???
337 bool prune_turn_ports = false;
338 absl::optional<int> stun_candidate_keepalive_interval = absl::nullopt;
339
340 if ( !port_allocator_->SetConfiguration(
341 stun_servers, turn_servers,
342 ice_candidate_pool_size, prune_turn_ports,
343 turn_customizer,
344 stun_candidate_keepalive_interval
345 ) ) {
346 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "PortAllocator::SetConfiguration failed\n" );
347 return false;
348 }
349
350 // ???
351 std::string transport_name = "CICESession";
352 int component = 0;
353 std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_; // This is apparently allowed to be null
354
355 ice_transport_ = absl::make_unique<cricket::P2PTransportChannel>(
356 transport_name, component, port_allocator_.get(), async_resolver_factory_.get(),
357 nullptr );
358
359 if ( !ice_transport_ )
360 {
361 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "Failed to create P2PTransportChannel\n" );
362 return false;
363 }
364
365 const int kBufferSize = 512*1024;
366 ice_transport_->SetOption( rtc::Socket::OPT_SNDBUF, kBufferSize );
367 ice_transport_->SetOption( rtc::Socket::OPT_RCVBUF, kBufferSize );
368
369 static_assert(
370 (int)k_EICERole_Unknown == (int)cricket::ICEROLE_UNKNOWN
371 && (int)k_EICERole_Controlling == (int)cricket::ICEROLE_CONTROLLING
372 && (int)k_EICERole_Controlled == (int)cricket::ICEROLE_CONTROLLED, "We assume our ICE role enum matches WebRTC's" );
373 ice_transport_->SetIceRole( cricket::IceRole( cfg.m_eRole ) );
374
375 //m_transport->SetIceTiebreaker(ice_tiebreaker_);
376 //cricket::IceConfig ice_config;
377 //ice_config.receiving_timeout = RTCConfigurationToIceConfigOptionalInt(
378 // config.ice_connection_receiving_timeout);
379 //ice_config.prioritize_most_likely_candidate_pairs =
380 // config.prioritize_most_likely_ice_candidate_pairs;
381 //ice_config.backup_connection_ping_interval =
382 // RTCConfigurationToIceConfigOptionalInt(
383 // config.ice_backup_candidate_pair_ping_interval);
384 //ice_config.continual_gathering_policy = gathering_policy;
385 //ice_config.presume_writable_when_fully_relayed = config.presume_writable_when_fully_relayed;
386 //ice_config.ice_check_interval_strong_connectivity = config.ice_check_interval_strong_connectivity;
387 //ice_config.ice_check_interval_weak_connectivity = config.ice_check_interval_weak_connectivity;
388 //ice_config.ice_check_min_interval = config.ice_check_min_interval;
389 //ice_config.stun_keepalive_interval = config.stun_candidate_keepalive_interval;
390 //ice_config.regather_all_networks_interval_range = config.ice_regather_interval_range;
391 //ice_config.network_preference = config.network_preference;
392 //ice_transport_->SetIceConfig(ice_config);
393
394 // Set our local parameters. We don't know the other guy's params yet
395 cricket::IceParameters ice_params;
396 ice_params.ufrag = cfg.m_pszLocalUserFrag;
397 ice_params.pwd = cfg.m_pszLocalPwd;
398 ice_transport_->SetIceParameters( ice_params );
399
400 ice_transport_->SignalGatheringState.connect( this, &CICESession::OnTransportGatheringState_n);
401 ice_transport_->SignalCandidateGathered.connect( this, &CICESession::OnTransportCandidateGathered_n);
402 ice_transport_->SignalCandidatesRemoved.connect( this, &CICESession::OnTransportCandidatesRemoved_n);
403 ice_transport_->SignalRoleConflict.connect( this, &CICESession::OnTransportRoleConflict_n);
404 ice_transport_->SignalStateChanged.connect( this, &CICESession::OnTransportStateChanged_n);
405 ice_transport_->SignalWritableState.connect( this, &CICESession::OnWritableState );
406 ice_transport_->SignalReadPacket.connect( this, &CICESession::OnReadPacket );
407 ice_transport_->SignalSentPacket.connect(this, &CICESession::OnSentPacket);
408 ice_transport_->SignalReadyToSend.connect(this, &CICESession::OnReadyToSend);
409 ice_transport_->SignalReceivingState.connect( this, &CICESession::OnReceivingState);
410 ice_transport_->SignalNetworkRouteChanged.connect( this, &CICESession::OnNetworkRouteChanged);
411
412 ice_transport_->MaybeStartGathering();
413
414 return true;
415 }
416
DestroyOnSocketThread()417 void CICESession::DestroyOnSocketThread()
418 {
419 // Kind of defeats the purpose of using std::unique_ptr to manually
420 // destroy like this, but we really want to control the teardown order.
421 // and we need it to happen in a particular thread, so being "subtle"
422 // would be counter productive.
423 writable_ = false;
424 ice_transport_.reset();
425 port_allocator_.reset();
426 default_socket_factory_.reset();
427 default_network_manager_.reset();
428 }
429
430 //-----------------------------------------------------------------------------
431 //
432 //-----------------------------------------------------------------------------
Destroy()433 void CICESession::Destroy()
434 {
435 m_bShuttingDown = true;
436 delete this;
437 }
438
GetICECandidateType(const cricket::Candidate & candidate)439 EICECandidateType GetICECandidateType( const cricket::Candidate &candidate )
440 {
441 const rtc::SocketAddress &addr = candidate.address();
442 if ( !addr.IsComplete() )
443 return k_EICECandidate_Invalid;
444
445 const std::string &typ = candidate.type();
446 EICECandidateType eResult;
447 if ( strcasecmp( typ.c_str(), cricket::LOCAL_PORT_TYPE ) == 0 )
448 {
449 // NOTE: This doesn't classify fc00::/7 as private
450 if ( addr.IsPrivateIP() )
451 eResult = k_EICECandidate_IPv4_HostPrivate;
452 else
453 eResult = k_EICECandidate_IPv4_HostPublic;
454 }
455 else if ( strcasecmp( typ.c_str(), cricket::STUN_PORT_TYPE ) == 0 || strcasecmp( typ.c_str(), cricket::PRFLX_PORT_TYPE ) == 0 )
456 {
457 eResult = k_EICECandidate_IPv4_Reflexive;
458 }
459 else if ( strcasecmp( typ.c_str(), cricket::RELAY_PORT_TYPE ) == 0 )
460 {
461 eResult = k_EICECandidate_IPv4_Relay;
462 }
463 else
464 {
465 return k_EICECandidate_Invalid;
466 }
467
468 switch ( candidate.address().family() )
469 {
470 case AF_INET:
471 return eResult;
472 case AF_INET6:
473 static_assert(
474 k_EICECandidate_IPv4_HostPrivate<<8 == k_EICECandidate_IPv6_HostPrivate_Unsupported
475 && k_EICECandidate_IPv4_HostPublic<<8 == k_EICECandidate_IPv6_HostPublic
476 && k_EICECandidate_IPv4_Reflexive<<8 == k_EICECandidate_IPv6_Reflexive
477 && k_EICECandidate_IPv4_Relay<<8 == k_EICECandidate_IPv6_Relay, "We assume bit layout" );
478 return EICECandidateType( eResult << 8 );
479 }
480
481 return k_EICECandidate_Invalid;
482 }
483
484 //-----------------------------------------------------------------------------
485 //
486 //-----------------------------------------------------------------------------
AddRemoteIceCandidate(const char * pszCandidate)487 EICECandidateType CICESession::AddRemoteIceCandidate( const char *pszCandidate )
488 {
489 webrtc::SdpParseError error;
490 cricket::Candidate candidate;
491 if ( !webrtc::SdpDeserializeCandidate(
492 "", // transport_name, not really used
493 std::string( pszCandidate ),
494 &candidate,
495 &error
496 ) ) {
497 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "Error parsing ICE candidate '%s': %s\n", pszCandidate, error.description.c_str() );
498 return k_EICECandidate_Invalid;
499 }
500
501 // Should we post instead of invoke here?
502 s_pSocketThread->Invoke<void>( RTC_FROM_HERE, rtc::Bind( &cricket::P2PTransportChannel::AddRemoteCandidate, ice_transport_.get(), candidate ) );
503
504 return GetICECandidateType( candidate );
505 }
506
507 const uint32_t SEND_PACKET_IN_GOOGLE_THREAD = 1000;
508 struct SendPacktetInGoogleThread : rtc::MessageData
509 {
510 size_t nSize;
511 char data[4];
512 };
513
OnMessage(rtc::Message * msg)514 void CICESession::OnMessage( rtc::Message* msg )
515 {
516 if ( msg->message_id != SEND_PACKET_IN_GOOGLE_THREAD )
517 {
518 assert( false );
519 return;
520 }
521
522 if ( ice_transport_ )
523 {
524 auto *pkt = static_cast<SendPacktetInGoogleThread *>( msg->pdata );
525 rtc::PacketOptions options;
526 int flags = 0;
527 ice_transport_->SendPacket( pkt->data, pkt->nSize, options, flags );
528 }
529 free( msg->pdata );
530 }
531
BSendData(const void * pData,size_t nSize)532 bool CICESession::BSendData( const void *pData, size_t nSize )
533 {
534 if ( !ice_transport_ || !writable_ )
535 return false;
536
537 // Create a message to send it in the other thread. I hate all this payload
538 // copying and context switching. It's fine on machines with plenty of
539 // hardware threads, but on limited hardware, this is a perf bottleneck
540 SendPacktetInGoogleThread *pkt = (SendPacktetInGoogleThread*)malloc( sizeof(SendPacktetInGoogleThread) - sizeof(SendPacktetInGoogleThread::data) + nSize );
541 new ( pkt ) SendPacktetInGoogleThread();
542 pkt->nSize = nSize;
543 memcpy( pkt->data, pData, nSize );
544 bool time_sensitive = false; // Actually, this is really time sensitive. But passing "true" triggers an assert for some reason.
545 s_pSocketThread->Post( RTC_FROM_HERE, this, SEND_PACKET_IN_GOOGLE_THREAD, pkt, time_sensitive );
546 return true;
547 }
548
SetRemoteAuth(const char * pszUserFrag,const char * pszPwd)549 void CICESession::SetRemoteAuth( const char *pszUserFrag, const char *pszPwd )
550 {
551 if ( !ice_transport_ )
552 return;
553 cricket::IceParameters ice_params;
554 ice_params.ufrag = pszUserFrag;
555 ice_params.pwd = pszPwd;
556 s_pSocketThread->Invoke<void>( RTC_FROM_HERE, rtc::Bind( &cricket::P2PTransportChannel::SetRemoteIceParameters, ice_transport_.get(), ice_params ) );
557 }
558
GetWritableState()559 bool CICESession::GetWritableState()
560 {
561 return ice_transport_ && writable_;
562 }
563
GetPing()564 int CICESession::GetPing()
565 {
566 if ( !ice_transport_ )
567 m_nCachedPing = -1;
568 return m_nCachedPing;
569 }
570
CacheRouteAndPing()571 void CICESession::CacheRouteAndPing()
572 {
573 m_bCachedRouteValid = false;
574 m_nCachedPing = -1;
575 if ( !ice_transport_ )
576 return;
577 absl::optional<int> rtt = ice_transport_->GetRttEstimate();
578 if ( rtt )
579 m_nCachedPing = *rtt;
580 const cricket::Connection *conn = ice_transport_->selected_connection();
581 if ( !conn )
582 return;
583
584 m_eCachedRouteLocalCandidate = GetICECandidateType( conn->local_candidate() );
585 m_eCachedRouteRemoteCandidate = GetICECandidateType( conn->remote_candidate() );
586 std::string remote_addr = conn->remote_candidate().address().ToString();
587 strncpy( m_szCachedRouteRemoteAddress, remote_addr.c_str(), sizeof(m_szCachedRouteRemoteAddress) - 1 );
588 m_szCachedRouteRemoteAddress[ sizeof(m_szCachedRouteRemoteAddress)-1 ] = '\0';
589
590 m_bCachedRouteValid = ( m_eCachedRouteLocalCandidate != k_EICECandidate_Invalid
591 && m_eCachedRouteRemoteCandidate != k_EICECandidate_Invalid
592 && m_szCachedRouteRemoteAddress[0] != '\0'
593 );
594 }
595
GetRoute(EICECandidateType & eLocalCandidate,EICECandidateType & eRemoteCandidate,CandidateAddressString & szRemoteAddress)596 bool CICESession::GetRoute( EICECandidateType &eLocalCandidate, EICECandidateType &eRemoteCandidate, CandidateAddressString &szRemoteAddress )
597 {
598 if ( !ice_transport_ )
599 m_bCachedRouteValid = false;
600 if ( !m_bCachedRouteValid )
601 return false;
602 eLocalCandidate = m_eCachedRouteLocalCandidate;
603 eRemoteCandidate = m_eCachedRouteRemoteCandidate;
604
605 strcpy( szRemoteAddress, m_szCachedRouteRemoteAddress );
606
607 return true;
608 }
609
OnTransportGatheringState_n(cricket::IceTransportInternal * transport)610 void CICESession::OnTransportGatheringState_n(cricket::IceTransportInternal* transport)
611 {
612 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityInfo, "P2PTransportChannel::OnTransportGatheringState now %d\n", ice_transport_->gathering_state() );
613 }
614
OnTransportCandidateGathered_n(cricket::IceTransportInternal * transport,const cricket::Candidate & candidate)615 void CICESession::OnTransportCandidateGathered_n(cricket::IceTransportInternal* transport, const cricket::Candidate& candidate)
616 {
617 std::string sdp = webrtc::SdpSerializeCandidate( candidate );
618 EICECandidateType eType = GetICECandidateType( candidate );
619 m_pDelegate->OnLocalCandidateGathered( eType, sdp.c_str() );
620 }
621
OnTransportCandidatesRemoved_n(cricket::IceTransportInternal * transport,const cricket::Candidates & candidates)622 void CICESession::OnTransportCandidatesRemoved_n(cricket::IceTransportInternal* transport, const cricket::Candidates& candidates)
623 {
624 // FIXME delegate doesn't understand this right now
625 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityWarning, "Ignoring removal of %d ICE candidate\n", (int)candidates.size() );
626 }
627
OnTransportRoleConflict_n(cricket::IceTransportInternal * transport)628 void CICESession::OnTransportRoleConflict_n(cricket::IceTransportInternal* transport)
629 {
630 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityError, "ICE role conflict detected!\n" );
631 }
632
OnTransportStateChanged_n(cricket::IceTransportInternal * transport)633 void CICESession::OnTransportStateChanged_n(cricket::IceTransportInternal* transport)
634 {
635 cricket::IceTransportState state = ice_transport_->GetState();
636 CacheRouteAndPing();
637 if ( state == cricket::IceTransportState::STATE_COMPLETED )
638 {
639 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityInfo, "ICE completed\n" );
640 //m_pDelegate->OnFinished( true );
641 }
642 else if ( state == cricket::IceTransportState::STATE_FAILED )
643 {
644 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityInfo, "ICE failed\n" );
645 //m_pDelegate->OnFinished( false );
646 }
647 }
648
OnWritableState(rtc::PacketTransportInternal * transport)649 void CICESession::OnWritableState(rtc::PacketTransportInternal* transport)
650 {
651 writable_ = ice_transport_->writable();
652 CacheRouteAndPing();
653 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityInfo, "ICE OnWritableState now %d\n", (int)writable_ );
654 m_pDelegate->OnWritableStateChanged();
655 }
656
OnReadPacket(rtc::PacketTransportInternal * transport,const char * data,size_t size,const int64_t & packet_time,int flags)657 void CICESession::OnReadPacket(
658 rtc::PacketTransportInternal* transport,
659 const char* data,
660 size_t size,
661 const int64_t& packet_time,
662 int flags
663 ) {
664 m_pDelegate->OnData( data, size );
665 }
666
OnSentPacket(rtc::PacketTransportInternal * transport,const rtc::SentPacket & sent_packet)667 void CICESession::OnSentPacket(rtc::PacketTransportInternal* transport, const rtc::SentPacket& sent_packet)
668 {
669 }
670
OnReadyToSend(rtc::PacketTransportInternal * transport)671 void CICESession::OnReadyToSend(rtc::PacketTransportInternal* transport)
672 {
673 }
674
OnReceivingState(rtc::PacketTransportInternal * transport)675 void CICESession::OnReceivingState(rtc::PacketTransportInternal* transport)
676 {
677 CacheRouteAndPing();
678 m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityInfo, "ICE OnReceivingState now %d\n", ice_transport_->receiving() );
679 }
680
OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)681 void CICESession::OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)
682 {
683 CacheRouteAndPing();
684 m_pDelegate->OnRouteChanged();
685 //m_pDelegate->Log( IICESessionDelegate::k_ELogPriorityInfo, "ICE OnNetworkRouteChanged %d\n", ice_transport_->receiving() );
686 }
687