blob: 2924340c1698453f83b6eed9faed42e798d2b96f [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>
Per K357947f2023-11-27 12:03:5217#include <cstddef>
18#include <cstdint>
jbauch555604a2016-04-26 10:13:2219#include <memory>
jbauch313afba2016-03-03 11:41:0520
Steve Anton3fa2b802020-01-31 18:31:5321#include "api/array_view.h"
Steve Anton10542f22019-01-11 17:11:0022#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3123#include "rtc_base/checks.h"
24#include "rtc_base/logging.h"
Yves Gerey3e707812018-11-28 15:47:4925#include "rtc_base/network/sent_packet.h"
Steve Anton10542f22019-01-11 17:11:0026#include "rtc_base/time_utils.h" // for TimeMillis
henrike@webrtc.orgf0488722014-05-13 18:00:2627
28#if defined(WEBRTC_POSIX)
29#include <errno.h>
30#endif // WEBRTC_POSIX
31
32namespace rtc {
33
34static const size_t kMaxPacketSize = 64 * 1024;
35
Peter Boström0c4e06b2015-10-07 10:23:2136typedef uint16_t PacketLength;
henrike@webrtc.orgf0488722014-05-13 18:00:2637static const size_t kPacketLenSize = sizeof(PacketLength);
38
39static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
40
jbauch313afba2016-03-03 11:41:0541// The input buffer will be resized so that at least kMinimumRecvSize bytes can
42// be received (but it will not grow above the maximum size passed to the
43// constructor).
44static const size_t kMinimumRecvSize = 128;
45
henrike@webrtc.orgf0488722014-05-13 18:00:2646static const int kListenBacklog = 5;
47
Artem Titov96e3b992021-07-26 14:03:1448// Binds and connects `socket`
Niels Möllerd0b88792021-08-12 08:32:3049Socket* AsyncTCPSocketBase::ConnectSocket(
50 rtc::Socket* socket,
henrike@webrtc.orgf0488722014-05-13 18:00:2651 const rtc::SocketAddress& bind_address,
52 const rtc::SocketAddress& remote_address) {
Niels Möllerd0b88792021-08-12 08:32:3053 std::unique_ptr<rtc::Socket> owned_socket(socket);
henrike@webrtc.orgf0488722014-05-13 18:00:2654 if (socket->Bind(bind_address) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2555 RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 22:06:4156 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2657 }
58 if (socket->Connect(remote_address) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2559 RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 22:06:4160 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2661 }
62 return owned_socket.release();
63}
64
Jared Siskin802e8e52023-04-20 00:35:2865AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket, size_t max_packet_size)
henrike@webrtc.orgf0488722014-05-13 18:00:2666 : socket_(socket),
jbauch313afba2016-03-03 11:41:0567 max_insize_(max_packet_size),
jbauch250fc652016-02-28 23:06:4068 max_outsize_(max_packet_size) {
Niels Möllerd30ece12021-10-19 08:11:0269 inbuf_.EnsureCapacity(kMinimumRecvSize);
henrike@webrtc.orgf0488722014-05-13 18:00:2670
Yves Gerey665174f2018-06-19 13:03:0571 socket_->SignalConnectEvent.connect(this,
72 &AsyncTCPSocketBase::OnConnectEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:2673 socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
74 socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
75 socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:2676}
77
jbauch3c165762016-02-26 17:31:3278AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
henrike@webrtc.orgf0488722014-05-13 18:00:2679
80SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
81 return socket_->GetLocalAddress();
82}
83
84SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
85 return socket_->GetRemoteAddress();
86}
87
88int AsyncTCPSocketBase::Close() {
89 return socket_->Close();
90}
91
92AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
93 switch (socket_->GetState()) {
94 case Socket::CS_CLOSED:
95 return STATE_CLOSED;
96 case Socket::CS_CONNECTING:
Niels Möllerd30ece12021-10-19 08:11:0297 return STATE_CONNECTING;
henrike@webrtc.orgf0488722014-05-13 18:00:2698 case Socket::CS_CONNECTED:
99 return STATE_CONNECTED;
100 default:
Artem Titovd3251962021-11-15 15:57:07101 RTC_DCHECK_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26102 return STATE_CLOSED;
103 }
104}
105
106int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
107 return socket_->GetOption(opt, value);
108}
109
110int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
111 return socket_->SetOption(opt, value);
112}
113
114int AsyncTCPSocketBase::GetError() const {
115 return socket_->GetError();
116}
117
118void AsyncTCPSocketBase::SetError(int error) {
119 return socket_->SetError(error);
120}
121
Yves Gerey665174f2018-06-19 13:03:05122int AsyncTCPSocketBase::SendTo(const void* pv,
123 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26124 const SocketAddress& addr,
125 const rtc::PacketOptions& options) {
honghaizb19eba32015-08-03 17:23:31126 const SocketAddress& remote_address = GetRemoteAddress();
127 if (addr == remote_address)
henrike@webrtc.orgf0488722014-05-13 18:00:26128 return Send(pv, cb, options);
honghaizb19eba32015-08-03 17:23:31129 // Remote address may be empty if there is a sudden network change.
jbauch3c165762016-02-26 17:31:32130 RTC_DCHECK(remote_address.IsNil());
henrike@webrtc.orgf0488722014-05-13 18:00:26131 socket_->SetError(ENOTCONN);
132 return -1;
133}
134
henrike@webrtc.orgf0488722014-05-13 18:00:26135int AsyncTCPSocketBase::FlushOutBuffer() {
Steve Anton3fa2b802020-01-31 18:31:53136 RTC_DCHECK_GT(outbuf_.size(), 0);
137 rtc::ArrayView<uint8_t> view = outbuf_;
138 int res;
139 while (view.size() > 0) {
140 res = socket_->Send(view.data(), view.size());
141 if (res <= 0) {
142 break;
143 }
144 if (static_cast<size_t>(res) > view.size()) {
Artem Titovd3251962021-11-15 15:57:07145 RTC_DCHECK_NOTREACHED();
Steve Anton3fa2b802020-01-31 18:31:53146 res = -1;
147 break;
148 }
149 view = view.subview(res);
henrike@webrtc.orgf0488722014-05-13 18:00:26150 }
Steve Anton3fa2b802020-01-31 18:31:53151 if (res > 0) {
152 // The output buffer may have been written out over multiple partial Send(),
153 // so reconstruct the total written length.
154 RTC_DCHECK_EQ(view.size(), 0);
155 res = outbuf_.size();
156 outbuf_.Clear();
157 } else {
158 // There was an error when calling Send(), so there will still be data left
159 // to send at a later point.
160 RTC_DCHECK_GT(view.size(), 0);
161 // In the special case of EWOULDBLOCK, signal that we had a partial write.
162 if (socket_->GetError() == EWOULDBLOCK) {
163 res = outbuf_.size() - view.size();
164 }
165 if (view.size() < outbuf_.size()) {
166 memmove(outbuf_.data(), view.data(), view.size());
167 outbuf_.SetSize(view.size());
168 }
henrike@webrtc.orgf0488722014-05-13 18:00:26169 }
henrike@webrtc.orgf0488722014-05-13 18:00:26170 return res;
171}
172
173void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
jbauch250fc652016-02-28 23:06:40174 RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
jbauch250fc652016-02-28 23:06:40175 outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26176}
177
Niels Möllerd0b88792021-08-12 08:32:30178void AsyncTCPSocketBase::OnConnectEvent(Socket* socket) {
henrike@webrtc.orgf0488722014-05-13 18:00:26179 SignalConnect(this);
180}
181
Niels Möllerd0b88792021-08-12 08:32:30182void AsyncTCPSocketBase::OnReadEvent(Socket* socket) {
jbauch3c165762016-02-26 17:31:32183 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26184
Niels Möllerd30ece12021-10-19 08:11:02185 size_t total_recv = 0;
186 while (true) {
187 size_t free_size = inbuf_.capacity() - inbuf_.size();
188 if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
189 inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
190 free_size = inbuf_.capacity() - inbuf_.size();
henrike@webrtc.orgf0488722014-05-13 18:00:26191 }
192
Niels Möllerd30ece12021-10-19 08:11:02193 int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
194 if (len < 0) {
195 // TODO(stefan): Do something better like forwarding the error to the
196 // user.
197 if (!socket_->IsBlocking()) {
198 RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
199 }
200 break;
201 }
henrike@webrtc.orgf0488722014-05-13 18:00:26202
Niels Möllerd30ece12021-10-19 08:11:02203 total_recv += len;
204 inbuf_.SetSize(inbuf_.size() + len);
205 if (!len || static_cast<size_t>(len) < free_size) {
206 break;
207 }
208 }
209
210 if (!total_recv) {
211 return;
212 }
213
Per K357947f2023-11-27 12:03:52214 size_t processed = ProcessInput(inbuf_);
215 size_t bytes_remaining = inbuf_.size() - processed;
216 if (processed > inbuf_.size()) {
Niels Möllerd30ece12021-10-19 08:11:02217 RTC_LOG(LS_ERROR) << "input buffer overflow";
Artem Titovd3251962021-11-15 15:57:07218 RTC_DCHECK_NOTREACHED();
Niels Möllerd30ece12021-10-19 08:11:02219 inbuf_.Clear();
henrike@webrtc.orgf0488722014-05-13 18:00:26220 } else {
Per K357947f2023-11-27 12:03:52221 if (bytes_remaining > 0) {
222 memmove(inbuf_.data(), inbuf_.data() + processed, bytes_remaining);
223 }
224 inbuf_.SetSize(bytes_remaining);
henrike@webrtc.orgf0488722014-05-13 18:00:26225 }
226}
227
Niels Möllerd0b88792021-08-12 08:32:30228void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) {
jbauch3c165762016-02-26 17:31:32229 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26230
jbauch250fc652016-02-28 23:06:40231 if (outbuf_.size() > 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26232 FlushOutBuffer();
233 }
234
jbauch250fc652016-02-28 23:06:40235 if (outbuf_.size() == 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26236 SignalReadyToSend(this);
237 }
238}
239
Niels Möllerd0b88792021-08-12 08:32:30240void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) {
Tomas Gunnarssonf15189d2022-04-13 09:03:52241 NotifyClosed(error);
henrike@webrtc.orgf0488722014-05-13 18:00:26242}
243
244// AsyncTCPSocket
Artem Titov96e3b992021-07-26 14:03:14245// Binds and connects `socket` and creates AsyncTCPSocket for
246// it. Takes ownership of `socket`. Returns null if bind() or
247// connect() fail (`socket` is destroyed in that case).
Niels Möllerd0b88792021-08-12 08:32:30248AsyncTCPSocket* AsyncTCPSocket::Create(Socket* socket,
Yves Gerey665174f2018-06-19 13:03:05249 const SocketAddress& bind_address,
250 const SocketAddress& remote_address) {
251 return new AsyncTCPSocket(
Niels Möllerd30ece12021-10-19 08:11:02252 AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address));
henrike@webrtc.orgf0488722014-05-13 18:00:26253}
254
Niels Möllerd30ece12021-10-19 08:11:02255AsyncTCPSocket::AsyncTCPSocket(Socket* socket)
256 : AsyncTCPSocketBase(socket, kBufSize) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26257
Yves Gerey665174f2018-06-19 13:03:05258int AsyncTCPSocket::Send(const void* pv,
259 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26260 const rtc::PacketOptions& options) {
261 if (cb > kBufSize) {
262 SetError(EMSGSIZE);
263 return -1;
264 }
265
266 // If we are blocking on send, then silently drop this packet
267 if (!IsOutBufferEmpty())
268 return static_cast<int>(cb);
269
270 PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
271 AppendToOutBuffer(&pkt_len, kPacketLenSize);
272 AppendToOutBuffer(pv, cb);
273
274 int res = FlushOutBuffer();
275 if (res <= 0) {
276 // drop packet if we made no progress
277 ClearOutBuffer();
278 return res;
279 }
280
Qingsi Wang6e641e62018-04-12 03:14:17281 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
282 options.info_signaled_after_sent);
Qingsi Wang4ea53b32018-04-17 01:22:31283 CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
stefanc1aeaf02015-10-15 14:26:07284 SignalSentPacket(this, sent_packet);
285
henrike@webrtc.orgf0488722014-05-13 18:00:26286 // We claim to have sent the whole thing, even if we only sent partial
287 return static_cast<int>(cb);
288}
289
Per K357947f2023-11-27 12:03:52290size_t AsyncTCPSocket::ProcessInput(rtc::ArrayView<const uint8_t> data) {
henrike@webrtc.orgf0488722014-05-13 18:00:26291 SocketAddress remote_addr(GetRemoteAddress());
292
Per K357947f2023-11-27 12:03:52293 size_t processed_bytes = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26294 while (true) {
Per K357947f2023-11-27 12:03:52295 size_t bytes_left = data.size() - processed_bytes;
296 if (bytes_left < kPacketLenSize)
297 return processed_bytes;
henrike@webrtc.orgf0488722014-05-13 18:00:26298
Per K357947f2023-11-27 12:03:52299 PacketLength pkt_len = rtc::GetBE16(data.data() + processed_bytes);
300 if (bytes_left < kPacketLenSize + pkt_len)
301 return processed_bytes;
henrike@webrtc.orgf0488722014-05-13 18:00:26302
Per K357947f2023-11-27 12:03:52303 rtc::ReceivedPacket received_packet(
304 data.subview(processed_bytes + kPacketLenSize, pkt_len), remote_addr,
305 webrtc::Timestamp::Micros(rtc::TimeMicros()));
306 NotifyPacketReceived(received_packet);
307 processed_bytes += kPacketLenSize + pkt_len;
henrike@webrtc.orgf0488722014-05-13 18:00:26308 }
309}
310
Niels Möllerd30ece12021-10-19 08:11:02311AsyncTcpListenSocket::AsyncTcpListenSocket(std::unique_ptr<Socket> socket)
312 : socket_(std::move(socket)) {
313 RTC_DCHECK(socket_.get() != nullptr);
314 socket_->SignalReadEvent.connect(this, &AsyncTcpListenSocket::OnReadEvent);
315 if (socket_->Listen(kListenBacklog) < 0) {
316 RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
317 }
318}
319
320AsyncTcpListenSocket::State AsyncTcpListenSocket::GetState() const {
321 switch (socket_->GetState()) {
322 case Socket::CS_CLOSED:
323 return State::kClosed;
324 case Socket::CS_CONNECTING:
325 return State::kBound;
326 default:
Artem Titovd3251962021-11-15 15:57:07327 RTC_DCHECK_NOTREACHED();
Niels Möllerd30ece12021-10-19 08:11:02328 return State::kClosed;
329 }
330}
331
332SocketAddress AsyncTcpListenSocket::GetLocalAddress() const {
333 return socket_->GetLocalAddress();
334}
335
Niels Möllerd30ece12021-10-19 08:11:02336void AsyncTcpListenSocket::OnReadEvent(Socket* socket) {
337 RTC_DCHECK(socket_.get() == socket);
338
339 rtc::SocketAddress address;
340 rtc::Socket* new_socket = socket->Accept(&address);
341 if (!new_socket) {
342 // TODO(stefan): Do something better like forwarding the error
343 // to the user.
344 RTC_LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
345 return;
346 }
347
348 HandleIncomingConnection(new_socket);
349
350 // Prime a read event in case data is waiting.
351 new_socket->SignalReadEvent(new_socket);
352}
353
354void AsyncTcpListenSocket::HandleIncomingConnection(Socket* socket) {
355 SignalNewConnection(this, new AsyncTCPSocket(socket));
henrike@webrtc.orgf0488722014-05-13 18:00:26356}
357
358} // namespace rtc