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