blob: 35401d7c0abb30154aded7f582c80a6ac7d35f9b [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"
24#include "rtc_base/third_party/sigslot/sigslot.h"
Steve Anton10542f22019-01-11 17:11:0025#include "rtc_base/time_utils.h" // for TimeMillis
henrike@webrtc.orgf0488722014-05-13 18:00:2626
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 10:23:2135typedef uint16_t PacketLength;
henrike@webrtc.orgf0488722014-05-13 18:00:2636static const size_t kPacketLenSize = sizeof(PacketLength);
37
38static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
39
jbauch313afba2016-03-03 11:41:0540// 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:2645static const int kListenBacklog = 5;
46
47// Binds and connects |socket|
48AsyncSocket* AsyncTCPSocketBase::ConnectSocket(
49 rtc::AsyncSocket* socket,
50 const rtc::SocketAddress& bind_address,
51 const rtc::SocketAddress& remote_address) {
jbauch555604a2016-04-26 10:13:2252 std::unique_ptr<rtc::AsyncSocket> owned_socket(socket);
henrike@webrtc.orgf0488722014-05-13 18:00:2653 if (socket->Bind(bind_address) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2554 RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 22:06:4155 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2656 }
57 if (socket->Connect(remote_address) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2558 RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 22:06:4159 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2660 }
61 return owned_socket.release();
62}
63
Yves Gerey665174f2018-06-19 13:03:0564AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket,
65 bool listen,
henrike@webrtc.orgf0488722014-05-13 18:00:2666 size_t max_packet_size)
67 : socket_(socket),
68 listen_(listen),
jbauch313afba2016-03-03 11:41:0569 max_insize_(max_packet_size),
jbauch250fc652016-02-28 23:06:4070 max_outsize_(max_packet_size) {
jbauch3c165762016-02-26 17:31:3271 if (!listen_) {
72 // Listening sockets don't send/receive data, so they don't need buffers.
jbauch313afba2016-03-03 11:41:0573 inbuf_.EnsureCapacity(kMinimumRecvSize);
jbauch3c165762016-02-26 17:31:3274 }
henrike@webrtc.orgf0488722014-05-13 18:00:2675
deadbeef37f5ecf2017-02-27 22:06:4176 RTC_DCHECK(socket_.get() != nullptr);
Yves Gerey665174f2018-06-19 13:03:0577 socket_->SignalConnectEvent.connect(this,
78 &AsyncTCPSocketBase::OnConnectEvent);
henrike@webrtc.orgf0488722014-05-13 18:00:2679 socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
80 socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
81 socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
82
83 if (listen_) {
84 if (socket_->Listen(kListenBacklog) < 0) {
Mirko Bonadei675513b2017-11-09 10:09:2585 RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
henrike@webrtc.orgf0488722014-05-13 18:00:2686 }
87 }
88}
89
jbauch3c165762016-02-26 17:31:3290AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
henrike@webrtc.orgf0488722014-05-13 18:00:2691
92SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
93 return socket_->GetLocalAddress();
94}
95
96SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
97 return socket_->GetRemoteAddress();
98}
99
100int AsyncTCPSocketBase::Close() {
101 return socket_->Close();
102}
103
104AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
105 switch (socket_->GetState()) {
106 case Socket::CS_CLOSED:
107 return STATE_CLOSED;
108 case Socket::CS_CONNECTING:
109 if (listen_) {
110 return STATE_BOUND;
111 } else {
112 return STATE_CONNECTING;
113 }
114 case Socket::CS_CONNECTED:
115 return STATE_CONNECTED;
116 default:
jbauch3c165762016-02-26 17:31:32117 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26118 return STATE_CLOSED;
119 }
120}
121
122int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
123 return socket_->GetOption(opt, value);
124}
125
126int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
127 return socket_->SetOption(opt, value);
128}
129
130int AsyncTCPSocketBase::GetError() const {
131 return socket_->GetError();
132}
133
134void AsyncTCPSocketBase::SetError(int error) {
135 return socket_->SetError(error);
136}
137
Yves Gerey665174f2018-06-19 13:03:05138int AsyncTCPSocketBase::SendTo(const void* pv,
139 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26140 const SocketAddress& addr,
141 const rtc::PacketOptions& options) {
honghaizb19eba32015-08-03 17:23:31142 const SocketAddress& remote_address = GetRemoteAddress();
143 if (addr == remote_address)
henrike@webrtc.orgf0488722014-05-13 18:00:26144 return Send(pv, cb, options);
honghaizb19eba32015-08-03 17:23:31145 // Remote address may be empty if there is a sudden network change.
jbauch3c165762016-02-26 17:31:32146 RTC_DCHECK(remote_address.IsNil());
henrike@webrtc.orgf0488722014-05-13 18:00:26147 socket_->SetError(ENOTCONN);
148 return -1;
149}
150
henrike@webrtc.orgf0488722014-05-13 18:00:26151int AsyncTCPSocketBase::FlushOutBuffer() {
jbauch250fc652016-02-28 23:06:40152 RTC_DCHECK(!listen_);
Steve Anton3fa2b802020-01-31 18:31:53153 RTC_DCHECK_GT(outbuf_.size(), 0);
154 rtc::ArrayView<uint8_t> view = outbuf_;
155 int res;
156 while (view.size() > 0) {
157 res = socket_->Send(view.data(), view.size());
158 if (res <= 0) {
159 break;
160 }
161 if (static_cast<size_t>(res) > view.size()) {
162 RTC_NOTREACHED();
163 res = -1;
164 break;
165 }
166 view = view.subview(res);
henrike@webrtc.orgf0488722014-05-13 18:00:26167 }
Steve Anton3fa2b802020-01-31 18:31:53168 if (res > 0) {
169 // The output buffer may have been written out over multiple partial Send(),
170 // so reconstruct the total written length.
171 RTC_DCHECK_EQ(view.size(), 0);
172 res = outbuf_.size();
173 outbuf_.Clear();
174 } else {
175 // There was an error when calling Send(), so there will still be data left
176 // to send at a later point.
177 RTC_DCHECK_GT(view.size(), 0);
178 // In the special case of EWOULDBLOCK, signal that we had a partial write.
179 if (socket_->GetError() == EWOULDBLOCK) {
180 res = outbuf_.size() - view.size();
181 }
182 if (view.size() < outbuf_.size()) {
183 memmove(outbuf_.data(), view.data(), view.size());
184 outbuf_.SetSize(view.size());
185 }
henrike@webrtc.orgf0488722014-05-13 18:00:26186 }
henrike@webrtc.orgf0488722014-05-13 18:00:26187 return res;
188}
189
190void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
jbauch250fc652016-02-28 23:06:40191 RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
192 RTC_DCHECK(!listen_);
193 outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26194}
195
196void AsyncTCPSocketBase::OnConnectEvent(AsyncSocket* socket) {
197 SignalConnect(this);
198}
199
200void AsyncTCPSocketBase::OnReadEvent(AsyncSocket* socket) {
jbauch3c165762016-02-26 17:31:32201 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26202
203 if (listen_) {
204 rtc::SocketAddress address;
205 rtc::AsyncSocket* new_socket = socket->Accept(&address);
206 if (!new_socket) {
jbauch313afba2016-03-03 11:41:05207 // TODO(stefan): Do something better like forwarding the error
henrike@webrtc.orgf0488722014-05-13 18:00:26208 // to the user.
Mirko Bonadei675513b2017-11-09 10:09:25209 RTC_LOG(LS_ERROR) << "TCP accept failed with error "
210 << socket_->GetError();
henrike@webrtc.orgf0488722014-05-13 18:00:26211 return;
212 }
213
214 HandleIncomingConnection(new_socket);
215
216 // Prime a read event in case data is waiting.
217 new_socket->SignalReadEvent(new_socket);
218 } else {
jbauch313afba2016-03-03 11:41:05219 size_t total_recv = 0;
220 while (true) {
221 size_t free_size = inbuf_.capacity() - inbuf_.size();
222 if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
223 inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
224 free_size = inbuf_.capacity() - inbuf_.size();
henrike@webrtc.orgf0488722014-05-13 18:00:26225 }
jbauch313afba2016-03-03 11:41:05226
Stefan Holmer9131efd2016-05-23 16:19:26227 int len =
228 socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
jbauch313afba2016-03-03 11:41:05229 if (len < 0) {
230 // TODO(stefan): Do something better like forwarding the error to the
231 // user.
232 if (!socket_->IsBlocking()) {
Mirko Bonadei675513b2017-11-09 10:09:25233 RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
jbauch313afba2016-03-03 11:41:05234 }
235 break;
236 }
237
238 total_recv += len;
239 inbuf_.SetSize(inbuf_.size() + len);
240 if (!len || static_cast<size_t>(len) < free_size) {
241 break;
242 }
243 }
244
245 if (!total_recv) {
henrike@webrtc.orgf0488722014-05-13 18:00:26246 return;
247 }
248
jbauch313afba2016-03-03 11:41:05249 size_t size = inbuf_.size();
250 ProcessInput(inbuf_.data<char>(), &size);
henrike@webrtc.orgf0488722014-05-13 18:00:26251
jbauch313afba2016-03-03 11:41:05252 if (size > inbuf_.size()) {
Mirko Bonadei675513b2017-11-09 10:09:25253 RTC_LOG(LS_ERROR) << "input buffer overflow";
jbauch3c165762016-02-26 17:31:32254 RTC_NOTREACHED();
jbauch313afba2016-03-03 11:41:05255 inbuf_.Clear();
256 } else {
257 inbuf_.SetSize(size);
henrike@webrtc.orgf0488722014-05-13 18:00:26258 }
259 }
260}
261
262void AsyncTCPSocketBase::OnWriteEvent(AsyncSocket* socket) {
jbauch3c165762016-02-26 17:31:32263 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26264
jbauch250fc652016-02-28 23:06:40265 if (outbuf_.size() > 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26266 FlushOutBuffer();
267 }
268
jbauch250fc652016-02-28 23:06:40269 if (outbuf_.size() == 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26270 SignalReadyToSend(this);
271 }
272}
273
274void AsyncTCPSocketBase::OnCloseEvent(AsyncSocket* socket, int error) {
275 SignalClose(this, error);
276}
277
278// AsyncTCPSocket
279// Binds and connects |socket| and creates AsyncTCPSocket for
deadbeef37f5ecf2017-02-27 22:06:41280// it. Takes ownership of |socket|. Returns null if bind() or
henrike@webrtc.orgf0488722014-05-13 18:00:26281// connect() fail (|socket| is destroyed in that case).
Yves Gerey665174f2018-06-19 13:03:05282AsyncTCPSocket* AsyncTCPSocket::Create(AsyncSocket* socket,
283 const SocketAddress& bind_address,
284 const SocketAddress& remote_address) {
285 return new AsyncTCPSocket(
286 AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address),
287 false);
henrike@webrtc.orgf0488722014-05-13 18:00:26288}
289
290AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
Yves Gerey665174f2018-06-19 13:03:05291 : AsyncTCPSocketBase(socket, listen, kBufSize) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26292
Yves Gerey665174f2018-06-19 13:03:05293int AsyncTCPSocket::Send(const void* pv,
294 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26295 const rtc::PacketOptions& options) {
296 if (cb > kBufSize) {
297 SetError(EMSGSIZE);
298 return -1;
299 }
300
301 // If we are blocking on send, then silently drop this packet
302 if (!IsOutBufferEmpty())
303 return static_cast<int>(cb);
304
305 PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
306 AppendToOutBuffer(&pkt_len, kPacketLenSize);
307 AppendToOutBuffer(pv, cb);
308
309 int res = FlushOutBuffer();
310 if (res <= 0) {
311 // drop packet if we made no progress
312 ClearOutBuffer();
313 return res;
314 }
315
Qingsi Wang6e641e62018-04-12 03:14:17316 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
317 options.info_signaled_after_sent);
Qingsi Wang4ea53b32018-04-17 01:22:31318 CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
stefanc1aeaf02015-10-15 14:26:07319 SignalSentPacket(this, sent_packet);
320
henrike@webrtc.orgf0488722014-05-13 18:00:26321 // We claim to have sent the whole thing, even if we only sent partial
322 return static_cast<int>(cb);
323}
324
Yves Gerey665174f2018-06-19 13:03:05325void AsyncTCPSocket::ProcessInput(char* data, size_t* len) {
henrike@webrtc.orgf0488722014-05-13 18:00:26326 SocketAddress remote_addr(GetRemoteAddress());
327
328 while (true) {
329 if (*len < kPacketLenSize)
330 return;
331
332 PacketLength pkt_len = rtc::GetBE16(data);
333 if (*len < kPacketLenSize + pkt_len)
334 return;
335
336 SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
Niels Möller15ca5a92018-11-01 13:32:47337 TimeMicros());
henrike@webrtc.orgf0488722014-05-13 18:00:26338
339 *len -= kPacketLenSize + pkt_len;
340 if (*len > 0) {
341 memmove(data, data + kPacketLenSize + pkt_len, *len);
342 }
343 }
344}
345
346void AsyncTCPSocket::HandleIncomingConnection(AsyncSocket* socket) {
347 SignalNewConnection(this, new AsyncTCPSocket(socket, false));
348}
349
350} // namespace rtc