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