@@ -20,6 +20,7 @@ enum PreservedErrno {
2020// Successful return value from usrsctp callbacks. Is not actually used by
2121// usrsctp, but all example programs for usrsctp use 1 as their return value.
2222constexpr int kSctpSuccessReturn = 1 ;
23+ constexpr int kSctpErrorReturn = 0 ;
2324
2425} // namespace
2526
@@ -83,6 +84,19 @@ enum {
8384// Should only be modified by UsrSctpWrapper.
8485ABSL_CONST_INIT cricket::SctpTransportMap* g_transport_map_ = nullptr ;
8586
87+ // Helper that will call C's free automatically.
88+ // TODO(b/181900299): Figure out why unique_ptr with a custom deleter is causing
89+ // issues in a certain build environment.
90+ class AutoFreedPointer {
91+ public:
92+ explicit AutoFreedPointer (void * ptr) : ptr_(ptr) {}
93+ AutoFreedPointer (AutoFreedPointer&& o) : ptr_(o.ptr_) { o.ptr_ = nullptr ; }
94+ ~AutoFreedPointer () { free (ptr_); }
95+ void * get () const { return ptr_; }
96+ private:
97+ void * ptr_;
98+ };
99+
86100// Helper for logging SCTP messages.
87101#if defined(__GNUC__)
88102__attribute__ ((__format__(__printf__, 1 , 2 )))
@@ -239,32 +253,20 @@ class SctpTransportMap {
239253 return map_.erase (id) > 0 ;
240254 }
241255
242- // Must be called on the transport's network thread to protect against
243- // simultaneous deletion/deregistration of the transport; if that's not
244- // guaranteed, use ExecuteWithLock.
245- SctpTransport* Retrieve (uintptr_t id) const {
246- webrtc::MutexLock lock (&lock_);
247- SctpTransport* transport = RetrieveWhileHoldingLock (id);
248- if (transport) {
249- RTC_DCHECK_RUN_ON (transport->network_thread ());
250- }
251- return transport;
252- }
253-
254256 // Posts |action| to the network thread of the transport identified by |id|
255257 // and returns true if found, all while holding a lock to protect against the
256258 // transport being simultaneously deleted/deregistered, or returns false if
257259 // not found.
258- bool PostToTransportThread ( uintptr_t id,
259- std::function< void (SctpTransport*)> action) const {
260+ template < typename F>
261+ bool PostToTransportThread ( uintptr_t id, F action) const {
260262 webrtc::MutexLock lock (&lock_);
261263 SctpTransport* transport = RetrieveWhileHoldingLock (id);
262264 if (!transport) {
263265 return false ;
264266 }
265267 transport->invoker_ .AsyncInvoke <void >(
266- RTC_FROM_HERE, transport->network_thread_ , [transport, action]() {
267- action (transport); });
268+ RTC_FROM_HERE, transport->network_thread_ ,
269+ [transport, action{ std::move (action)}]() { action (transport); });
268270 return true ;
269271 }
270272
@@ -406,7 +408,7 @@ class SctpTransport::UsrSctpWrapper {
406408 if (!found) {
407409 RTC_LOG (LS_ERROR)
408410 << " OnSctpOutboundPacket: Failed to get transport for socket ID "
409- << addr;
411+ << addr << " ; possibly was already destroyed. " ;
410412 return EINVAL;
411413 }
412414 return 0 ;
@@ -423,28 +425,45 @@ class SctpTransport::UsrSctpWrapper {
423425 struct sctp_rcvinfo rcv,
424426 int flags,
425427 void * ulp_info) {
426- SctpTransport* transport = GetTransportFromSocket (sock);
427- if (!transport) {
428+ AutoFreedPointer owned_data (data);
429+ absl::optional<uintptr_t > id = GetTransportIdFromSocket (sock);
430+ if (!id) {
428431 RTC_LOG (LS_ERROR)
429- << " OnSctpInboundPacket: Failed to get transport for socket " << sock
430- << " ; possibly was already destroyed." ;
431- free (data);
432- return 0 ;
432+ << " OnSctpInboundPacket: Failed to get transport ID from socket "
433+ << sock;
434+ return kSctpErrorReturn ;
435+ }
436+
437+ if (!g_transport_map_) {
438+ RTC_LOG (LS_ERROR)
439+ << " OnSctpInboundPacket called after usrsctp uninitialized?" ;
440+ return kSctpErrorReturn ;
441+ }
442+ // PostsToTransportThread protects against the transport being
443+ // simultaneously deregistered/deleted, since this callback may come from
444+ // the SCTP timer thread and thus race with the network thread.
445+ bool found = g_transport_map_->PostToTransportThread (
446+ *id, [owned_data{std::move (owned_data)}, length, rcv,
447+ flags](SctpTransport* transport) {
448+ transport->OnDataOrNotificationFromSctp (owned_data.get (), length, rcv,
449+ flags);
450+ });
451+ if (!found) {
452+ RTC_LOG (LS_ERROR)
453+ << " OnSctpInboundPacket: Failed to get transport for socket ID "
454+ << *id << " ; possibly was already destroyed." ;
455+ return kSctpErrorReturn ;
433456 }
434- // Sanity check that both methods of getting the SctpTransport pointer
435- // yield the same result.
436- RTC_CHECK_EQ (transport, static_cast <SctpTransport*>(ulp_info));
437- int result =
438- transport->OnDataOrNotificationFromSctp (data, length, rcv, flags);
439- free (data);
440- return result;
457+ return kSctpSuccessReturn ;
441458 }
442459
443- static SctpTransport* GetTransportFromSocket (struct socket * sock) {
460+ static absl::optional<uintptr_t > GetTransportIdFromSocket (
461+ struct socket * sock) {
462+ absl::optional<uintptr_t > ret;
444463 struct sockaddr * addrs = nullptr ;
445464 int naddrs = usrsctp_getladdrs (sock, 0 , &addrs);
446465 if (naddrs <= 0 || addrs[0 ].sa_family != AF_CONN) {
447- return nullptr ;
466+ return ret ;
448467 }
449468 // usrsctp_getladdrs() returns the addresses bound to this socket, which
450469 // contains the SctpTransport id as sconn_addr. Read the id,
@@ -453,17 +472,10 @@ class SctpTransport::UsrSctpWrapper {
453472 // id of the transport that created them, so [0] is as good as any other.
454473 struct sockaddr_conn * sconn =
455474 reinterpret_cast <struct sockaddr_conn *>(&addrs[0 ]);
456- if (!g_transport_map_) {
457- RTC_LOG (LS_ERROR)
458- << " GetTransportFromSocket called after usrsctp uninitialized?" ;
459- usrsctp_freeladdrs (addrs);
460- return nullptr ;
461- }
462- SctpTransport* transport = g_transport_map_->Retrieve (
463- reinterpret_cast <uintptr_t >(sconn->sconn_addr ));
475+ ret = reinterpret_cast <uintptr_t >(sconn->sconn_addr );
464476 usrsctp_freeladdrs (addrs);
465477
466- return transport ;
478+ return ret ;
467479 }
468480
469481 // TODO(crbug.com/webrtc/11899): This is a legacy callback signature, remove
@@ -472,14 +484,26 @@ class SctpTransport::UsrSctpWrapper {
472484 // Fired on our I/O thread. SctpTransport::OnPacketReceived() gets
473485 // a packet containing acknowledgments, which goes into usrsctp_conninput,
474486 // and then back here.
475- SctpTransport* transport = GetTransportFromSocket (sock);
476- if (!transport ) {
487+ absl::optional< uintptr_t > id = GetTransportIdFromSocket (sock);
488+ if (!id ) {
477489 RTC_LOG (LS_ERROR)
478- << " SendThresholdCallback: Failed to get transport for socket "
479- << sock << " ; possibly was already destroyed. " ;
490+ << " SendThresholdCallback: Failed to get transport ID from socket "
491+ << sock;
480492 return 0 ;
481493 }
482- transport->OnSendThresholdCallback ();
494+ if (!g_transport_map_) {
495+ RTC_LOG (LS_ERROR)
496+ << " SendThresholdCallback called after usrsctp uninitialized?" ;
497+ return 0 ;
498+ }
499+ bool found = g_transport_map_->PostToTransportThread (
500+ *id,
501+ [](SctpTransport* transport) { transport->OnSendThresholdCallback (); });
502+ if (!found) {
503+ RTC_LOG (LS_ERROR)
504+ << " SendThresholdCallback: Failed to get transport for socket ID "
505+ << *id << " ; possibly was already destroyed." ;
506+ }
483507 return 0 ;
484508 }
485509
@@ -489,17 +513,26 @@ class SctpTransport::UsrSctpWrapper {
489513 // Fired on our I/O thread. SctpTransport::OnPacketReceived() gets
490514 // a packet containing acknowledgments, which goes into usrsctp_conninput,
491515 // and then back here.
492- SctpTransport* transport = GetTransportFromSocket (sock);
493- if (!transport ) {
516+ absl::optional< uintptr_t > id = GetTransportIdFromSocket (sock);
517+ if (!id ) {
494518 RTC_LOG (LS_ERROR)
495- << " SendThresholdCallback: Failed to get transport for socket "
496- << sock << " ; possibly was already destroyed. " ;
519+ << " SendThresholdCallback: Failed to get transport ID from socket "
520+ << sock;
497521 return 0 ;
498522 }
499- // Sanity check that both methods of getting the SctpTransport pointer
500- // yield the same result.
501- RTC_CHECK_EQ (transport, static_cast <SctpTransport*>(ulp_info));
502- transport->OnSendThresholdCallback ();
523+ if (!g_transport_map_) {
524+ RTC_LOG (LS_ERROR)
525+ << " SendThresholdCallback called after usrsctp uninitialized?" ;
526+ return 0 ;
527+ }
528+ bool found = g_transport_map_->PostToTransportThread (
529+ *id,
530+ [](SctpTransport* transport) { transport->OnSendThresholdCallback (); });
531+ if (!found) {
532+ RTC_LOG (LS_ERROR)
533+ << " SendThresholdCallback: Failed to get transport for socket ID "
534+ << *id << " ; possibly was already destroyed." ;
535+ }
503536 return 0 ;
504537 }
505538};
@@ -1150,24 +1183,25 @@ void SctpTransport::OnPacketFromSctpToNetwork(
11501183 rtc::PacketOptions (), PF_NORMAL);
11511184}
11521185
1153- int SctpTransport::InjectDataOrNotificationFromSctpForTesting (
1186+ void SctpTransport::InjectDataOrNotificationFromSctpForTesting (
11541187 void * data,
11551188 size_t length,
11561189 struct sctp_rcvinfo rcv,
11571190 int flags) {
1158- return OnDataOrNotificationFromSctp (data, length, rcv, flags);
1191+ OnDataOrNotificationFromSctp (data, length, rcv, flags);
11591192}
11601193
1161- int SctpTransport::OnDataOrNotificationFromSctp (void * data,
1162- size_t length,
1163- struct sctp_rcvinfo rcv,
1164- int flags) {
1194+ void SctpTransport::OnDataOrNotificationFromSctp (void * data,
1195+ size_t length,
1196+ struct sctp_rcvinfo rcv,
1197+ int flags) {
1198+ RTC_DCHECK_RUN_ON (network_thread_);
11651199 // If data is NULL, the SCTP association has been closed.
11661200 if (!data) {
11671201 RTC_LOG (LS_INFO) << debug_name_
11681202 << " ->OnDataOrNotificationFromSctp(...): "
11691203 " No data; association closed." ;
1170- return kSctpSuccessReturn ;
1204+ return ;
11711205 }
11721206
11731207 // Handle notifications early.
@@ -1180,13 +1214,10 @@ int SctpTransport::OnDataOrNotificationFromSctp(void* data,
11801214 << " ->OnDataOrNotificationFromSctp(...): SCTP notification"
11811215 << " length=" << length;
11821216
1183- // Copy and dispatch asynchronously
11841217 rtc::CopyOnWriteBuffer notification (reinterpret_cast <uint8_t *>(data),
11851218 length);
1186- invoker_.AsyncInvoke <void >(
1187- RTC_FROM_HERE, network_thread_,
1188- rtc::Bind (&SctpTransport::OnNotificationFromSctp, this , notification));
1189- return kSctpSuccessReturn ;
1219+ OnNotificationFromSctp (notification);
1220+ return ;
11901221 }
11911222
11921223 // Log data chunk
@@ -1204,7 +1235,7 @@ int SctpTransport::OnDataOrNotificationFromSctp(void* data,
12041235 // Unexpected PPID, dropping
12051236 RTC_LOG (LS_ERROR) << " Received an unknown PPID " << ppid
12061237 << " on an SCTP packet. Dropping." ;
1207- return kSctpSuccessReturn ;
1238+ return ;
12081239 }
12091240
12101241 // Expect only continuation messages belonging to the same SID. The SCTP
@@ -1240,7 +1271,7 @@ int SctpTransport::OnDataOrNotificationFromSctp(void* data,
12401271 if (partial_incoming_message_.size () < kSctpSendBufferSize ) {
12411272 // We still have space in the buffer. Continue buffering chunks until
12421273 // the message is complete before handing it out.
1243- return kSctpSuccessReturn ;
1274+ return ;
12441275 } else {
12451276 // The sender is exceeding the maximum message size that we announced.
12461277 // Spit out a warning but still hand out the partial message. Note that
@@ -1254,17 +1285,11 @@ int SctpTransport::OnDataOrNotificationFromSctp(void* data,
12541285 }
12551286 }
12561287
1257- // Dispatch the complete message.
1258- // The ownership of the packet transfers to |invoker_|. Using
1259- // CopyOnWriteBuffer is the most convenient way to do this.
1260- invoker_.AsyncInvoke <void >(
1261- RTC_FROM_HERE, network_thread_,
1262- rtc::Bind (&SctpTransport::OnDataFromSctpToTransport, this , params,
1263- partial_incoming_message_));
1288+ // Dispatch the complete message and reset the message buffer.
12641289
1265- // Reset the message buffer
1290+ // Dispatch the complete message and reset the message buffer.
1291+ OnDataFromSctpToTransport (params, partial_incoming_message_);
12661292 partial_incoming_message_.Clear ();
1267- return kSctpSuccessReturn ;
12681293}
12691294
12701295void SctpTransport::OnDataFromSctpToTransport (
0 commit comments