blob: bc8b7ddbc7bdd459c1a060008e1e4271c9e2c326 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/async_tcp_socket.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <stdint.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000014#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
jbauch313afba2016-03-03 03:41:05 -080016#include <algorithm>
jbauch555604a2016-04-26 03:13:22 -070017#include <memory>
jbauch313afba2016-03-03 03:41:05 -080018
Steve Anton3fa2b802020-01-31 10:31:53 -080019#include "api/array_view.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
Yves Gerey3e707812018-11-28 16:47:49 +010023#include "rtc_base/network/sent_packet.h"
24#include "rtc_base/third_party/sigslot/sigslot.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/time_utils.h" // for TimeMillis
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026
27#if defined(WEBRTC_POSIX)
28#include <errno.h>
29#endif // WEBRTC_POSIX
30
31namespace rtc {
32
33static const size_t kMaxPacketSize = 64 * 1024;
34
Peter Boström0c4e06b2015-10-07 12:23:21 +020035typedef uint16_t PacketLength;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036static const size_t kPacketLenSize = sizeof(PacketLength);
37
38static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
39
jbauch313afba2016-03-03 03:41:05 -080040// The input buffer will be resized so that at least kMinimumRecvSize bytes can
41// be received (but it will not grow above the maximum size passed to the
42// constructor).
43static const size_t kMinimumRecvSize = 128;
44
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000045static const int kListenBacklog = 5;
46
Artem Titov96e3b992021-07-26 16:03:14 +020047// Binds and connects `socket`
Niels Möllerd0b88792021-08-12 10:32:30 +020048Socket* AsyncTCPSocketBase::ConnectSocket(
49 rtc::Socket* socket,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000050 const rtc::SocketAddress& bind_address,
51 const rtc::SocketAddress& remote_address) {
Niels Möllerd0b88792021-08-12 10:32:30 +020052 std::unique_ptr<rtc::Socket> owned_socket(socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000053 if (socket->Bind(bind_address) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010054 RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 14:06:41 -080055 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056 }
57 if (socket->Connect(remote_address) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010058 RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 14:06:41 -080059 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060 }
61 return owned_socket.release();
62}
63
Niels Möllerd0b88792021-08-12 10:32:30 +020064AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065 size_t max_packet_size)
66 : socket_(socket),
jbauch313afba2016-03-03 03:41:05 -080067 max_insize_(max_packet_size),
jbauch250fc652016-02-28 15:06:40 -080068 max_outsize_(max_packet_size) {
Niels Möllerd30ece12021-10-19 10:11:02 +020069 inbuf_.EnsureCapacity(kMinimumRecvSize);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070
deadbeef37f5ecf2017-02-27 14:06:41 -080071 RTC_DCHECK(socket_.get() != nullptr);
Yves Gerey665174f2018-06-19 15:03:05 +020072 socket_->SignalConnectEvent.connect(this,
73 &AsyncTCPSocketBase::OnConnectEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074 socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
75 socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
76 socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077}
78
jbauch3c165762016-02-26 09:31:32 -080079AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000080
81SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
82 return socket_->GetLocalAddress();
83}
84
85SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
86 return socket_->GetRemoteAddress();
87}
88
89int AsyncTCPSocketBase::Close() {
90 return socket_->Close();
91}
92
93AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
94 switch (socket_->GetState()) {
95 case Socket::CS_CLOSED:
96 return STATE_CLOSED;
97 case Socket::CS_CONNECTING:
Niels Möllerd30ece12021-10-19 10:11:02 +020098 return STATE_CONNECTING;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099 case Socket::CS_CONNECTED:
100 return STATE_CONNECTED;
101 default:
jbauch3c165762016-02-26 09:31:32 -0800102 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000103 return STATE_CLOSED;
104 }
105}
106
107int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
108 return socket_->GetOption(opt, value);
109}
110
111int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
112 return socket_->SetOption(opt, value);
113}
114
115int AsyncTCPSocketBase::GetError() const {
116 return socket_->GetError();
117}
118
119void AsyncTCPSocketBase::SetError(int error) {
120 return socket_->SetError(error);
121}
122
Yves Gerey665174f2018-06-19 15:03:05 +0200123int AsyncTCPSocketBase::SendTo(const void* pv,
124 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000125 const SocketAddress& addr,
126 const rtc::PacketOptions& options) {
honghaizb19eba32015-08-03 10:23:31 -0700127 const SocketAddress& remote_address = GetRemoteAddress();
128 if (addr == remote_address)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000129 return Send(pv, cb, options);
honghaizb19eba32015-08-03 10:23:31 -0700130 // Remote address may be empty if there is a sudden network change.
jbauch3c165762016-02-26 09:31:32 -0800131 RTC_DCHECK(remote_address.IsNil());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 socket_->SetError(ENOTCONN);
133 return -1;
134}
135
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000136int AsyncTCPSocketBase::FlushOutBuffer() {
Steve Anton3fa2b802020-01-31 10:31:53 -0800137 RTC_DCHECK_GT(outbuf_.size(), 0);
138 rtc::ArrayView<uint8_t> view = outbuf_;
139 int res;
140 while (view.size() > 0) {
141 res = socket_->Send(view.data(), view.size());
142 if (res <= 0) {
143 break;
144 }
145 if (static_cast<size_t>(res) > view.size()) {
146 RTC_NOTREACHED();
147 res = -1;
148 break;
149 }
150 view = view.subview(res);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151 }
Steve Anton3fa2b802020-01-31 10:31:53 -0800152 if (res > 0) {
153 // The output buffer may have been written out over multiple partial Send(),
154 // so reconstruct the total written length.
155 RTC_DCHECK_EQ(view.size(), 0);
156 res = outbuf_.size();
157 outbuf_.Clear();
158 } else {
159 // There was an error when calling Send(), so there will still be data left
160 // to send at a later point.
161 RTC_DCHECK_GT(view.size(), 0);
162 // In the special case of EWOULDBLOCK, signal that we had a partial write.
163 if (socket_->GetError() == EWOULDBLOCK) {
164 res = outbuf_.size() - view.size();
165 }
166 if (view.size() < outbuf_.size()) {
167 memmove(outbuf_.data(), view.data(), view.size());
168 outbuf_.SetSize(view.size());
169 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000170 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000171 return res;
172}
173
174void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
jbauch250fc652016-02-28 15:06:40 -0800175 RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
jbauch250fc652016-02-28 15:06:40 -0800176 outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000177}
178
Niels Möllerd0b88792021-08-12 10:32:30 +0200179void AsyncTCPSocketBase::OnConnectEvent(Socket* socket) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000180 SignalConnect(this);
181}
182
Niels Möllerd0b88792021-08-12 10:32:30 +0200183void AsyncTCPSocketBase::OnReadEvent(Socket* socket) {
jbauch3c165762016-02-26 09:31:32 -0800184 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000185
Niels Möllerd30ece12021-10-19 10:11:02 +0200186 size_t total_recv = 0;
187 while (true) {
188 size_t free_size = inbuf_.capacity() - inbuf_.size();
189 if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
190 inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
191 free_size = inbuf_.capacity() - inbuf_.size();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000192 }
193
Niels Möllerd30ece12021-10-19 10:11:02 +0200194 int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
195 if (len < 0) {
196 // TODO(stefan): Do something better like forwarding the error to the
197 // user.
198 if (!socket_->IsBlocking()) {
199 RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
200 }
201 break;
202 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000203
Niels Möllerd30ece12021-10-19 10:11:02 +0200204 total_recv += len;
205 inbuf_.SetSize(inbuf_.size() + len);
206 if (!len || static_cast<size_t>(len) < free_size) {
207 break;
208 }
209 }
210
211 if (!total_recv) {
212 return;
213 }
214
215 size_t size = inbuf_.size();
216 ProcessInput(inbuf_.data<char>(), &size);
217
218 if (size > inbuf_.size()) {
219 RTC_LOG(LS_ERROR) << "input buffer overflow";
220 RTC_NOTREACHED();
221 inbuf_.Clear();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000222 } else {
Niels Möllerd30ece12021-10-19 10:11:02 +0200223 inbuf_.SetSize(size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224 }
225}
226
Niels Möllerd0b88792021-08-12 10:32:30 +0200227void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) {
jbauch3c165762016-02-26 09:31:32 -0800228 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000229
jbauch250fc652016-02-28 15:06:40 -0800230 if (outbuf_.size() > 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 FlushOutBuffer();
232 }
233
jbauch250fc652016-02-28 15:06:40 -0800234 if (outbuf_.size() == 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235 SignalReadyToSend(this);
236 }
237}
238
Niels Möllerd0b88792021-08-12 10:32:30 +0200239void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240 SignalClose(this, error);
241}
242
243// AsyncTCPSocket
Artem Titov96e3b992021-07-26 16:03:14 +0200244// Binds and connects `socket` and creates AsyncTCPSocket for
245// it. Takes ownership of `socket`. Returns null if bind() or
246// connect() fail (`socket` is destroyed in that case).
Niels Möllerd0b88792021-08-12 10:32:30 +0200247AsyncTCPSocket* AsyncTCPSocket::Create(Socket* socket,
Yves Gerey665174f2018-06-19 15:03:05 +0200248 const SocketAddress& bind_address,
249 const SocketAddress& remote_address) {
250 return new AsyncTCPSocket(
Niels Möllerd30ece12021-10-19 10:11:02 +0200251 AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252}
253
Niels Möllerd30ece12021-10-19 10:11:02 +0200254AsyncTCPSocket::AsyncTCPSocket(Socket* socket)
255 : AsyncTCPSocketBase(socket, kBufSize) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000256
Yves Gerey665174f2018-06-19 15:03:05 +0200257int AsyncTCPSocket::Send(const void* pv,
258 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000259 const rtc::PacketOptions& options) {
260 if (cb > kBufSize) {
261 SetError(EMSGSIZE);
262 return -1;
263 }
264
265 // If we are blocking on send, then silently drop this packet
266 if (!IsOutBufferEmpty())
267 return static_cast<int>(cb);
268
269 PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
270 AppendToOutBuffer(&pkt_len, kPacketLenSize);
271 AppendToOutBuffer(pv, cb);
272
273 int res = FlushOutBuffer();
274 if (res <= 0) {
275 // drop packet if we made no progress
276 ClearOutBuffer();
277 return res;
278 }
279
Qingsi Wang6e641e62018-04-11 20:14:17 -0700280 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
281 options.info_signaled_after_sent);
Qingsi Wang4ea53b32018-04-16 18:22:31 -0700282 CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
stefanc1aeaf02015-10-15 07:26:07 -0700283 SignalSentPacket(this, sent_packet);
284
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000285 // We claim to have sent the whole thing, even if we only sent partial
286 return static_cast<int>(cb);
287}
288
Yves Gerey665174f2018-06-19 15:03:05 +0200289void AsyncTCPSocket::ProcessInput(char* data, size_t* len) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000290 SocketAddress remote_addr(GetRemoteAddress());
291
292 while (true) {
293 if (*len < kPacketLenSize)
294 return;
295
296 PacketLength pkt_len = rtc::GetBE16(data);
297 if (*len < kPacketLenSize + pkt_len)
298 return;
299
300 SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
Niels Möller15ca5a92018-11-01 14:32:47 +0100301 TimeMicros());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302
303 *len -= kPacketLenSize + pkt_len;
304 if (*len > 0) {
305 memmove(data, data + kPacketLenSize + pkt_len, *len);
306 }
307 }
308}
309
Niels Möllerd30ece12021-10-19 10:11:02 +0200310AsyncTcpListenSocket::AsyncTcpListenSocket(std::unique_ptr<Socket> socket)
311 : socket_(std::move(socket)) {
312 RTC_DCHECK(socket_.get() != nullptr);
313 socket_->SignalReadEvent.connect(this, &AsyncTcpListenSocket::OnReadEvent);
314 if (socket_->Listen(kListenBacklog) < 0) {
315 RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
316 }
317}
318
319AsyncTcpListenSocket::State AsyncTcpListenSocket::GetState() const {
320 switch (socket_->GetState()) {
321 case Socket::CS_CLOSED:
322 return State::kClosed;
323 case Socket::CS_CONNECTING:
324 return State::kBound;
325 default:
326 RTC_NOTREACHED();
327 return State::kClosed;
328 }
329}
330
331SocketAddress AsyncTcpListenSocket::GetLocalAddress() const {
332 return socket_->GetLocalAddress();
333}
334
Niels Möllerd30ece12021-10-19 10:11:02 +0200335void AsyncTcpListenSocket::OnReadEvent(Socket* socket) {
336 RTC_DCHECK(socket_.get() == socket);
337
338 rtc::SocketAddress address;
339 rtc::Socket* new_socket = socket->Accept(&address);
340 if (!new_socket) {
341 // TODO(stefan): Do something better like forwarding the error
342 // to the user.
343 RTC_LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
344 return;
345 }
346
347 HandleIncomingConnection(new_socket);
348
349 // Prime a read event in case data is waiting.
350 new_socket->SignalReadEvent(new_socket);
351}
352
353void AsyncTcpListenSocket::HandleIncomingConnection(Socket* socket) {
354 SignalNewConnection(this, new AsyncTCPSocket(socket));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355}
356
357} // namespace rtc