blob: 367c5b04e745734645c1f2e6c067dc5210e0a19e [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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 17:11:0011#include "rtc_base/async_tcp_socket.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2612
Yves Gerey3e707812018-11-28 15:47:4913#include <stdint.h>
henrike@webrtc.orgf0488722014-05-13 18:00:2614#include <string.h>
Jonas Olssona4d87372019-07-05 17:08:3315
jbauch313afba2016-03-03 11:41:0516#include <algorithm>
jbauch555604a2016-04-26 10:13:2217#include <memory>
jbauch313afba2016-03-03 11:41:0518
Steve Anton3fa2b802020-01-31 18:31:5319#include "api/array_view.h"
Steve Anton10542f22019-01-11 17:11:0020#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3121#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
Yves Gerey3e707812018-11-28 15:47:4923#include "rtc_base/network/sent_packet.h"
Steve Anton10542f22019-01-11 17:11:0024#include "rtc_base/time_utils.h" // for TimeMillis
henrike@webrtc.orgf0488722014-05-13 18:00:2625
26#if defined(WEBRTC_POSIX)
27#include <errno.h>
28#endif // WEBRTC_POSIX
29
30namespace rtc {
31
32static const size_t kMaxPacketSize = 64 * 1024;
33
Peter Boström0c4e06b2015-10-07 10:23:2134typedef uint16_t PacketLength;
henrike@webrtc.orgf0488722014-05-13 18:00:2635static const size_t kPacketLenSize = sizeof(PacketLength);
36
37static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
38
jbauch313afba2016-03-03 11:41:0539// The input buffer will be resized so that at least kMinimumRecvSize bytes can
40// be received (but it will not grow above the maximum size passed to the
41// constructor).
42static const size_t kMinimumRecvSize = 128;
43
henrike@webrtc.orgf0488722014-05-13 18:00:2644static const int kListenBacklog = 5;
45
Artem Titov96e3b992021-07-26 14:03:1446// Binds and connects `socket`
Niels Möllerd0b88792021-08-12 08:32:3047Socket* AsyncTCPSocketBase::ConnectSocket(
48 rtc::Socket* socket,
henrike@webrtc.orgf0488722014-05-13 18:00:2649 const rtc::SocketAddress& bind_address,
50 const rtc::SocketAddress& remote_address) {
Niels Möllerd0b88792021-08-12 08:32:3051 std::unique_ptr<rtc::Socket> owned_socket(socket);
henrike@webrtc.orgf0488722014-05-13 18:00:2652 if (socket->Bind(bind_address) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2553 RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 22:06:4154 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2655 }
56 if (socket->Connect(remote_address) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2557 RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 22:06:4158 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2659 }
60 return owned_socket.release();
61}
62
Jared Siskin802e8e52023-04-20 00:35:2863AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket, size_t max_packet_size)
henrike@webrtc.orgf0488722014-05-13 18:00:2664 : socket_(socket),
jbauch313afba2016-03-03 11:41:0565 max_insize_(max_packet_size),
jbauch250fc652016-02-28 23:06:4066 max_outsize_(max_packet_size) {
Niels Möllerd30ece12021-10-19 08:11:0267 inbuf_.EnsureCapacity(kMinimumRecvSize);
henrike@webrtc.orgf0488722014-05-13 18:00:2668
Yves Gerey665174f2018-06-19 13:03:0569 socket_->SignalConnectEvent.connect(this,
70 &AsyncTCPSocketBase::OnConnectEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:2671 socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
72 socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
73 socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:2674}
75
jbauch3c165762016-02-26 17:31:3276AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
henrike@webrtc.orgf0488722014-05-13 18:00:2677
78SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
79 return socket_->GetLocalAddress();
80}
81
82SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
83 return socket_->GetRemoteAddress();
84}
85
86int AsyncTCPSocketBase::Close() {
87 return socket_->Close();
88}
89
90AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
91 switch (socket_->GetState()) {
92 case Socket::CS_CLOSED:
93 return STATE_CLOSED;
94 case Socket::CS_CONNECTING:
Niels Möllerd30ece12021-10-19 08:11:0295 return STATE_CONNECTING;
henrike@webrtc.orgf0488722014-05-13 18:00:2696 case Socket::CS_CONNECTED:
97 return STATE_CONNECTED;
98 default:
Artem Titovd3251962021-11-15 15:57:0799 RTC_DCHECK_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26100 return STATE_CLOSED;
101 }
102}
103
104int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
105 return socket_->GetOption(opt, value);
106}
107
108int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
109 return socket_->SetOption(opt, value);
110}
111
112int AsyncTCPSocketBase::GetError() const {
113 return socket_->GetError();
114}
115
116void AsyncTCPSocketBase::SetError(int error) {
117 return socket_->SetError(error);
118}
119
Yves Gerey665174f2018-06-19 13:03:05120int AsyncTCPSocketBase::SendTo(const void* pv,
121 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26122 const SocketAddress& addr,
123 const rtc::PacketOptions& options) {
honghaizb19eba32015-08-03 17:23:31124 const SocketAddress& remote_address = GetRemoteAddress();
125 if (addr == remote_address)
henrike@webrtc.orgf0488722014-05-13 18:00:26126 return Send(pv, cb, options);
honghaizb19eba32015-08-03 17:23:31127 // Remote address may be empty if there is a sudden network change.
jbauch3c165762016-02-26 17:31:32128 RTC_DCHECK(remote_address.IsNil());
henrike@webrtc.orgf0488722014-05-13 18:00:26129 socket_->SetError(ENOTCONN);
130 return -1;
131}
132
henrike@webrtc.orgf0488722014-05-13 18:00:26133int AsyncTCPSocketBase::FlushOutBuffer() {
Steve Anton3fa2b802020-01-31 18:31:53134 RTC_DCHECK_GT(outbuf_.size(), 0);
135 rtc::ArrayView<uint8_t> view = outbuf_;
136 int res;
137 while (view.size() > 0) {
138 res = socket_->Send(view.data(), view.size());
139 if (res <= 0) {
140 break;
141 }
142 if (static_cast<size_t>(res) > view.size()) {
Artem Titovd3251962021-11-15 15:57:07143 RTC_DCHECK_NOTREACHED();
Steve Anton3fa2b802020-01-31 18:31:53144 res = -1;
145 break;
146 }
147 view = view.subview(res);
henrike@webrtc.orgf0488722014-05-13 18:00:26148 }
Steve Anton3fa2b802020-01-31 18:31:53149 if (res > 0) {
150 // The output buffer may have been written out over multiple partial Send(),
151 // so reconstruct the total written length.
152 RTC_DCHECK_EQ(view.size(), 0);
153 res = outbuf_.size();
154 outbuf_.Clear();
155 } else {
156 // There was an error when calling Send(), so there will still be data left
157 // to send at a later point.
158 RTC_DCHECK_GT(view.size(), 0);
159 // In the special case of EWOULDBLOCK, signal that we had a partial write.
160 if (socket_->GetError() == EWOULDBLOCK) {
161 res = outbuf_.size() - view.size();
162 }
163 if (view.size() < outbuf_.size()) {
164 memmove(outbuf_.data(), view.data(), view.size());
165 outbuf_.SetSize(view.size());
166 }
henrike@webrtc.orgf0488722014-05-13 18:00:26167 }
henrike@webrtc.orgf0488722014-05-13 18:00:26168 return res;
169}
170
171void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
jbauch250fc652016-02-28 23:06:40172 RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
jbauch250fc652016-02-28 23:06:40173 outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26174}
175
Niels Möllerd0b88792021-08-12 08:32:30176void AsyncTCPSocketBase::OnConnectEvent(Socket* socket) {
henrike@webrtc.orgf0488722014-05-13 18:00:26177 SignalConnect(this);
178}
179
Niels Möllerd0b88792021-08-12 08:32:30180void AsyncTCPSocketBase::OnReadEvent(Socket* socket) {
jbauch3c165762016-02-26 17:31:32181 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26182
Niels Möllerd30ece12021-10-19 08:11:02183 size_t total_recv = 0;
184 while (true) {
185 size_t free_size = inbuf_.capacity() - inbuf_.size();
186 if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
187 inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
188 free_size = inbuf_.capacity() - inbuf_.size();
henrike@webrtc.orgf0488722014-05-13 18:00:26189 }
190
Niels Möllerd30ece12021-10-19 08:11:02191 int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
192 if (len < 0) {
193 // TODO(stefan): Do something better like forwarding the error to the
194 // user.
195 if (!socket_->IsBlocking()) {
196 RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
197 }
198 break;
199 }
henrike@webrtc.orgf0488722014-05-13 18:00:26200
Niels Möllerd30ece12021-10-19 08:11:02201 total_recv += len;
202 inbuf_.SetSize(inbuf_.size() + len);
203 if (!len || static_cast<size_t>(len) < free_size) {
204 break;
205 }
206 }
207
208 if (!total_recv) {
209 return;
210 }
211
212 size_t size = inbuf_.size();
213 ProcessInput(inbuf_.data<char>(), &size);
214
215 if (size > inbuf_.size()) {
216 RTC_LOG(LS_ERROR) << "input buffer overflow";
Artem Titovd3251962021-11-15 15:57:07217 RTC_DCHECK_NOTREACHED();
Niels Möllerd30ece12021-10-19 08:11:02218 inbuf_.Clear();
henrike@webrtc.orgf0488722014-05-13 18:00:26219 } else {
Niels Möllerd30ece12021-10-19 08:11:02220 inbuf_.SetSize(size);
henrike@webrtc.orgf0488722014-05-13 18:00:26221 }
222}
223
Niels Möllerd0b88792021-08-12 08:32:30224void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) {
jbauch3c165762016-02-26 17:31:32225 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26226
jbauch250fc652016-02-28 23:06:40227 if (outbuf_.size() > 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26228 FlushOutBuffer();
229 }
230
jbauch250fc652016-02-28 23:06:40231 if (outbuf_.size() == 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26232 SignalReadyToSend(this);
233 }
234}
235
Niels Möllerd0b88792021-08-12 08:32:30236void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) {
Tomas Gunnarssonf15189d2022-04-13 09:03:52237 NotifyClosed(error);
henrike@webrtc.orgf0488722014-05-13 18:00:26238}
239
240// AsyncTCPSocket
Artem Titov96e3b992021-07-26 14:03:14241// Binds and connects `socket` and creates AsyncTCPSocket for
242// it. Takes ownership of `socket`. Returns null if bind() or
243// connect() fail (`socket` is destroyed in that case).
Niels Möllerd0b88792021-08-12 08:32:30244AsyncTCPSocket* AsyncTCPSocket::Create(Socket* socket,
Yves Gerey665174f2018-06-19 13:03:05245 const SocketAddress& bind_address,
246 const SocketAddress& remote_address) {
247 return new AsyncTCPSocket(
Niels Möllerd30ece12021-10-19 08:11:02248 AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address));
henrike@webrtc.orgf0488722014-05-13 18:00:26249}
250
Niels Möllerd30ece12021-10-19 08:11:02251AsyncTCPSocket::AsyncTCPSocket(Socket* socket)
252 : AsyncTCPSocketBase(socket, kBufSize) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26253
Yves Gerey665174f2018-06-19 13:03:05254int AsyncTCPSocket::Send(const void* pv,
255 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26256 const rtc::PacketOptions& options) {
257 if (cb > kBufSize) {
258 SetError(EMSGSIZE);
259 return -1;
260 }
261
262 // If we are blocking on send, then silently drop this packet
263 if (!IsOutBufferEmpty())
264 return static_cast<int>(cb);
265
266 PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
267 AppendToOutBuffer(&pkt_len, kPacketLenSize);
268 AppendToOutBuffer(pv, cb);
269
270 int res = FlushOutBuffer();
271 if (res <= 0) {
272 // drop packet if we made no progress
273 ClearOutBuffer();
274 return res;
275 }
276
Qingsi Wang6e641e62018-04-12 03:14:17277 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
278 options.info_signaled_after_sent);
Qingsi Wang4ea53b32018-04-17 01:22:31279 CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
stefanc1aeaf02015-10-15 14:26:07280 SignalSentPacket(this, sent_packet);
281
henrike@webrtc.orgf0488722014-05-13 18:00:26282 // We claim to have sent the whole thing, even if we only sent partial
283 return static_cast<int>(cb);
284}
285
Yves Gerey665174f2018-06-19 13:03:05286void AsyncTCPSocket::ProcessInput(char* data, size_t* len) {
henrike@webrtc.orgf0488722014-05-13 18:00:26287 SocketAddress remote_addr(GetRemoteAddress());
288
289 while (true) {
290 if (*len < kPacketLenSize)
291 return;
292
293 PacketLength pkt_len = rtc::GetBE16(data);
294 if (*len < kPacketLenSize + pkt_len)
295 return;
296
297 SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
Niels Möller15ca5a92018-11-01 13:32:47298 TimeMicros());
henrike@webrtc.orgf0488722014-05-13 18:00:26299
300 *len -= kPacketLenSize + pkt_len;
301 if (*len > 0) {
302 memmove(data, data + kPacketLenSize + pkt_len, *len);
303 }
304 }
305}
306
Niels Möllerd30ece12021-10-19 08:11:02307AsyncTcpListenSocket::AsyncTcpListenSocket(std::unique_ptr<Socket> socket)
308 : socket_(std::move(socket)) {
309 RTC_DCHECK(socket_.get() != nullptr);
310 socket_->SignalReadEvent.connect(this, &AsyncTcpListenSocket::OnReadEvent);
311 if (socket_->Listen(kListenBacklog) < 0) {
312 RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
313 }
314}
315
316AsyncTcpListenSocket::State AsyncTcpListenSocket::GetState() const {
317 switch (socket_->GetState()) {
318 case Socket::CS_CLOSED:
319 return State::kClosed;
320 case Socket::CS_CONNECTING:
321 return State::kBound;
322 default:
Artem Titovd3251962021-11-15 15:57:07323 RTC_DCHECK_NOTREACHED();
Niels Möllerd30ece12021-10-19 08:11:02324 return State::kClosed;
325 }
326}
327
328SocketAddress AsyncTcpListenSocket::GetLocalAddress() const {
329 return socket_->GetLocalAddress();
330}
331
Niels Möllerd30ece12021-10-19 08:11:02332void AsyncTcpListenSocket::OnReadEvent(Socket* socket) {
333 RTC_DCHECK(socket_.get() == socket);
334
335 rtc::SocketAddress address;
336 rtc::Socket* new_socket = socket->Accept(&address);
337 if (!new_socket) {
338 // TODO(stefan): Do something better like forwarding the error
339 // to the user.
340 RTC_LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
341 return;
342 }
343
344 HandleIncomingConnection(new_socket);
345
346 // Prime a read event in case data is waiting.
347 new_socket->SignalReadEvent(new_socket);
348}
349
350void AsyncTcpListenSocket::HandleIncomingConnection(Socket* socket) {
351 SignalNewConnection(this, new AsyncTCPSocket(socket));
henrike@webrtc.orgf0488722014-05-13 18:00:26352}
353
354} // namespace rtc