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