147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2010 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// MacAsyncSocket is a kind of AsyncSocket. It does not support the SOCK_DGRAM
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// type (yet). It works asynchronously, which means that users of this socket
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// should connect to the various events declared in asyncsocket.h to receive
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// notifications about this socket.  It uses CFSockets for signals, but prefers
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// the basic bsd socket operations rather than their CFSocket wrappers when
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// possible.
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <CoreFoundation/CoreFoundation.h>
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <fcntl.h>
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macasyncsocket.h"
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macsocketserver.h"
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const int kCallbackFlags = kCFSocketReadCallBack |
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                  kCFSocketConnectCallBack |
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                  kCFSocketWriteCallBack;
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacAsyncSocket::MacAsyncSocket(MacBaseSocketServer* ss, int family)
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : ss_(ss),
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      socket_(NULL),
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      native_socket_(INVALID_SOCKET),
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      source_(NULL),
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      current_callbacks_(0),
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      disabled_(false),
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      error_(0),
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      state_(CS_CLOSED),
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      resolver_(NULL) {
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Initialize(family);
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacAsyncSocket::~MacAsyncSocket() {
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Close();
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Returns the address to which the socket is bound.  If the socket is not
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// bound, then the any-address is returned.
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSocketAddress MacAsyncSocket::GetLocalAddress() const {
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SocketAddress address;
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // The CFSocket doesn't pick up on implicit binds from the connect call.
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Calling bind in before connect explicitly causes errors, so just query
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // the underlying bsd socket.
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage addr;
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socklen_t addrlen = sizeof(addr);
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int result = ::getsockname(native_socket_,
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                             reinterpret_cast<sockaddr*>(&addr), &addrlen);
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result >= 0) {
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SocketAddressFromSockAddrStorage(addr, &address);
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return address;
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Returns the address to which the socket is connected.  If the socket is not
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// connected, then the any-address is returned.
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSocketAddress MacAsyncSocket::GetRemoteAddress() const {
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SocketAddress address;
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Use native_socket for consistency with GetLocalAddress.
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage addr;
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socklen_t addrlen = sizeof(addr);
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int result = ::getpeername(native_socket_,
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                             reinterpret_cast<sockaddr*>(&addr), &addrlen);
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result >= 0) {
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SocketAddressFromSockAddrStorage(addr, &address);
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return address;
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Bind the socket to a local address.
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::Bind(const SocketAddress& address) {
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage saddr = {0};
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t len = address.ToSockAddrStorage(&saddr);
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int err = ::bind(native_socket_, reinterpret_cast<sockaddr*>(&saddr), len);
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (err == SOCKET_ERROR) error_ = errno;
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return err;
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacAsyncSocket::OnResolveResult(SignalThread* thread) {
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (thread != resolver_) {
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int error = resolver_->GetError();
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (error == 0) {
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error = DoConnect(resolver_->address());
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Close();
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (error) {
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = error;
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SignalCloseEvent(this, error_);
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Connect to a remote address.
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::Connect(const SocketAddress& addr) {
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // TODO(djw): Consolidate all the connect->resolve->doconnect implementations.
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ != CS_CLOSED) {
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SetError(EALREADY);
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (addr.IsUnresolved()) {
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_VERBOSE) << "Resolving addr in MacAsyncSocket::Connect";
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    resolver_ = new AsyncResolver();
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    resolver_->SignalWorkDone.connect(this,
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                      &MacAsyncSocket::OnResolveResult);
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    resolver_->Start(addr);
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = CS_CONNECTING;
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return 0;
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return DoConnect(addr);
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::DoConnect(const SocketAddress& addr) {
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!valid()) {
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Initialize(addr.family());
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!valid())
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SOCKET_ERROR;
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage saddr;
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t len = addr.ToSockAddrStorage(&saddr);
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int result = ::connect(native_socket_, reinterpret_cast<sockaddr*>(&saddr),
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                         len);
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result != SOCKET_ERROR) {
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = CS_CONNECTED;
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = errno;
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (error_ == EINPROGRESS) {
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      state_ = CS_CONNECTING;
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      result = 0;
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return result;
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Send to the remote end we're connected to.
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::Send(const void* buffer, size_t length) {
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!valid()) {
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int sent = ::send(native_socket_, buffer, length, 0);
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (sent == SOCKET_ERROR) {
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = errno;
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (IsBlocking()) {
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Reenable the writable callback (once), since we are flow controlled.
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFSocketEnableCallBacks(socket_, kCallbackFlags);
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      current_callbacks_ = kCallbackFlags;
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return sent;
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Send to the given address. We may or may not be connected to anyone.
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::SendTo(const void* buffer, size_t length,
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                           const SocketAddress& address) {
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!valid()) {
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage saddr;
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t len = address.ToSockAddrStorage(&saddr);
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int sent = ::sendto(native_socket_, buffer, length, 0,
18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                      reinterpret_cast<sockaddr*>(&saddr), len);
18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (sent == SOCKET_ERROR) {
18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = errno;
18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return sent;
18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Read data received from the remote end we're connected to.
19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::Recv(void* buffer, size_t length) {
19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int received = ::recv(native_socket_, reinterpret_cast<char*>(buffer),
19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                        length, 0);
19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (received == SOCKET_ERROR) error_ = errno;
19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Recv should only be called when there is data to read
19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT((received != 0) || (length == 0));
19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return received;
19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Read data received from any remote party
20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::RecvFrom(void* buffer, size_t length,
20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                             SocketAddress* out_addr) {
20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage saddr;
20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socklen_t addr_len = sizeof(saddr);
20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int received = ::recvfrom(native_socket_, reinterpret_cast<char*>(buffer),
20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                            length, 0, reinterpret_cast<sockaddr*>(&saddr),
20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                            &addr_len);
20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (received >= 0 && out_addr != NULL) {
21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SocketAddressFromSockAddrStorage(saddr, out_addr);
21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else if (received == SOCKET_ERROR) {
21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = errno;
21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return received;
21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::Listen(int backlog) {
21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!valid()) {
21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int res = ::listen(native_socket_, backlog);
22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (res != SOCKET_ERROR)
22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = CS_CONNECTING;
22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  else
22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = errno;
22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return res;
22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacAsyncSocket* MacAsyncSocket::Accept(SocketAddress* out_addr) {
23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage saddr;
23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socklen_t addr_len = sizeof(saddr);
23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int socket_fd = ::accept(native_socket_, reinterpret_cast<sockaddr*>(&saddr),
23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                           &addr_len);
23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (socket_fd == INVALID_SOCKET) {
23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = errno;
23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return NULL;
24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  MacAsyncSocket* s = new MacAsyncSocket(ss_, saddr.ss_family, socket_fd);
24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (s && s->valid()) {
24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    s->state_ = CS_CONNECTED;
24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (out_addr)
24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      SocketAddressFromSockAddrStorage(saddr, out_addr);
24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    delete s;
24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    s = NULL;
25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return s;
25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::Close() {
25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (source_ != NULL) {
25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopSourceInvalidate(source_);
25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(source_);
25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (ss_) ss_->UnregisterSocket(this);
25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    source_ = NULL;
26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (socket_ != NULL) {
26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFSocketInvalidate(socket_);
26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(socket_);
26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    socket_ = NULL;
26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (resolver_) {
26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    resolver_->Destroy(false);
27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    resolver_ = NULL;
27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  native_socket_ = INVALID_SOCKET;  // invalidates the socket
27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  error_ = 0;
27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  state_ = CS_CLOSED;
27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return 0;
27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::EstimateMTU(uint16* mtu) {
28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(false && "NYI");
28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::GetError() const {
28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return error_;
28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacAsyncSocket::SetError(int error) {
28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  error_ = error;
29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSocket::ConnState MacAsyncSocket::GetState() const {
29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return state_;
29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::GetOption(Option opt, int* value) {
29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(false && "NYI");
29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint MacAsyncSocket::SetOption(Option opt, int value) {
30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(false && "NYI");
30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacAsyncSocket::EnableCallbacks() {
30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (valid()) {
30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    disabled_ = false;
30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFSocketEnableCallBacks(socket_, current_callbacks_);
31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacAsyncSocket::DisableCallbacks() {
31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (valid()) {
31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    disabled_ = true;
31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFSocketDisableCallBacks(socket_, kCallbackFlags);
31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacAsyncSocket::MacAsyncSocket(MacBaseSocketServer* ss, int family,
32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                               int native_socket)
32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : ss_(ss),
32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      socket_(NULL),
32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      native_socket_(native_socket),
32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      source_(NULL),
32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      current_callbacks_(0),
32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      disabled_(false),
32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      error_(0),
32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      state_(CS_CLOSED),
33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      resolver_(NULL) {
33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Initialize(family);
33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Create a new socket, wrapping the native socket if provided or creating one
33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// otherwise. In case of any failure, consume the native socket.  We assume the
33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// wrapped socket is in the closed state.  If this is not the case you must
33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// update the state_ field for this socket yourself.
33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacAsyncSocket::Initialize(int family) {
33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFSocketContext ctx = { 0 };
34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ctx.info = this;
34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // First create the CFSocket
34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFSocketRef cf_socket = NULL;
34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool res = false;
34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (native_socket_ == INVALID_SOCKET) {
34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    cf_socket = CFSocketCreate(kCFAllocatorDefault,
34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                               family, SOCK_STREAM, IPPROTO_TCP,
34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                               kCallbackFlags, MacAsyncSocketCallBack, &ctx);
34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                         native_socket_, kCallbackFlags,
35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                         MacAsyncSocketCallBack, &ctx);
35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (cf_socket) {
35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    res = true;
35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    socket_ = cf_socket;
35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    native_socket_ = CFSocketGetNative(cf_socket);
35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    current_callbacks_ = kCallbackFlags;
36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (res) {
36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Make the underlying socket asynchronous
36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    res = (-1 != ::fcntl(native_socket_, F_SETFL,
36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                         ::fcntl(native_socket_, F_GETFL, 0) | O_NONBLOCK));
36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (res) {
36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Add this socket to the run loop, at priority 1 so that it will be
37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // queued behind any pending signals.
37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    source_ = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 1);
37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    res = (source_ != NULL);
37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!res) errno = EINVAL;
37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (res) {
37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (ss_) ss_->RegisterSocket(this);
37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopCommonModes);
37947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
38047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!res) {
38247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    int error = errno;
38347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Close();  //  Clears error_.
38447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    error_ = error;
38547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
38647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
38747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Call CFRelease on the result when done using it
38947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgCFDataRef MacAsyncSocket::CopyCFAddress(const SocketAddress& address) {
39047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockaddr_storage saddr;
39147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t len = address.ToSockAddrStorage(&saddr);
39247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  const UInt8* bytes = reinterpret_cast<UInt8*>(&saddr);
39447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFDataRef cf_address = CFDataCreate(kCFAllocatorDefault,
39647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                      bytes, len);
39747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(cf_address != NULL);
39947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return cf_address;
40047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
40147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
40247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacAsyncSocket::MacAsyncSocketCallBack(CFSocketRef s,
40347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            CFSocketCallBackType callbackType,
40447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            CFDataRef address,
40547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            const void* data,
40647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            void* info) {
40747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  MacAsyncSocket* this_socket =
40847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      reinterpret_cast<MacAsyncSocket*>(info);
40947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(this_socket != NULL && this_socket->socket_ == s);
41047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
41147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Don't signal any socket messages if the socketserver is not listening on
41247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // them.  When we are reenabled they will be requeued and will fire again.
41347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (this_socket->disabled_)
41447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
41547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
41647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (callbackType) {
41747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case kCFSocketReadCallBack:
41847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // This callback is invoked in one of 3 situations:
41947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // 1. A new connection is waiting to be accepted.
42047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // 2. The remote end closed the connection (a recv will return 0).
42147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // 3. Data is available to read.
42247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // 4. The connection closed unhappily (recv will return -1).
42347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (this_socket->state_ == CS_CONNECTING) {
42447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // Case 1.
42547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        this_socket->SignalReadEvent(this_socket);
42647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      } else {
42747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        char ch, amt;
42847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        amt = ::recv(this_socket->native_socket_, &ch, 1, MSG_PEEK);
42947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        if (amt == 0) {
43047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          // Case 2.
43147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          this_socket->state_ = CS_CLOSED;
43247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
43347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          // Disable additional callbacks or we will signal close twice.
43447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          CFSocketDisableCallBacks(this_socket->socket_, kCFSocketReadCallBack);
43547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          this_socket->current_callbacks_ &= ~kCFSocketReadCallBack;
43647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          this_socket->SignalCloseEvent(this_socket, 0);
43747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        } else if (amt > 0) {
43847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          // Case 3.
43947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          this_socket->SignalReadEvent(this_socket);
44047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        } else {
44147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          // Case 4.
44247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          int error = errno;
44347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          if (error == EAGAIN) {
44447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            // Observed in practice.  Let's hope it's a spurious or out of date
44547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            // signal, since we just eat it.
44647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          } else {
44747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            this_socket->error_ = error;
44847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            this_socket->SignalCloseEvent(this_socket, error);
44947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          }
45047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        }
45147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
45247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
45347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
45447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case kCFSocketConnectCallBack:
45547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (data != NULL) {
45647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // An error occured in the background while connecting
45747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        this_socket->error_ = errno;
45847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        this_socket->state_ = CS_CLOSED;
45947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        this_socket->SignalCloseEvent(this_socket, this_socket->error_);
46047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      } else {
46147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        this_socket->state_ = CS_CONNECTED;
46247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        this_socket->SignalConnectEvent(this_socket);
46347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
46447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
46547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
46647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case kCFSocketWriteCallBack:
46747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Update our callback tracking.  Write doesn't reenable, so it's off now.
46847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      this_socket->current_callbacks_ &= ~kCFSocketWriteCallBack;
46947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      this_socket->SignalWriteEvent(this_socket);
47047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
47147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
47247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    default:
47347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ASSERT(false && "Invalid callback type for socket");
47447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
47547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
47647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
47747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
478