blob: 3d68a2a46a6c637a8ed2fa7a2fbd9cb3e5ccf7dd [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/asynctcpsocket.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
13#include <string.h>
14
jbauch313afba2016-03-03 03:41:05 -080015#include <algorithm>
jbauch555604a2016-04-26 03:13:22 -070016#include <memory>
jbauch313afba2016-03-03 03:41:05 -080017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/byteorder.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000021
22#if defined(WEBRTC_POSIX)
23#include <errno.h>
24#endif // WEBRTC_POSIX
25
26namespace rtc {
27
28static const size_t kMaxPacketSize = 64 * 1024;
29
Peter Boström0c4e06b2015-10-07 12:23:21 +020030typedef uint16_t PacketLength;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000031static const size_t kPacketLenSize = sizeof(PacketLength);
32
33static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
34
jbauch313afba2016-03-03 03:41:05 -080035// The input buffer will be resized so that at least kMinimumRecvSize bytes can
36// be received (but it will not grow above the maximum size passed to the
37// constructor).
38static const size_t kMinimumRecvSize = 128;
39
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040static const int kListenBacklog = 5;
41
42// Binds and connects |socket|
43AsyncSocket* AsyncTCPSocketBase::ConnectSocket(
44 rtc::AsyncSocket* socket,
45 const rtc::SocketAddress& bind_address,
46 const rtc::SocketAddress& remote_address) {
jbauch555604a2016-04-26 03:13:22 -070047 std::unique_ptr<rtc::AsyncSocket> owned_socket(socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048 if (socket->Bind(bind_address) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010049 RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 14:06:41 -080050 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000051 }
52 if (socket->Connect(remote_address) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010053 RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
deadbeef37f5ecf2017-02-27 14:06:41 -080054 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055 }
56 return owned_socket.release();
57}
58
Yves Gerey665174f2018-06-19 15:03:05 +020059AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket,
60 bool listen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000061 size_t max_packet_size)
62 : socket_(socket),
63 listen_(listen),
jbauch313afba2016-03-03 03:41:05 -080064 max_insize_(max_packet_size),
jbauch250fc652016-02-28 15:06:40 -080065 max_outsize_(max_packet_size) {
jbauch3c165762016-02-26 09:31:32 -080066 if (!listen_) {
67 // Listening sockets don't send/receive data, so they don't need buffers.
jbauch313afba2016-03-03 03:41:05 -080068 inbuf_.EnsureCapacity(kMinimumRecvSize);
jbauch3c165762016-02-26 09:31:32 -080069 }
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);
77
78 if (listen_) {
79 if (socket_->Listen(kListenBacklog) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010080 RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081 }
82 }
83}
84
jbauch3c165762016-02-26 09:31:32 -080085AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000086
87SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
88 return socket_->GetLocalAddress();
89}
90
91SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
92 return socket_->GetRemoteAddress();
93}
94
95int AsyncTCPSocketBase::Close() {
96 return socket_->Close();
97}
98
99AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
100 switch (socket_->GetState()) {
101 case Socket::CS_CLOSED:
102 return STATE_CLOSED;
103 case Socket::CS_CONNECTING:
104 if (listen_) {
105 return STATE_BOUND;
106 } else {
107 return STATE_CONNECTING;
108 }
109 case Socket::CS_CONNECTED:
110 return STATE_CONNECTED;
111 default:
jbauch3c165762016-02-26 09:31:32 -0800112 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000113 return STATE_CLOSED;
114 }
115}
116
117int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
118 return socket_->GetOption(opt, value);
119}
120
121int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
122 return socket_->SetOption(opt, value);
123}
124
125int AsyncTCPSocketBase::GetError() const {
126 return socket_->GetError();
127}
128
129void AsyncTCPSocketBase::SetError(int error) {
130 return socket_->SetError(error);
131}
132
Yves Gerey665174f2018-06-19 15:03:05 +0200133int AsyncTCPSocketBase::SendTo(const void* pv,
134 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000135 const SocketAddress& addr,
136 const rtc::PacketOptions& options) {
honghaizb19eba32015-08-03 10:23:31 -0700137 const SocketAddress& remote_address = GetRemoteAddress();
138 if (addr == remote_address)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000139 return Send(pv, cb, options);
honghaizb19eba32015-08-03 10:23:31 -0700140 // Remote address may be empty if there is a sudden network change.
jbauch3c165762016-02-26 09:31:32 -0800141 RTC_DCHECK(remote_address.IsNil());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 socket_->SetError(ENOTCONN);
143 return -1;
144}
145
Yves Gerey665174f2018-06-19 15:03:05 +0200146int AsyncTCPSocketBase::SendRaw(const void* pv, size_t cb) {
jbauch250fc652016-02-28 15:06:40 -0800147 if (outbuf_.size() + cb > max_outsize_) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 socket_->SetError(EMSGSIZE);
149 return -1;
150 }
151
jbauch250fc652016-02-28 15:06:40 -0800152 RTC_DCHECK(!listen_);
153 outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154
155 return FlushOutBuffer();
156}
157
158int AsyncTCPSocketBase::FlushOutBuffer() {
jbauch250fc652016-02-28 15:06:40 -0800159 RTC_DCHECK(!listen_);
160 int res = socket_->Send(outbuf_.data(), outbuf_.size());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161 if (res <= 0) {
162 return res;
163 }
jbauch250fc652016-02-28 15:06:40 -0800164 if (static_cast<size_t>(res) > outbuf_.size()) {
jbauch3c165762016-02-26 09:31:32 -0800165 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000166 return -1;
167 }
jbauch250fc652016-02-28 15:06:40 -0800168 size_t new_size = outbuf_.size() - res;
169 if (new_size > 0) {
170 memmove(outbuf_.data(), outbuf_.data() + res, new_size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000171 }
jbauch250fc652016-02-28 15:06:40 -0800172 outbuf_.SetSize(new_size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000173 return res;
174}
175
176void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
jbauch250fc652016-02-28 15:06:40 -0800177 RTC_DCHECK(outbuf_.size() + cb <= max_outsize_);
178 RTC_DCHECK(!listen_);
179 outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000180}
181
182void AsyncTCPSocketBase::OnConnectEvent(AsyncSocket* socket) {
183 SignalConnect(this);
184}
185
186void AsyncTCPSocketBase::OnReadEvent(AsyncSocket* socket) {
jbauch3c165762016-02-26 09:31:32 -0800187 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188
189 if (listen_) {
190 rtc::SocketAddress address;
191 rtc::AsyncSocket* new_socket = socket->Accept(&address);
192 if (!new_socket) {
jbauch313afba2016-03-03 03:41:05 -0800193 // TODO(stefan): Do something better like forwarding the error
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000194 // to the user.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100195 RTC_LOG(LS_ERROR) << "TCP accept failed with error "
196 << socket_->GetError();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000197 return;
198 }
199
200 HandleIncomingConnection(new_socket);
201
202 // Prime a read event in case data is waiting.
203 new_socket->SignalReadEvent(new_socket);
204 } else {
jbauch313afba2016-03-03 03:41:05 -0800205 size_t total_recv = 0;
206 while (true) {
207 size_t free_size = inbuf_.capacity() - inbuf_.size();
208 if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
209 inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
210 free_size = inbuf_.capacity() - inbuf_.size();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211 }
jbauch313afba2016-03-03 03:41:05 -0800212
Stefan Holmer9131efd2016-05-23 18:19:26 +0200213 int len =
214 socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr);
jbauch313afba2016-03-03 03:41:05 -0800215 if (len < 0) {
216 // TODO(stefan): Do something better like forwarding the error to the
217 // user.
218 if (!socket_->IsBlocking()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100219 RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
jbauch313afba2016-03-03 03:41:05 -0800220 }
221 break;
222 }
223
224 total_recv += len;
225 inbuf_.SetSize(inbuf_.size() + len);
226 if (!len || static_cast<size_t>(len) < free_size) {
227 break;
228 }
229 }
230
231 if (!total_recv) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000232 return;
233 }
234
jbauch313afba2016-03-03 03:41:05 -0800235 size_t size = inbuf_.size();
236 ProcessInput(inbuf_.data<char>(), &size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237
jbauch313afba2016-03-03 03:41:05 -0800238 if (size > inbuf_.size()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100239 RTC_LOG(LS_ERROR) << "input buffer overflow";
jbauch3c165762016-02-26 09:31:32 -0800240 RTC_NOTREACHED();
jbauch313afba2016-03-03 03:41:05 -0800241 inbuf_.Clear();
242 } else {
243 inbuf_.SetSize(size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000244 }
245 }
246}
247
248void AsyncTCPSocketBase::OnWriteEvent(AsyncSocket* socket) {
jbauch3c165762016-02-26 09:31:32 -0800249 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000250
jbauch250fc652016-02-28 15:06:40 -0800251 if (outbuf_.size() > 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252 FlushOutBuffer();
253 }
254
jbauch250fc652016-02-28 15:06:40 -0800255 if (outbuf_.size() == 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000256 SignalReadyToSend(this);
257 }
258}
259
260void AsyncTCPSocketBase::OnCloseEvent(AsyncSocket* socket, int error) {
261 SignalClose(this, error);
262}
263
264// AsyncTCPSocket
265// Binds and connects |socket| and creates AsyncTCPSocket for
deadbeef37f5ecf2017-02-27 14:06:41 -0800266// it. Takes ownership of |socket|. Returns null if bind() or
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000267// connect() fail (|socket| is destroyed in that case).
Yves Gerey665174f2018-06-19 15:03:05 +0200268AsyncTCPSocket* AsyncTCPSocket::Create(AsyncSocket* socket,
269 const SocketAddress& bind_address,
270 const SocketAddress& remote_address) {
271 return new AsyncTCPSocket(
272 AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address),
273 false);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274}
275
276AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
Yves Gerey665174f2018-06-19 15:03:05 +0200277 : AsyncTCPSocketBase(socket, listen, kBufSize) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000278
Yves Gerey665174f2018-06-19 15:03:05 +0200279int AsyncTCPSocket::Send(const void* pv,
280 size_t cb,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000281 const rtc::PacketOptions& options) {
282 if (cb > kBufSize) {
283 SetError(EMSGSIZE);
284 return -1;
285 }
286
287 // If we are blocking on send, then silently drop this packet
288 if (!IsOutBufferEmpty())
289 return static_cast<int>(cb);
290
291 PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
292 AppendToOutBuffer(&pkt_len, kPacketLenSize);
293 AppendToOutBuffer(pv, cb);
294
295 int res = FlushOutBuffer();
296 if (res <= 0) {
297 // drop packet if we made no progress
298 ClearOutBuffer();
299 return res;
300 }
301
Qingsi Wang6e641e62018-04-11 20:14:17 -0700302 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
303 options.info_signaled_after_sent);
Qingsi Wang4ea53b32018-04-16 18:22:31 -0700304 CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info);
stefanc1aeaf02015-10-15 07:26:07 -0700305 SignalSentPacket(this, sent_packet);
306
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000307 // We claim to have sent the whole thing, even if we only sent partial
308 return static_cast<int>(cb);
309}
310
Yves Gerey665174f2018-06-19 15:03:05 +0200311void AsyncTCPSocket::ProcessInput(char* data, size_t* len) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312 SocketAddress remote_addr(GetRemoteAddress());
313
314 while (true) {
315 if (*len < kPacketLenSize)
316 return;
317
318 PacketLength pkt_len = rtc::GetBE16(data);
319 if (*len < kPacketLenSize + pkt_len)
320 return;
321
322 SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
323 CreatePacketTime(0));
324
325 *len -= kPacketLenSize + pkt_len;
326 if (*len > 0) {
327 memmove(data, data + kPacketLenSize + pkt_len, *len);
328 }
329 }
330}
331
332void AsyncTCPSocket::HandleIncomingConnection(AsyncSocket* socket) {
333 SignalNewConnection(this, new AsyncTCPSocket(socket, false));
334}
335
336} // namespace rtc