xref: /aosp_15_r20/external/webrtc/rtc_base/async_tcp_socket.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/async_tcp_socket.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <stdint.h>
14*d9f75844SAndroid Build Coastguard Worker #include <string.h>
15*d9f75844SAndroid Build Coastguard Worker 
16*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
17*d9f75844SAndroid Build Coastguard Worker #include <memory>
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/byte_order.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/network/sent_packet.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/third_party/sigslot/sigslot.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"  // for TimeMillis
26*d9f75844SAndroid Build Coastguard Worker 
27*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_POSIX)
28*d9f75844SAndroid Build Coastguard Worker #include <errno.h>
29*d9f75844SAndroid Build Coastguard Worker #endif  // WEBRTC_POSIX
30*d9f75844SAndroid Build Coastguard Worker 
31*d9f75844SAndroid Build Coastguard Worker namespace rtc {
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker static const size_t kMaxPacketSize = 64 * 1024;
34*d9f75844SAndroid Build Coastguard Worker 
35*d9f75844SAndroid Build Coastguard Worker typedef uint16_t PacketLength;
36*d9f75844SAndroid Build Coastguard Worker static const size_t kPacketLenSize = sizeof(PacketLength);
37*d9f75844SAndroid Build Coastguard Worker 
38*d9f75844SAndroid Build Coastguard Worker static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
39*d9f75844SAndroid Build Coastguard Worker 
40*d9f75844SAndroid Build Coastguard Worker // The input buffer will be resized so that at least kMinimumRecvSize bytes can
41*d9f75844SAndroid Build Coastguard Worker // be received (but it will not grow above the maximum size passed to the
42*d9f75844SAndroid Build Coastguard Worker // constructor).
43*d9f75844SAndroid Build Coastguard Worker static const size_t kMinimumRecvSize = 128;
44*d9f75844SAndroid Build Coastguard Worker 
45*d9f75844SAndroid Build Coastguard Worker static const int kListenBacklog = 5;
46*d9f75844SAndroid Build Coastguard Worker 
47*d9f75844SAndroid Build Coastguard Worker // Binds and connects `socket`
ConnectSocket(rtc::Socket * socket,const rtc::SocketAddress & bind_address,const rtc::SocketAddress & remote_address)48*d9f75844SAndroid Build Coastguard Worker Socket* AsyncTCPSocketBase::ConnectSocket(
49*d9f75844SAndroid Build Coastguard Worker     rtc::Socket* socket,
50*d9f75844SAndroid Build Coastguard Worker     const rtc::SocketAddress& bind_address,
51*d9f75844SAndroid Build Coastguard Worker     const rtc::SocketAddress& remote_address) {
52*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<rtc::Socket> owned_socket(socket);
53*d9f75844SAndroid Build Coastguard Worker   if (socket->Bind(bind_address) < 0) {
54*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
55*d9f75844SAndroid Build Coastguard Worker     return nullptr;
56*d9f75844SAndroid Build Coastguard Worker   }
57*d9f75844SAndroid Build Coastguard Worker   if (socket->Connect(remote_address) < 0) {
58*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
59*d9f75844SAndroid Build Coastguard Worker     return nullptr;
60*d9f75844SAndroid Build Coastguard Worker   }
61*d9f75844SAndroid Build Coastguard Worker   return owned_socket.release();
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker 
AsyncTCPSocketBase(Socket * socket,size_t max_packet_size)64*d9f75844SAndroid Build Coastguard Worker AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket,
65*d9f75844SAndroid Build Coastguard Worker                                        size_t max_packet_size)
66*d9f75844SAndroid Build Coastguard Worker     : socket_(socket),
67*d9f75844SAndroid Build Coastguard Worker       max_insize_(max_packet_size),
68*d9f75844SAndroid Build Coastguard Worker       max_outsize_(max_packet_size) {
69*d9f75844SAndroid Build Coastguard Worker   inbuf_.EnsureCapacity(kMinimumRecvSize);
70*d9f75844SAndroid Build Coastguard Worker 
71*d9f75844SAndroid Build Coastguard Worker   socket_->SignalConnectEvent.connect(this,
72*d9f75844SAndroid Build Coastguard Worker                                       &AsyncTCPSocketBase::OnConnectEvent);
73*d9f75844SAndroid Build Coastguard Worker   socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
74*d9f75844SAndroid Build Coastguard Worker   socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
75*d9f75844SAndroid Build Coastguard Worker   socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
76*d9f75844SAndroid Build Coastguard Worker }
77*d9f75844SAndroid Build Coastguard Worker 
~AsyncTCPSocketBase()78*d9f75844SAndroid Build Coastguard Worker AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
79*d9f75844SAndroid Build Coastguard Worker 
GetLocalAddress() const80*d9f75844SAndroid Build Coastguard Worker SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
81*d9f75844SAndroid Build Coastguard Worker   return socket_->GetLocalAddress();
82*d9f75844SAndroid Build Coastguard Worker }
83*d9f75844SAndroid Build Coastguard Worker 
GetRemoteAddress() const84*d9f75844SAndroid Build Coastguard Worker SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
85*d9f75844SAndroid Build Coastguard Worker   return socket_->GetRemoteAddress();
86*d9f75844SAndroid Build Coastguard Worker }
87*d9f75844SAndroid Build Coastguard Worker 
Close()88*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocketBase::Close() {
89*d9f75844SAndroid Build Coastguard Worker   return socket_->Close();
90*d9f75844SAndroid Build Coastguard Worker }
91*d9f75844SAndroid Build Coastguard Worker 
GetState() const92*d9f75844SAndroid Build Coastguard Worker AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
93*d9f75844SAndroid Build Coastguard Worker   switch (socket_->GetState()) {
94*d9f75844SAndroid Build Coastguard Worker     case Socket::CS_CLOSED:
95*d9f75844SAndroid Build Coastguard Worker       return STATE_CLOSED;
96*d9f75844SAndroid Build Coastguard Worker     case Socket::CS_CONNECTING:
97*d9f75844SAndroid Build Coastguard Worker       return STATE_CONNECTING;
98*d9f75844SAndroid Build Coastguard Worker     case Socket::CS_CONNECTED:
99*d9f75844SAndroid Build Coastguard Worker       return STATE_CONNECTED;
100*d9f75844SAndroid Build Coastguard Worker     default:
101*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_NOTREACHED();
102*d9f75844SAndroid Build Coastguard Worker       return STATE_CLOSED;
103*d9f75844SAndroid Build Coastguard Worker   }
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker 
GetOption(Socket::Option opt,int * value)106*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
107*d9f75844SAndroid Build Coastguard Worker   return socket_->GetOption(opt, value);
108*d9f75844SAndroid Build Coastguard Worker }
109*d9f75844SAndroid Build Coastguard Worker 
SetOption(Socket::Option opt,int value)110*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
111*d9f75844SAndroid Build Coastguard Worker   return socket_->SetOption(opt, value);
112*d9f75844SAndroid Build Coastguard Worker }
113*d9f75844SAndroid Build Coastguard Worker 
GetError() const114*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocketBase::GetError() const {
115*d9f75844SAndroid Build Coastguard Worker   return socket_->GetError();
116*d9f75844SAndroid Build Coastguard Worker }
117*d9f75844SAndroid Build Coastguard Worker 
SetError(int error)118*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocketBase::SetError(int error) {
119*d9f75844SAndroid Build Coastguard Worker   return socket_->SetError(error);
120*d9f75844SAndroid Build Coastguard Worker }
121*d9f75844SAndroid Build Coastguard Worker 
SendTo(const void * pv,size_t cb,const SocketAddress & addr,const rtc::PacketOptions & options)122*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocketBase::SendTo(const void* pv,
123*d9f75844SAndroid Build Coastguard Worker                                size_t cb,
124*d9f75844SAndroid Build Coastguard Worker                                const SocketAddress& addr,
125*d9f75844SAndroid Build Coastguard Worker                                const rtc::PacketOptions& options) {
126*d9f75844SAndroid Build Coastguard Worker   const SocketAddress& remote_address = GetRemoteAddress();
127*d9f75844SAndroid Build Coastguard Worker   if (addr == remote_address)
128*d9f75844SAndroid Build Coastguard Worker     return Send(pv, cb, options);
129*d9f75844SAndroid Build Coastguard Worker   // Remote address may be empty if there is a sudden network change.
130*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(remote_address.IsNil());
131*d9f75844SAndroid Build Coastguard Worker   socket_->SetError(ENOTCONN);
132*d9f75844SAndroid Build Coastguard Worker   return -1;
133*d9f75844SAndroid Build Coastguard Worker }
134*d9f75844SAndroid Build Coastguard Worker 
FlushOutBuffer()135*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocketBase::FlushOutBuffer() {
136*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(outbuf_.size(), 0);
137*d9f75844SAndroid Build Coastguard Worker   rtc::ArrayView<uint8_t> view = outbuf_;
138*d9f75844SAndroid Build Coastguard Worker   int res;
139*d9f75844SAndroid Build Coastguard Worker   while (view.size() > 0) {
140*d9f75844SAndroid Build Coastguard Worker     res = socket_->Send(view.data(), view.size());
141*d9f75844SAndroid Build Coastguard Worker     if (res <= 0) {
142*d9f75844SAndroid Build Coastguard Worker       break;
143*d9f75844SAndroid Build Coastguard Worker     }
144*d9f75844SAndroid Build Coastguard Worker     if (static_cast<size_t>(res) > view.size()) {
145*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_NOTREACHED();
146*d9f75844SAndroid Build Coastguard Worker       res = -1;
147*d9f75844SAndroid Build Coastguard Worker       break;
148*d9f75844SAndroid Build Coastguard Worker     }
149*d9f75844SAndroid Build Coastguard Worker     view = view.subview(res);
150*d9f75844SAndroid Build Coastguard Worker   }
151*d9f75844SAndroid Build Coastguard Worker   if (res > 0) {
152*d9f75844SAndroid Build Coastguard Worker     // The output buffer may have been written out over multiple partial Send(),
153*d9f75844SAndroid Build Coastguard Worker     // so reconstruct the total written length.
154*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(view.size(), 0);
155*d9f75844SAndroid Build Coastguard Worker     res = outbuf_.size();
156*d9f75844SAndroid Build Coastguard Worker     outbuf_.Clear();
157*d9f75844SAndroid Build Coastguard Worker   } else {
158*d9f75844SAndroid Build Coastguard Worker     // There was an error when calling Send(), so there will still be data left
159*d9f75844SAndroid Build Coastguard Worker     // to send at a later point.
160*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GT(view.size(), 0);
161*d9f75844SAndroid Build Coastguard Worker     // In the special case of EWOULDBLOCK, signal that we had a partial write.
162*d9f75844SAndroid Build Coastguard Worker     if (socket_->GetError() == EWOULDBLOCK) {
163*d9f75844SAndroid Build Coastguard Worker       res = outbuf_.size() - view.size();
164*d9f75844SAndroid Build Coastguard Worker     }
165*d9f75844SAndroid Build Coastguard Worker     if (view.size() < outbuf_.size()) {
166*d9f75844SAndroid Build Coastguard Worker       memmove(outbuf_.data(), view.data(), view.size());
167*d9f75844SAndroid Build Coastguard Worker       outbuf_.SetSize(view.size());
168*d9f75844SAndroid Build Coastguard Worker     }
169*d9f75844SAndroid Build Coastguard Worker   }
170*d9f75844SAndroid Build Coastguard Worker   return res;
171*d9f75844SAndroid Build Coastguard Worker }
172*d9f75844SAndroid Build Coastguard Worker 
AppendToOutBuffer(const void * pv,size_t cb)173*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
174*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
175*d9f75844SAndroid Build Coastguard Worker   outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
176*d9f75844SAndroid Build Coastguard Worker }
177*d9f75844SAndroid Build Coastguard Worker 
OnConnectEvent(Socket * socket)178*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocketBase::OnConnectEvent(Socket* socket) {
179*d9f75844SAndroid Build Coastguard Worker   SignalConnect(this);
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker 
OnReadEvent(Socket * socket)182*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocketBase::OnReadEvent(Socket* socket) {
183*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(socket_.get() == socket);
184*d9f75844SAndroid Build Coastguard Worker 
185*d9f75844SAndroid Build Coastguard Worker   size_t total_recv = 0;
186*d9f75844SAndroid Build Coastguard Worker   while (true) {
187*d9f75844SAndroid Build Coastguard Worker     size_t free_size = inbuf_.capacity() - inbuf_.size();
188*d9f75844SAndroid Build Coastguard Worker     if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
189*d9f75844SAndroid Build Coastguard Worker       inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
190*d9f75844SAndroid Build Coastguard Worker       free_size = inbuf_.capacity() - inbuf_.size();
191*d9f75844SAndroid Build Coastguard Worker     }
192*d9f75844SAndroid Build Coastguard Worker 
193*d9f75844SAndroid Build Coastguard Worker     int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
194*d9f75844SAndroid Build Coastguard Worker     if (len < 0) {
195*d9f75844SAndroid Build Coastguard Worker       // TODO(stefan): Do something better like forwarding the error to the
196*d9f75844SAndroid Build Coastguard Worker       // user.
197*d9f75844SAndroid Build Coastguard Worker       if (!socket_->IsBlocking()) {
198*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
199*d9f75844SAndroid Build Coastguard Worker       }
200*d9f75844SAndroid Build Coastguard Worker       break;
201*d9f75844SAndroid Build Coastguard Worker     }
202*d9f75844SAndroid Build Coastguard Worker 
203*d9f75844SAndroid Build Coastguard Worker     total_recv += len;
204*d9f75844SAndroid Build Coastguard Worker     inbuf_.SetSize(inbuf_.size() + len);
205*d9f75844SAndroid Build Coastguard Worker     if (!len || static_cast<size_t>(len) < free_size) {
206*d9f75844SAndroid Build Coastguard Worker       break;
207*d9f75844SAndroid Build Coastguard Worker     }
208*d9f75844SAndroid Build Coastguard Worker   }
209*d9f75844SAndroid Build Coastguard Worker 
210*d9f75844SAndroid Build Coastguard Worker   if (!total_recv) {
211*d9f75844SAndroid Build Coastguard Worker     return;
212*d9f75844SAndroid Build Coastguard Worker   }
213*d9f75844SAndroid Build Coastguard Worker 
214*d9f75844SAndroid Build Coastguard Worker   size_t size = inbuf_.size();
215*d9f75844SAndroid Build Coastguard Worker   ProcessInput(inbuf_.data<char>(), &size);
216*d9f75844SAndroid Build Coastguard Worker 
217*d9f75844SAndroid Build Coastguard Worker   if (size > inbuf_.size()) {
218*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "input buffer overflow";
219*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_NOTREACHED();
220*d9f75844SAndroid Build Coastguard Worker     inbuf_.Clear();
221*d9f75844SAndroid Build Coastguard Worker   } else {
222*d9f75844SAndroid Build Coastguard Worker     inbuf_.SetSize(size);
223*d9f75844SAndroid Build Coastguard Worker   }
224*d9f75844SAndroid Build Coastguard Worker }
225*d9f75844SAndroid Build Coastguard Worker 
OnWriteEvent(Socket * socket)226*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) {
227*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(socket_.get() == socket);
228*d9f75844SAndroid Build Coastguard Worker 
229*d9f75844SAndroid Build Coastguard Worker   if (outbuf_.size() > 0) {
230*d9f75844SAndroid Build Coastguard Worker     FlushOutBuffer();
231*d9f75844SAndroid Build Coastguard Worker   }
232*d9f75844SAndroid Build Coastguard Worker 
233*d9f75844SAndroid Build Coastguard Worker   if (outbuf_.size() == 0) {
234*d9f75844SAndroid Build Coastguard Worker     SignalReadyToSend(this);
235*d9f75844SAndroid Build Coastguard Worker   }
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker 
OnCloseEvent(Socket * socket,int error)238*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) {
239*d9f75844SAndroid Build Coastguard Worker   NotifyClosed(error);
240*d9f75844SAndroid Build Coastguard Worker }
241*d9f75844SAndroid Build Coastguard Worker 
242*d9f75844SAndroid Build Coastguard Worker // AsyncTCPSocket
243*d9f75844SAndroid Build Coastguard Worker // Binds and connects `socket` and creates AsyncTCPSocket for
244*d9f75844SAndroid Build Coastguard Worker // it. Takes ownership of `socket`. Returns null if bind() or
245*d9f75844SAndroid Build Coastguard Worker // connect() fail (`socket` is destroyed in that case).
Create(Socket * socket,const SocketAddress & bind_address,const SocketAddress & remote_address)246*d9f75844SAndroid Build Coastguard Worker AsyncTCPSocket* AsyncTCPSocket::Create(Socket* socket,
247*d9f75844SAndroid Build Coastguard Worker                                        const SocketAddress& bind_address,
248*d9f75844SAndroid Build Coastguard Worker                                        const SocketAddress& remote_address) {
249*d9f75844SAndroid Build Coastguard Worker   return new AsyncTCPSocket(
250*d9f75844SAndroid Build Coastguard Worker       AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address));
251*d9f75844SAndroid Build Coastguard Worker }
252*d9f75844SAndroid Build Coastguard Worker 
AsyncTCPSocket(Socket * socket)253*d9f75844SAndroid Build Coastguard Worker AsyncTCPSocket::AsyncTCPSocket(Socket* socket)
254*d9f75844SAndroid Build Coastguard Worker     : AsyncTCPSocketBase(socket, kBufSize) {}
255*d9f75844SAndroid Build Coastguard Worker 
Send(const void * pv,size_t cb,const rtc::PacketOptions & options)256*d9f75844SAndroid Build Coastguard Worker int AsyncTCPSocket::Send(const void* pv,
257*d9f75844SAndroid Build Coastguard Worker                          size_t cb,
258*d9f75844SAndroid Build Coastguard Worker                          const rtc::PacketOptions& options) {
259*d9f75844SAndroid Build Coastguard Worker   if (cb > kBufSize) {
260*d9f75844SAndroid Build Coastguard Worker     SetError(EMSGSIZE);
261*d9f75844SAndroid Build Coastguard Worker     return -1;
262*d9f75844SAndroid Build Coastguard Worker   }
263*d9f75844SAndroid Build Coastguard Worker 
264*d9f75844SAndroid Build Coastguard Worker   // If we are blocking on send, then silently drop this packet
265*d9f75844SAndroid Build Coastguard Worker   if (!IsOutBufferEmpty())
266*d9f75844SAndroid Build Coastguard Worker     return static_cast<int>(cb);
267*d9f75844SAndroid Build Coastguard Worker 
268*d9f75844SAndroid Build Coastguard Worker   PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
269*d9f75844SAndroid Build Coastguard Worker   AppendToOutBuffer(&pkt_len, kPacketLenSize);
270*d9f75844SAndroid Build Coastguard Worker   AppendToOutBuffer(pv, cb);
271*d9f75844SAndroid Build Coastguard Worker 
272*d9f75844SAndroid Build Coastguard Worker   int res = FlushOutBuffer();
273*d9f75844SAndroid Build Coastguard Worker   if (res <= 0) {
274*d9f75844SAndroid Build Coastguard Worker     // drop packet if we made no progress
275*d9f75844SAndroid Build Coastguard Worker     ClearOutBuffer();
276*d9f75844SAndroid Build Coastguard Worker     return res;
277*d9f75844SAndroid Build Coastguard Worker   }
278*d9f75844SAndroid Build Coastguard Worker 
279*d9f75844SAndroid Build Coastguard Worker   rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
280*d9f75844SAndroid Build Coastguard Worker                               options.info_signaled_after_sent);
281*d9f75844SAndroid Build Coastguard Worker   CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
282*d9f75844SAndroid Build Coastguard Worker   SignalSentPacket(this, sent_packet);
283*d9f75844SAndroid Build Coastguard Worker 
284*d9f75844SAndroid Build Coastguard Worker   // We claim to have sent the whole thing, even if we only sent partial
285*d9f75844SAndroid Build Coastguard Worker   return static_cast<int>(cb);
286*d9f75844SAndroid Build Coastguard Worker }
287*d9f75844SAndroid Build Coastguard Worker 
ProcessInput(char * data,size_t * len)288*d9f75844SAndroid Build Coastguard Worker void AsyncTCPSocket::ProcessInput(char* data, size_t* len) {
289*d9f75844SAndroid Build Coastguard Worker   SocketAddress remote_addr(GetRemoteAddress());
290*d9f75844SAndroid Build Coastguard Worker 
291*d9f75844SAndroid Build Coastguard Worker   while (true) {
292*d9f75844SAndroid Build Coastguard Worker     if (*len < kPacketLenSize)
293*d9f75844SAndroid Build Coastguard Worker       return;
294*d9f75844SAndroid Build Coastguard Worker 
295*d9f75844SAndroid Build Coastguard Worker     PacketLength pkt_len = rtc::GetBE16(data);
296*d9f75844SAndroid Build Coastguard Worker     if (*len < kPacketLenSize + pkt_len)
297*d9f75844SAndroid Build Coastguard Worker       return;
298*d9f75844SAndroid Build Coastguard Worker 
299*d9f75844SAndroid Build Coastguard Worker     SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
300*d9f75844SAndroid Build Coastguard Worker                      TimeMicros());
301*d9f75844SAndroid Build Coastguard Worker 
302*d9f75844SAndroid Build Coastguard Worker     *len -= kPacketLenSize + pkt_len;
303*d9f75844SAndroid Build Coastguard Worker     if (*len > 0) {
304*d9f75844SAndroid Build Coastguard Worker       memmove(data, data + kPacketLenSize + pkt_len, *len);
305*d9f75844SAndroid Build Coastguard Worker     }
306*d9f75844SAndroid Build Coastguard Worker   }
307*d9f75844SAndroid Build Coastguard Worker }
308*d9f75844SAndroid Build Coastguard Worker 
AsyncTcpListenSocket(std::unique_ptr<Socket> socket)309*d9f75844SAndroid Build Coastguard Worker AsyncTcpListenSocket::AsyncTcpListenSocket(std::unique_ptr<Socket> socket)
310*d9f75844SAndroid Build Coastguard Worker     : socket_(std::move(socket)) {
311*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(socket_.get() != nullptr);
312*d9f75844SAndroid Build Coastguard Worker   socket_->SignalReadEvent.connect(this, &AsyncTcpListenSocket::OnReadEvent);
313*d9f75844SAndroid Build Coastguard Worker   if (socket_->Listen(kListenBacklog) < 0) {
314*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
315*d9f75844SAndroid Build Coastguard Worker   }
316*d9f75844SAndroid Build Coastguard Worker }
317*d9f75844SAndroid Build Coastguard Worker 
GetState() const318*d9f75844SAndroid Build Coastguard Worker AsyncTcpListenSocket::State AsyncTcpListenSocket::GetState() const {
319*d9f75844SAndroid Build Coastguard Worker   switch (socket_->GetState()) {
320*d9f75844SAndroid Build Coastguard Worker     case Socket::CS_CLOSED:
321*d9f75844SAndroid Build Coastguard Worker       return State::kClosed;
322*d9f75844SAndroid Build Coastguard Worker     case Socket::CS_CONNECTING:
323*d9f75844SAndroid Build Coastguard Worker       return State::kBound;
324*d9f75844SAndroid Build Coastguard Worker     default:
325*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_NOTREACHED();
326*d9f75844SAndroid Build Coastguard Worker       return State::kClosed;
327*d9f75844SAndroid Build Coastguard Worker   }
328*d9f75844SAndroid Build Coastguard Worker }
329*d9f75844SAndroid Build Coastguard Worker 
GetLocalAddress() const330*d9f75844SAndroid Build Coastguard Worker SocketAddress AsyncTcpListenSocket::GetLocalAddress() const {
331*d9f75844SAndroid Build Coastguard Worker   return socket_->GetLocalAddress();
332*d9f75844SAndroid Build Coastguard Worker }
333*d9f75844SAndroid Build Coastguard Worker 
OnReadEvent(Socket * socket)334*d9f75844SAndroid Build Coastguard Worker void AsyncTcpListenSocket::OnReadEvent(Socket* socket) {
335*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(socket_.get() == socket);
336*d9f75844SAndroid Build Coastguard Worker 
337*d9f75844SAndroid Build Coastguard Worker   rtc::SocketAddress address;
338*d9f75844SAndroid Build Coastguard Worker   rtc::Socket* new_socket = socket->Accept(&address);
339*d9f75844SAndroid Build Coastguard Worker   if (!new_socket) {
340*d9f75844SAndroid Build Coastguard Worker     // TODO(stefan): Do something better like forwarding the error
341*d9f75844SAndroid Build Coastguard Worker     // to the user.
342*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
343*d9f75844SAndroid Build Coastguard Worker     return;
344*d9f75844SAndroid Build Coastguard Worker   }
345*d9f75844SAndroid Build Coastguard Worker 
346*d9f75844SAndroid Build Coastguard Worker   HandleIncomingConnection(new_socket);
347*d9f75844SAndroid Build Coastguard Worker 
348*d9f75844SAndroid Build Coastguard Worker   // Prime a read event in case data is waiting.
349*d9f75844SAndroid Build Coastguard Worker   new_socket->SignalReadEvent(new_socket);
350*d9f75844SAndroid Build Coastguard Worker }
351*d9f75844SAndroid Build Coastguard Worker 
HandleIncomingConnection(Socket * socket)352*d9f75844SAndroid Build Coastguard Worker void AsyncTcpListenSocket::HandleIncomingConnection(Socket* socket) {
353*d9f75844SAndroid Build Coastguard Worker   SignalNewConnection(this, new AsyncTCPSocket(socket));
354*d9f75844SAndroid Build Coastguard Worker }
355*d9f75844SAndroid Build Coastguard Worker 
356*d9f75844SAndroid Build Coastguard Worker }  // namespace rtc
357