Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: webrtc/base/macasyncsocket.cc

Issue 2369013002: Delete macsocketserver.h and related files. (Closed)
Patch Set: Drop macsocketserver_unittest.cc. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2010 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 // MacAsyncSocket is a kind of AsyncSocket. It does not support the SOCK_DGRAM
12 // type (yet). It works asynchronously, which means that users of this socket
13 // should connect to the various events declared in asyncsocket.h to receive
14 // notifications about this socket. It uses CFSockets for signals, but prefers
15 // the basic bsd socket operations rather than their CFSocket wrappers when
16 // possible.
17
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <fcntl.h>
20
21 #include "webrtc/base/macasyncsocket.h"
22
23 #include "webrtc/base/logging.h"
24 #include "webrtc/base/macsocketserver.h"
25
26 namespace rtc {
27
28 static const int kCallbackFlags = kCFSocketReadCallBack |
29 kCFSocketConnectCallBack |
30 kCFSocketWriteCallBack;
31
32 MacAsyncSocket::MacAsyncSocket(MacBaseSocketServer* ss, int family)
33 : ss_(ss),
34 socket_(NULL),
35 native_socket_(INVALID_SOCKET),
36 source_(NULL),
37 current_callbacks_(0),
38 disabled_(false),
39 error_(0),
40 state_(CS_CLOSED),
41 resolver_(NULL) {
42 Initialize(family);
43 }
44
45 MacAsyncSocket::~MacAsyncSocket() {
46 Close();
47 }
48
49 // Returns the address to which the socket is bound. If the socket is not
50 // bound, then the any-address is returned.
51 SocketAddress MacAsyncSocket::GetLocalAddress() const {
52 SocketAddress address;
53
54 // The CFSocket doesn't pick up on implicit binds from the connect call.
55 // Calling bind in before connect explicitly causes errors, so just query
56 // the underlying bsd socket.
57 sockaddr_storage addr;
58 socklen_t addrlen = sizeof(addr);
59 int result = ::getsockname(native_socket_,
60 reinterpret_cast<sockaddr*>(&addr), &addrlen);
61 if (result >= 0) {
62 SocketAddressFromSockAddrStorage(addr, &address);
63 }
64 return address;
65 }
66
67 // Returns the address to which the socket is connected. If the socket is not
68 // connected, then the any-address is returned.
69 SocketAddress MacAsyncSocket::GetRemoteAddress() const {
70 SocketAddress address;
71
72 // Use native_socket for consistency with GetLocalAddress.
73 sockaddr_storage addr;
74 socklen_t addrlen = sizeof(addr);
75 int result = ::getpeername(native_socket_,
76 reinterpret_cast<sockaddr*>(&addr), &addrlen);
77 if (result >= 0) {
78 SocketAddressFromSockAddrStorage(addr, &address);
79 }
80 return address;
81 }
82
83 // Bind the socket to a local address.
84 int MacAsyncSocket::Bind(const SocketAddress& address) {
85 sockaddr_storage saddr = {0};
86 size_t len = address.ToSockAddrStorage(&saddr);
87 int err = ::bind(native_socket_, reinterpret_cast<sockaddr*>(&saddr), len);
88 if (err == SOCKET_ERROR) error_ = errno;
89 return err;
90 }
91
92 void MacAsyncSocket::OnResolveResult(SignalThread* thread) {
93 if (thread != resolver_) {
94 return;
95 }
96 int error = resolver_->GetError();
97 if (error == 0) {
98 error = DoConnect(resolver_->address());
99 } else {
100 Close();
101 }
102 if (error) {
103 error_ = error;
104 SignalCloseEvent(this, error_);
105 }
106 }
107
108 // Connect to a remote address.
109 int MacAsyncSocket::Connect(const SocketAddress& addr) {
110 // TODO(djw): Consolidate all the connect->resolve->doconnect implementations.
111 if (state_ != CS_CLOSED) {
112 SetError(EALREADY);
113 return SOCKET_ERROR;
114 }
115 if (addr.IsUnresolvedIP()) {
116 LOG(LS_VERBOSE) << "Resolving addr in MacAsyncSocket::Connect";
117 resolver_ = new AsyncResolver();
118 resolver_->SignalWorkDone.connect(this,
119 &MacAsyncSocket::OnResolveResult);
120 resolver_->Start(addr);
121 state_ = CS_CONNECTING;
122 return 0;
123 }
124 return DoConnect(addr);
125 }
126
127 int MacAsyncSocket::DoConnect(const SocketAddress& addr) {
128 if (!valid()) {
129 Initialize(addr.family());
130 if (!valid())
131 return SOCKET_ERROR;
132 }
133
134 sockaddr_storage saddr;
135 size_t len = addr.ToSockAddrStorage(&saddr);
136 int result = ::connect(native_socket_, reinterpret_cast<sockaddr*>(&saddr),
137 len);
138
139 if (result != SOCKET_ERROR) {
140 state_ = CS_CONNECTED;
141 } else {
142 error_ = errno;
143 if (error_ == EINPROGRESS) {
144 state_ = CS_CONNECTING;
145 result = 0;
146 }
147 }
148 return result;
149 }
150
151 // Send to the remote end we're connected to.
152 int MacAsyncSocket::Send(const void* buffer, size_t length) {
153 if (!valid()) {
154 return SOCKET_ERROR;
155 }
156
157 int sent = ::send(native_socket_, buffer, length, 0);
158
159 if (sent == SOCKET_ERROR) {
160 error_ = errno;
161
162 if (IsBlocking()) {
163 // Reenable the writable callback (once), since we are flow controlled.
164 CFSocketEnableCallBacks(socket_, kCallbackFlags);
165 current_callbacks_ = kCallbackFlags;
166 }
167 }
168 return sent;
169 }
170
171 // Send to the given address. We may or may not be connected to anyone.
172 int MacAsyncSocket::SendTo(const void* buffer, size_t length,
173 const SocketAddress& address) {
174 if (!valid()) {
175 return SOCKET_ERROR;
176 }
177
178 sockaddr_storage saddr;
179 size_t len = address.ToSockAddrStorage(&saddr);
180 int sent = ::sendto(native_socket_, buffer, length, 0,
181 reinterpret_cast<sockaddr*>(&saddr), len);
182
183 if (sent == SOCKET_ERROR) {
184 error_ = errno;
185 }
186
187 return sent;
188 }
189
190 // Read data received from the remote end we're connected to.
191 int MacAsyncSocket::Recv(void* buffer, size_t length, int64_t* timestamp) {
192 if (timestamp) {
193 *timestamp = -1;
194 }
195 int received = ::recv(native_socket_, reinterpret_cast<char*>(buffer),
196 length, 0);
197 if (received == SOCKET_ERROR) error_ = errno;
198
199 // Recv should only be called when there is data to read
200 ASSERT((received != 0) || (length == 0));
201 return received;
202 }
203
204 // Read data received from any remote party
205 int MacAsyncSocket::RecvFrom(void* buffer,
206 size_t length,
207 SocketAddress* out_addr,
208 int64_t* timestamp) {
209 if (timestamp) {
210 *timestamp = -1;
211 }
212 sockaddr_storage saddr;
213 socklen_t addr_len = sizeof(saddr);
214 int received = ::recvfrom(native_socket_, reinterpret_cast<char*>(buffer),
215 length, 0, reinterpret_cast<sockaddr*>(&saddr),
216 &addr_len);
217 if (received >= 0 && out_addr != NULL) {
218 SocketAddressFromSockAddrStorage(saddr, out_addr);
219 } else if (received == SOCKET_ERROR) {
220 error_ = errno;
221 }
222 return received;
223 }
224
225 int MacAsyncSocket::Listen(int backlog) {
226 if (!valid()) {
227 return SOCKET_ERROR;
228 }
229
230 int res = ::listen(native_socket_, backlog);
231 if (res != SOCKET_ERROR)
232 state_ = CS_CONNECTING;
233 else
234 error_ = errno;
235
236 return res;
237 }
238
239 MacAsyncSocket* MacAsyncSocket::Accept(SocketAddress* out_addr) {
240 sockaddr_storage saddr;
241 socklen_t addr_len = sizeof(saddr);
242
243 int socket_fd = ::accept(native_socket_, reinterpret_cast<sockaddr*>(&saddr),
244 &addr_len);
245 if (socket_fd == INVALID_SOCKET) {
246 error_ = errno;
247 return NULL;
248 }
249
250 MacAsyncSocket* s = new MacAsyncSocket(ss_, saddr.ss_family, socket_fd);
251 if (s && s->valid()) {
252 s->state_ = CS_CONNECTED;
253 if (out_addr)
254 SocketAddressFromSockAddrStorage(saddr, out_addr);
255 } else {
256 delete s;
257 s = NULL;
258 }
259 return s;
260 }
261
262 int MacAsyncSocket::Close() {
263 if (source_ != NULL) {
264 CFRunLoopSourceInvalidate(source_);
265 CFRelease(source_);
266 if (ss_) ss_->UnregisterSocket(this);
267 source_ = NULL;
268 }
269
270 if (socket_ != NULL) {
271 CFSocketInvalidate(socket_);
272 CFRelease(socket_);
273 socket_ = NULL;
274 }
275
276 if (resolver_) {
277 resolver_->Destroy(false);
278 resolver_ = NULL;
279 }
280
281 native_socket_ = INVALID_SOCKET; // invalidates the socket
282 error_ = 0;
283 state_ = CS_CLOSED;
284 return 0;
285 }
286
287 int MacAsyncSocket::EstimateMTU(uint16_t* mtu) {
288 ASSERT(false && "NYI");
289 return -1;
290 }
291
292 int MacAsyncSocket::GetError() const {
293 return error_;
294 }
295
296 void MacAsyncSocket::SetError(int error) {
297 error_ = error;
298 }
299
300 Socket::ConnState MacAsyncSocket::GetState() const {
301 return state_;
302 }
303
304 int MacAsyncSocket::GetOption(Option opt, int* value) {
305 ASSERT(false && "NYI");
306 return -1;
307 }
308
309 int MacAsyncSocket::SetOption(Option opt, int value) {
310 ASSERT(false && "NYI");
311 return -1;
312 }
313
314 void MacAsyncSocket::EnableCallbacks() {
315 if (valid()) {
316 disabled_ = false;
317 CFSocketEnableCallBacks(socket_, current_callbacks_);
318 }
319 }
320
321 void MacAsyncSocket::DisableCallbacks() {
322 if (valid()) {
323 disabled_ = true;
324 CFSocketDisableCallBacks(socket_, kCallbackFlags);
325 }
326 }
327
328 MacAsyncSocket::MacAsyncSocket(MacBaseSocketServer* ss, int family,
329 int native_socket)
330 : ss_(ss),
331 socket_(NULL),
332 native_socket_(native_socket),
333 source_(NULL),
334 current_callbacks_(0),
335 disabled_(false),
336 error_(0),
337 state_(CS_CLOSED),
338 resolver_(NULL) {
339 Initialize(family);
340 }
341
342 // Create a new socket, wrapping the native socket if provided or creating one
343 // otherwise. In case of any failure, consume the native socket. We assume the
344 // wrapped socket is in the closed state. If this is not the case you must
345 // update the state_ field for this socket yourself.
346 void MacAsyncSocket::Initialize(int family) {
347 CFSocketContext ctx = { 0 };
348 ctx.info = this;
349
350 // First create the CFSocket
351 CFSocketRef cf_socket = NULL;
352 bool res = false;
353 if (native_socket_ == INVALID_SOCKET) {
354 cf_socket = CFSocketCreate(kCFAllocatorDefault,
355 family, SOCK_STREAM, IPPROTO_TCP,
356 kCallbackFlags, MacAsyncSocketCallBack, &ctx);
357 } else {
358 cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
359 native_socket_, kCallbackFlags,
360 MacAsyncSocketCallBack, &ctx);
361 }
362
363 if (cf_socket) {
364 res = true;
365 socket_ = cf_socket;
366 native_socket_ = CFSocketGetNative(cf_socket);
367 current_callbacks_ = kCallbackFlags;
368 }
369
370 if (res) {
371 // Make the underlying socket asynchronous
372 res = (-1 != ::fcntl(native_socket_, F_SETFL,
373 ::fcntl(native_socket_, F_GETFL, 0) | O_NONBLOCK));
374 }
375
376 if (res) {
377 // Add this socket to the run loop, at priority 1 so that it will be
378 // queued behind any pending signals.
379 source_ = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 1);
380 res = (source_ != NULL);
381 if (!res) errno = EINVAL;
382 }
383
384 if (res) {
385 if (ss_) ss_->RegisterSocket(this);
386 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopCommonModes);
387 }
388
389 if (!res) {
390 int error = errno;
391 Close(); // Clears error_.
392 error_ = error;
393 }
394 }
395
396 // Call CFRelease on the result when done using it
397 CFDataRef MacAsyncSocket::CopyCFAddress(const SocketAddress& address) {
398 sockaddr_storage saddr;
399 size_t len = address.ToSockAddrStorage(&saddr);
400
401 const UInt8* bytes = reinterpret_cast<UInt8*>(&saddr);
402
403 CFDataRef cf_address = CFDataCreate(kCFAllocatorDefault,
404 bytes, len);
405
406 ASSERT(cf_address != NULL);
407 return cf_address;
408 }
409
410 void MacAsyncSocket::MacAsyncSocketCallBack(CFSocketRef s,
411 CFSocketCallBackType callbackType,
412 CFDataRef address,
413 const void* data,
414 void* info) {
415 MacAsyncSocket* this_socket =
416 reinterpret_cast<MacAsyncSocket*>(info);
417 ASSERT(this_socket != NULL && this_socket->socket_ == s);
418
419 // Don't signal any socket messages if the socketserver is not listening on
420 // them. When we are reenabled they will be requeued and will fire again.
421 if (this_socket->disabled_)
422 return;
423
424 switch (callbackType) {
425 case kCFSocketReadCallBack:
426 // This callback is invoked in one of 3 situations:
427 // 1. A new connection is waiting to be accepted.
428 // 2. The remote end closed the connection (a recv will return 0).
429 // 3. Data is available to read.
430 // 4. The connection closed unhappily (recv will return -1).
431 if (this_socket->state_ == CS_CONNECTING) {
432 // Case 1.
433 this_socket->SignalReadEvent(this_socket);
434 } else {
435 char ch, amt;
436 amt = ::recv(this_socket->native_socket_, &ch, 1, MSG_PEEK);
437 if (amt == 0) {
438 // Case 2.
439 this_socket->state_ = CS_CLOSED;
440
441 // Disable additional callbacks or we will signal close twice.
442 CFSocketDisableCallBacks(this_socket->socket_, kCFSocketReadCallBack);
443 this_socket->current_callbacks_ &= ~kCFSocketReadCallBack;
444 this_socket->SignalCloseEvent(this_socket, 0);
445 } else if (amt > 0) {
446 // Case 3.
447 this_socket->SignalReadEvent(this_socket);
448 } else {
449 // Case 4.
450 int error = errno;
451 if (error == EAGAIN) {
452 // Observed in practice. Let's hope it's a spurious or out of date
453 // signal, since we just eat it.
454 } else {
455 this_socket->error_ = error;
456 this_socket->SignalCloseEvent(this_socket, error);
457 }
458 }
459 }
460 break;
461
462 case kCFSocketConnectCallBack:
463 if (data != NULL) {
464 // An error occured in the background while connecting
465 this_socket->error_ = errno;
466 this_socket->state_ = CS_CLOSED;
467 this_socket->SignalCloseEvent(this_socket, this_socket->error_);
468 } else {
469 this_socket->state_ = CS_CONNECTED;
470 this_socket->SignalConnectEvent(this_socket);
471 }
472 break;
473
474 case kCFSocketWriteCallBack:
475 // Update our callback tracking. Write doesn't reenable, so it's off now.
476 this_socket->current_callbacks_ &= ~kCFSocketWriteCallBack;
477 this_socket->SignalWriteEvent(this_socket);
478 break;
479
480 default:
481 ASSERT(false && "Invalid callback type for socket");
482 }
483 }
484
485 } // namespace rtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698