Home | History | Annotate | Download | only in base
      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) {
    192   int received = ::recv(native_socket_, reinterpret_cast<char*>(buffer),
    193                         length, 0);
    194   if (received == SOCKET_ERROR) error_ = errno;
    195 
    196   // Recv should only be called when there is data to read
    197   ASSERT((received != 0) || (length == 0));
    198   return received;
    199 }
    200 
    201 // Read data received from any remote party
    202 int MacAsyncSocket::RecvFrom(void* buffer, size_t length,
    203                              SocketAddress* out_addr) {
    204   sockaddr_storage saddr;
    205   socklen_t addr_len = sizeof(saddr);
    206   int received = ::recvfrom(native_socket_, reinterpret_cast<char*>(buffer),
    207                             length, 0, reinterpret_cast<sockaddr*>(&saddr),
    208                             &addr_len);
    209   if (received >= 0 && out_addr != NULL) {
    210     SocketAddressFromSockAddrStorage(saddr, out_addr);
    211   } else if (received == SOCKET_ERROR) {
    212     error_ = errno;
    213   }
    214   return received;
    215 }
    216 
    217 int MacAsyncSocket::Listen(int backlog) {
    218   if (!valid()) {
    219     return SOCKET_ERROR;
    220   }
    221 
    222   int res = ::listen(native_socket_, backlog);
    223   if (res != SOCKET_ERROR)
    224     state_ = CS_CONNECTING;
    225   else
    226     error_ = errno;
    227 
    228   return res;
    229 }
    230 
    231 MacAsyncSocket* MacAsyncSocket::Accept(SocketAddress* out_addr) {
    232   sockaddr_storage saddr;
    233   socklen_t addr_len = sizeof(saddr);
    234 
    235   int socket_fd = ::accept(native_socket_, reinterpret_cast<sockaddr*>(&saddr),
    236                            &addr_len);
    237   if (socket_fd == INVALID_SOCKET) {
    238     error_ = errno;
    239     return NULL;
    240   }
    241 
    242   MacAsyncSocket* s = new MacAsyncSocket(ss_, saddr.ss_family, socket_fd);
    243   if (s && s->valid()) {
    244     s->state_ = CS_CONNECTED;
    245     if (out_addr)
    246       SocketAddressFromSockAddrStorage(saddr, out_addr);
    247   } else {
    248     delete s;
    249     s = NULL;
    250   }
    251   return s;
    252 }
    253 
    254 int MacAsyncSocket::Close() {
    255   if (source_ != NULL) {
    256     CFRunLoopSourceInvalidate(source_);
    257     CFRelease(source_);
    258     if (ss_) ss_->UnregisterSocket(this);
    259     source_ = NULL;
    260   }
    261 
    262   if (socket_ != NULL) {
    263     CFSocketInvalidate(socket_);
    264     CFRelease(socket_);
    265     socket_ = NULL;
    266   }
    267 
    268   if (resolver_) {
    269     resolver_->Destroy(false);
    270     resolver_ = NULL;
    271   }
    272 
    273   native_socket_ = INVALID_SOCKET;  // invalidates the socket
    274   error_ = 0;
    275   state_ = CS_CLOSED;
    276   return 0;
    277 }
    278 
    279 int MacAsyncSocket::EstimateMTU(uint16_t* mtu) {
    280   ASSERT(false && "NYI");
    281   return -1;
    282 }
    283 
    284 int MacAsyncSocket::GetError() const {
    285   return error_;
    286 }
    287 
    288 void MacAsyncSocket::SetError(int error) {
    289   error_ = error;
    290 }
    291 
    292 Socket::ConnState MacAsyncSocket::GetState() const {
    293   return state_;
    294 }
    295 
    296 int MacAsyncSocket::GetOption(Option opt, int* value) {
    297   ASSERT(false && "NYI");
    298   return -1;
    299 }
    300 
    301 int MacAsyncSocket::SetOption(Option opt, int value) {
    302   ASSERT(false && "NYI");
    303   return -1;
    304 }
    305 
    306 void MacAsyncSocket::EnableCallbacks() {
    307   if (valid()) {
    308     disabled_ = false;
    309     CFSocketEnableCallBacks(socket_, current_callbacks_);
    310   }
    311 }
    312 
    313 void MacAsyncSocket::DisableCallbacks() {
    314   if (valid()) {
    315     disabled_ = true;
    316     CFSocketDisableCallBacks(socket_, kCallbackFlags);
    317   }
    318 }
    319 
    320 MacAsyncSocket::MacAsyncSocket(MacBaseSocketServer* ss, int family,
    321                                int native_socket)
    322     : ss_(ss),
    323       socket_(NULL),
    324       native_socket_(native_socket),
    325       source_(NULL),
    326       current_callbacks_(0),
    327       disabled_(false),
    328       error_(0),
    329       state_(CS_CLOSED),
    330       resolver_(NULL) {
    331   Initialize(family);
    332 }
    333 
    334 // Create a new socket, wrapping the native socket if provided or creating one
    335 // otherwise. In case of any failure, consume the native socket.  We assume the
    336 // wrapped socket is in the closed state.  If this is not the case you must
    337 // update the state_ field for this socket yourself.
    338 void MacAsyncSocket::Initialize(int family) {
    339   CFSocketContext ctx = { 0 };
    340   ctx.info = this;
    341 
    342   // First create the CFSocket
    343   CFSocketRef cf_socket = NULL;
    344   bool res = false;
    345   if (native_socket_ == INVALID_SOCKET) {
    346     cf_socket = CFSocketCreate(kCFAllocatorDefault,
    347                                family, SOCK_STREAM, IPPROTO_TCP,
    348                                kCallbackFlags, MacAsyncSocketCallBack, &ctx);
    349   } else {
    350     cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
    351                                          native_socket_, kCallbackFlags,
    352                                          MacAsyncSocketCallBack, &ctx);
    353   }
    354 
    355   if (cf_socket) {
    356     res = true;
    357     socket_ = cf_socket;
    358     native_socket_ = CFSocketGetNative(cf_socket);
    359     current_callbacks_ = kCallbackFlags;
    360   }
    361 
    362   if (res) {
    363     // Make the underlying socket asynchronous
    364     res = (-1 != ::fcntl(native_socket_, F_SETFL,
    365                          ::fcntl(native_socket_, F_GETFL, 0) | O_NONBLOCK));
    366   }
    367 
    368   if (res) {
    369     // Add this socket to the run loop, at priority 1 so that it will be
    370     // queued behind any pending signals.
    371     source_ = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 1);
    372     res = (source_ != NULL);
    373     if (!res) errno = EINVAL;
    374   }
    375 
    376   if (res) {
    377     if (ss_) ss_->RegisterSocket(this);
    378     CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopCommonModes);
    379   }
    380 
    381   if (!res) {
    382     int error = errno;
    383     Close();  //  Clears error_.
    384     error_ = error;
    385   }
    386 }
    387 
    388 // Call CFRelease on the result when done using it
    389 CFDataRef MacAsyncSocket::CopyCFAddress(const SocketAddress& address) {
    390   sockaddr_storage saddr;
    391   size_t len = address.ToSockAddrStorage(&saddr);
    392 
    393   const UInt8* bytes = reinterpret_cast<UInt8*>(&saddr);
    394 
    395   CFDataRef cf_address = CFDataCreate(kCFAllocatorDefault,
    396                                       bytes, len);
    397 
    398   ASSERT(cf_address != NULL);
    399   return cf_address;
    400 }
    401 
    402 void MacAsyncSocket::MacAsyncSocketCallBack(CFSocketRef s,
    403                                             CFSocketCallBackType callbackType,
    404                                             CFDataRef address,
    405                                             const void* data,
    406                                             void* info) {
    407   MacAsyncSocket* this_socket =
    408       reinterpret_cast<MacAsyncSocket*>(info);
    409   ASSERT(this_socket != NULL && this_socket->socket_ == s);
    410 
    411   // Don't signal any socket messages if the socketserver is not listening on
    412   // them.  When we are reenabled they will be requeued and will fire again.
    413   if (this_socket->disabled_)
    414     return;
    415 
    416   switch (callbackType) {
    417     case kCFSocketReadCallBack:
    418       // This callback is invoked in one of 3 situations:
    419       // 1. A new connection is waiting to be accepted.
    420       // 2. The remote end closed the connection (a recv will return 0).
    421       // 3. Data is available to read.
    422       // 4. The connection closed unhappily (recv will return -1).
    423       if (this_socket->state_ == CS_CONNECTING) {
    424         // Case 1.
    425         this_socket->SignalReadEvent(this_socket);
    426       } else {
    427         char ch, amt;
    428         amt = ::recv(this_socket->native_socket_, &ch, 1, MSG_PEEK);
    429         if (amt == 0) {
    430           // Case 2.
    431           this_socket->state_ = CS_CLOSED;
    432 
    433           // Disable additional callbacks or we will signal close twice.
    434           CFSocketDisableCallBacks(this_socket->socket_, kCFSocketReadCallBack);
    435           this_socket->current_callbacks_ &= ~kCFSocketReadCallBack;
    436           this_socket->SignalCloseEvent(this_socket, 0);
    437         } else if (amt > 0) {
    438           // Case 3.
    439           this_socket->SignalReadEvent(this_socket);
    440         } else {
    441           // Case 4.
    442           int error = errno;
    443           if (error == EAGAIN) {
    444             // Observed in practice.  Let's hope it's a spurious or out of date
    445             // signal, since we just eat it.
    446           } else {
    447             this_socket->error_ = error;
    448             this_socket->SignalCloseEvent(this_socket, error);
    449           }
    450         }
    451       }
    452       break;
    453 
    454     case kCFSocketConnectCallBack:
    455       if (data != NULL) {
    456         // An error occured in the background while connecting
    457         this_socket->error_ = errno;
    458         this_socket->state_ = CS_CLOSED;
    459         this_socket->SignalCloseEvent(this_socket, this_socket->error_);
    460       } else {
    461         this_socket->state_ = CS_CONNECTED;
    462         this_socket->SignalConnectEvent(this_socket);
    463       }
    464       break;
    465 
    466     case kCFSocketWriteCallBack:
    467       // Update our callback tracking.  Write doesn't reenable, so it's off now.
    468       this_socket->current_callbacks_ &= ~kCFSocketWriteCallBack;
    469       this_socket->SignalWriteEvent(this_socket);
    470       break;
    471 
    472     default:
    473       ASSERT(false && "Invalid callback type for socket");
    474   }
    475 }
    476 
    477 }  // namespace rtc
    478