blob: 7ec6dc8bc284053bab81782c0c7d235504c57f2f [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
11#include "webrtc/base/asynctcpsocket.h"
12
13#include <string.h>
14
15#include "webrtc/base/byteorder.h"
jbauch3c165762016-02-26 09:31:32 -080016#include "webrtc/base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017#include "webrtc/base/common.h"
18#include "webrtc/base/logging.h"
19
20#if defined(WEBRTC_POSIX)
21#include <errno.h>
22#endif // WEBRTC_POSIX
23
24namespace rtc {
25
26static const size_t kMaxPacketSize = 64 * 1024;
27
Peter Boström0c4e06b2015-10-07 12:23:21 +020028typedef uint16_t PacketLength;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029static const size_t kPacketLenSize = sizeof(PacketLength);
30
31static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
32
33static const int kListenBacklog = 5;
34
35// Binds and connects |socket|
36AsyncSocket* AsyncTCPSocketBase::ConnectSocket(
37 rtc::AsyncSocket* socket,
38 const rtc::SocketAddress& bind_address,
39 const rtc::SocketAddress& remote_address) {
40 rtc::scoped_ptr<rtc::AsyncSocket> owned_socket(socket);
41 if (socket->Bind(bind_address) < 0) {
42 LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
43 return NULL;
44 }
45 if (socket->Connect(remote_address) < 0) {
46 LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
47 return NULL;
48 }
49 return owned_socket.release();
50}
51
52AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket, bool listen,
53 size_t max_packet_size)
54 : socket_(socket),
55 listen_(listen),
56 insize_(max_packet_size),
57 inpos_(0),
58 outsize_(max_packet_size),
59 outpos_(0) {
jbauch3c165762016-02-26 09:31:32 -080060 if (!listen_) {
61 // Listening sockets don't send/receive data, so they don't need buffers.
62 inbuf_.reset(new char[insize_]);
63 outbuf_.reset(new char[outsize_]);
64 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065
jbauch3c165762016-02-26 09:31:32 -080066 RTC_DCHECK(socket_.get() != NULL);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 socket_->SignalConnectEvent.connect(
68 this, &AsyncTCPSocketBase::OnConnectEvent);
69 socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
70 socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
71 socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
72
73 if (listen_) {
74 if (socket_->Listen(kListenBacklog) < 0) {
75 LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
76 }
77 }
78}
79
jbauch3c165762016-02-26 09:31:32 -080080AsyncTCPSocketBase::~AsyncTCPSocketBase() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081
82SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
83 return socket_->GetLocalAddress();
84}
85
86SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
87 return socket_->GetRemoteAddress();
88}
89
90int AsyncTCPSocketBase::Close() {
91 return socket_->Close();
92}
93
94AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
95 switch (socket_->GetState()) {
96 case Socket::CS_CLOSED:
97 return STATE_CLOSED;
98 case Socket::CS_CONNECTING:
99 if (listen_) {
100 return STATE_BOUND;
101 } else {
102 return STATE_CONNECTING;
103 }
104 case Socket::CS_CONNECTED:
105 return STATE_CONNECTED;
106 default:
jbauch3c165762016-02-26 09:31:32 -0800107 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108 return STATE_CLOSED;
109 }
110}
111
112int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
113 return socket_->GetOption(opt, value);
114}
115
116int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
117 return socket_->SetOption(opt, value);
118}
119
120int AsyncTCPSocketBase::GetError() const {
121 return socket_->GetError();
122}
123
124void AsyncTCPSocketBase::SetError(int error) {
125 return socket_->SetError(error);
126}
127
128int AsyncTCPSocketBase::SendTo(const void *pv, size_t cb,
129 const SocketAddress& addr,
130 const rtc::PacketOptions& options) {
honghaizb19eba32015-08-03 10:23:31 -0700131 const SocketAddress& remote_address = GetRemoteAddress();
132 if (addr == remote_address)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000133 return Send(pv, cb, options);
honghaizb19eba32015-08-03 10:23:31 -0700134 // Remote address may be empty if there is a sudden network change.
jbauch3c165762016-02-26 09:31:32 -0800135 RTC_DCHECK(remote_address.IsNil());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000136 socket_->SetError(ENOTCONN);
137 return -1;
138}
139
140int AsyncTCPSocketBase::SendRaw(const void * pv, size_t cb) {
141 if (outpos_ + cb > outsize_) {
142 socket_->SetError(EMSGSIZE);
143 return -1;
144 }
145
jbauch3c165762016-02-26 09:31:32 -0800146 RTC_DCHECK(outbuf_.get());
147 memcpy(outbuf_.get() + outpos_, pv, cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 outpos_ += cb;
149
150 return FlushOutBuffer();
151}
152
153int AsyncTCPSocketBase::FlushOutBuffer() {
jbauch3c165762016-02-26 09:31:32 -0800154 RTC_DCHECK(outbuf_.get());
155 int res = socket_->Send(outbuf_.get(), outpos_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 if (res <= 0) {
157 return res;
158 }
159 if (static_cast<size_t>(res) <= outpos_) {
160 outpos_ -= res;
161 } else {
jbauch3c165762016-02-26 09:31:32 -0800162 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000163 return -1;
164 }
165 if (outpos_ > 0) {
jbauch3c165762016-02-26 09:31:32 -0800166 memmove(outbuf_.get(), outbuf_.get() + res, outpos_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000167 }
168 return res;
169}
170
171void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
jbauch3c165762016-02-26 09:31:32 -0800172 RTC_DCHECK(outpos_ + cb < outsize_);
173 RTC_DCHECK(outbuf_.get());
174 memcpy(outbuf_.get() + outpos_, pv, cb);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175 outpos_ += cb;
176}
177
178void AsyncTCPSocketBase::OnConnectEvent(AsyncSocket* socket) {
179 SignalConnect(this);
180}
181
182void AsyncTCPSocketBase::OnReadEvent(AsyncSocket* socket) {
jbauch3c165762016-02-26 09:31:32 -0800183 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000184
185 if (listen_) {
186 rtc::SocketAddress address;
187 rtc::AsyncSocket* new_socket = socket->Accept(&address);
188 if (!new_socket) {
189 // TODO: Do something better like forwarding the error
190 // to the user.
191 LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
192 return;
193 }
194
195 HandleIncomingConnection(new_socket);
196
197 // Prime a read event in case data is waiting.
198 new_socket->SignalReadEvent(new_socket);
199 } else {
jbauch3c165762016-02-26 09:31:32 -0800200 RTC_DCHECK(inbuf_.get());
201 int len = socket_->Recv(inbuf_.get() + inpos_, insize_ - inpos_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000202 if (len < 0) {
203 // TODO: Do something better like forwarding the error to the user.
204 if (!socket_->IsBlocking()) {
205 LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
206 }
207 return;
208 }
209
210 inpos_ += len;
211
jbauch3c165762016-02-26 09:31:32 -0800212 ProcessInput(inbuf_.get(), &inpos_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000213
214 if (inpos_ >= insize_) {
215 LOG(LS_ERROR) << "input buffer overflow";
jbauch3c165762016-02-26 09:31:32 -0800216 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217 inpos_ = 0;
218 }
219 }
220}
221
222void AsyncTCPSocketBase::OnWriteEvent(AsyncSocket* socket) {
jbauch3c165762016-02-26 09:31:32 -0800223 RTC_DCHECK(socket_.get() == socket);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224
225 if (outpos_ > 0) {
226 FlushOutBuffer();
227 }
228
229 if (outpos_ == 0) {
230 SignalReadyToSend(this);
231 }
232}
233
234void AsyncTCPSocketBase::OnCloseEvent(AsyncSocket* socket, int error) {
235 SignalClose(this, error);
236}
237
238// AsyncTCPSocket
239// Binds and connects |socket| and creates AsyncTCPSocket for
240// it. Takes ownership of |socket|. Returns NULL if bind() or
241// connect() fail (|socket| is destroyed in that case).
242AsyncTCPSocket* AsyncTCPSocket::Create(
243 AsyncSocket* socket,
244 const SocketAddress& bind_address,
245 const SocketAddress& remote_address) {
246 return new AsyncTCPSocket(AsyncTCPSocketBase::ConnectSocket(
247 socket, bind_address, remote_address), false);
248}
249
250AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
251 : AsyncTCPSocketBase(socket, listen, kBufSize) {
252}
253
254int AsyncTCPSocket::Send(const void *pv, size_t cb,
255 const rtc::PacketOptions& options) {
256 if (cb > kBufSize) {
257 SetError(EMSGSIZE);
258 return -1;
259 }
260
261 // If we are blocking on send, then silently drop this packet
262 if (!IsOutBufferEmpty())
263 return static_cast<int>(cb);
264
265 PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
266 AppendToOutBuffer(&pkt_len, kPacketLenSize);
267 AppendToOutBuffer(pv, cb);
268
269 int res = FlushOutBuffer();
270 if (res <= 0) {
271 // drop packet if we made no progress
272 ClearOutBuffer();
273 return res;
274 }
275
stefanc1aeaf02015-10-15 07:26:07 -0700276 rtc::SentPacket sent_packet(options.packet_id, rtc::Time());
277 SignalSentPacket(this, sent_packet);
278
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000279 // We claim to have sent the whole thing, even if we only sent partial
280 return static_cast<int>(cb);
281}
282
283void AsyncTCPSocket::ProcessInput(char * data, size_t* len) {
284 SocketAddress remote_addr(GetRemoteAddress());
285
286 while (true) {
287 if (*len < kPacketLenSize)
288 return;
289
290 PacketLength pkt_len = rtc::GetBE16(data);
291 if (*len < kPacketLenSize + pkt_len)
292 return;
293
294 SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
295 CreatePacketTime(0));
296
297 *len -= kPacketLenSize + pkt_len;
298 if (*len > 0) {
299 memmove(data, data + kPacketLenSize + pkt_len, *len);
300 }
301 }
302}
303
304void AsyncTCPSocket::HandleIncomingConnection(AsyncSocket* socket) {
305 SignalNewConnection(this, new AsyncTCPSocket(socket, false));
306}
307
308} // namespace rtc