| Index: net/base/tcp_client_socket_libevent.cc
|
| ===================================================================
|
| --- net/base/tcp_client_socket_libevent.cc (revision 18948)
|
| +++ net/base/tcp_client_socket_libevent.cc (working copy)
|
| @@ -1,373 +0,0 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/base/tcp_client_socket_libevent.h"
|
| -
|
| -#include <errno.h>
|
| -#include <fcntl.h>
|
| -#include <netdb.h>
|
| -#include <sys/socket.h>
|
| -
|
| -#include "base/eintr_wrapper.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/string_util.h"
|
| -#include "base/trace_event.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "third_party/libevent/event.h"
|
| -
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -const int kInvalidSocket = -1;
|
| -
|
| -// Return 0 on success, -1 on failure.
|
| -// Too small a function to bother putting in a library?
|
| -int SetNonBlocking(int fd) {
|
| - int flags = fcntl(fd, F_GETFL, 0);
|
| - if (-1 == flags)
|
| - return flags;
|
| - return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
| -}
|
| -
|
| -// Convert values from <errno.h> to values from "net/base/net_errors.h"
|
| -int MapPosixError(int err) {
|
| - // There are numerous posix error codes, but these are the ones we thus far
|
| - // find interesting.
|
| - switch (err) {
|
| - case EAGAIN:
|
| -#if EWOULDBLOCK != EAGAIN
|
| - case EWOULDBLOCK:
|
| -#endif
|
| - return ERR_IO_PENDING;
|
| - case ENETDOWN:
|
| - return ERR_INTERNET_DISCONNECTED;
|
| - case ETIMEDOUT:
|
| - return ERR_TIMED_OUT;
|
| - case ECONNRESET:
|
| - case ENETRESET: // Related to keep-alive
|
| - return ERR_CONNECTION_RESET;
|
| - case ECONNABORTED:
|
| - return ERR_CONNECTION_ABORTED;
|
| - case ECONNREFUSED:
|
| - return ERR_CONNECTION_REFUSED;
|
| - case EHOSTUNREACH:
|
| - case ENETUNREACH:
|
| - return ERR_ADDRESS_UNREACHABLE;
|
| - case EADDRNOTAVAIL:
|
| - return ERR_ADDRESS_INVALID;
|
| - case 0:
|
| - return OK;
|
| - default:
|
| - LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
|
| - return ERR_FAILED;
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses)
|
| - : socket_(kInvalidSocket),
|
| - addresses_(addresses),
|
| - current_ai_(addresses_.head()),
|
| - waiting_connect_(false),
|
| - read_watcher_(this),
|
| - write_watcher_(this),
|
| - read_callback_(NULL),
|
| - write_callback_(NULL) {
|
| -}
|
| -
|
| -TCPClientSocketLibevent::~TCPClientSocketLibevent() {
|
| - Disconnect();
|
| -}
|
| -
|
| -int TCPClientSocketLibevent::Connect(CompletionCallback* callback) {
|
| - // If already connected, then just return OK.
|
| - if (socket_ != kInvalidSocket)
|
| - return OK;
|
| -
|
| - DCHECK(!waiting_connect_);
|
| -
|
| - TRACE_EVENT_BEGIN("socket.connect", this, "");
|
| - const addrinfo* ai = current_ai_;
|
| - DCHECK(ai);
|
| -
|
| - int rv = CreateSocket(ai);
|
| - if (rv != OK)
|
| - return rv;
|
| -
|
| - if (!HANDLE_EINTR(connect(socket_, ai->ai_addr,
|
| - static_cast<int>(ai->ai_addrlen)))) {
|
| - TRACE_EVENT_END("socket.connect", this, "");
|
| - // Connected without waiting!
|
| - return OK;
|
| - }
|
| -
|
| - // Synchronous operation not supported
|
| - DCHECK(callback);
|
| -
|
| - if (errno != EINPROGRESS) {
|
| - DLOG(INFO) << "connect failed: " << errno;
|
| - close(socket_);
|
| - socket_ = kInvalidSocket;
|
| - return MapPosixError(errno);
|
| - }
|
| -
|
| - // Initialize write_socket_watcher_ and link it to our MessagePump.
|
| - // POLLOUT is set if the connection is established.
|
| - // POLLIN is set if the connection fails.
|
| - if (!MessageLoopForIO::current()->WatchFileDescriptor(
|
| - socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_,
|
| - &write_watcher_)) {
|
| - DLOG(INFO) << "WatchFileDescriptor failed: " << errno;
|
| - close(socket_);
|
| - socket_ = kInvalidSocket;
|
| - return MapPosixError(errno);
|
| - }
|
| -
|
| - waiting_connect_ = true;
|
| - write_callback_ = callback;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void TCPClientSocketLibevent::Disconnect() {
|
| - if (socket_ == kInvalidSocket)
|
| - return;
|
| -
|
| - TRACE_EVENT_INSTANT("socket.disconnect", this, "");
|
| -
|
| - bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
|
| - DCHECK(ok);
|
| - ok = write_socket_watcher_.StopWatchingFileDescriptor();
|
| - DCHECK(ok);
|
| - close(socket_);
|
| - socket_ = kInvalidSocket;
|
| - waiting_connect_ = false;
|
| -
|
| - // Reset for next time.
|
| - current_ai_ = addresses_.head();
|
| -}
|
| -
|
| -bool TCPClientSocketLibevent::IsConnected() const {
|
| - if (socket_ == kInvalidSocket || waiting_connect_)
|
| - return false;
|
| -
|
| - // Check if connection is alive.
|
| - char c;
|
| - int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
|
| - if (rv == 0)
|
| - return false;
|
| - if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool TCPClientSocketLibevent::IsConnectedAndIdle() const {
|
| - if (socket_ == kInvalidSocket || waiting_connect_)
|
| - return false;
|
| -
|
| - // Check if connection is alive and we haven't received any data
|
| - // unexpectedly.
|
| - char c;
|
| - int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
|
| - if (rv >= 0)
|
| - return false;
|
| - if (errno != EAGAIN && errno != EWOULDBLOCK)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -int TCPClientSocketLibevent::Read(IOBuffer* buf,
|
| - int buf_len,
|
| - CompletionCallback* callback) {
|
| - DCHECK_NE(kInvalidSocket, socket_);
|
| - DCHECK(!waiting_connect_);
|
| - DCHECK(!read_callback_);
|
| - // Synchronous operation not supported
|
| - DCHECK(callback);
|
| - DCHECK_GT(buf_len, 0);
|
| -
|
| - TRACE_EVENT_BEGIN("socket.read", this, "");
|
| - int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
|
| - if (nread >= 0) {
|
| - TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", nread));
|
| - return nread;
|
| - }
|
| - if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
| - DLOG(INFO) << "read failed, errno " << errno;
|
| - return MapPosixError(errno);
|
| - }
|
| -
|
| - if (!MessageLoopForIO::current()->WatchFileDescriptor(
|
| - socket_, true, MessageLoopForIO::WATCH_READ,
|
| - &read_socket_watcher_, &read_watcher_)) {
|
| - DLOG(INFO) << "WatchFileDescriptor failed on read, errno " << errno;
|
| - return MapPosixError(errno);
|
| - }
|
| -
|
| - read_buf_ = buf;
|
| - read_buf_len_ = buf_len;
|
| - read_callback_ = callback;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -int TCPClientSocketLibevent::Write(IOBuffer* buf,
|
| - int buf_len,
|
| - CompletionCallback* callback) {
|
| - DCHECK_NE(kInvalidSocket, socket_);
|
| - DCHECK(!waiting_connect_);
|
| - DCHECK(!write_callback_);
|
| - // Synchronous operation not supported
|
| - DCHECK(callback);
|
| - DCHECK_GT(buf_len, 0);
|
| -
|
| - TRACE_EVENT_BEGIN("socket.write", this, "");
|
| - int nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
|
| - if (nwrite >= 0) {
|
| - TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", nwrite));
|
| - return nwrite;
|
| - }
|
| - if (errno != EAGAIN && errno != EWOULDBLOCK)
|
| - return MapPosixError(errno);
|
| -
|
| - if (!MessageLoopForIO::current()->WatchFileDescriptor(
|
| - socket_, true, MessageLoopForIO::WATCH_WRITE,
|
| - &write_socket_watcher_, &write_watcher_)) {
|
| - DLOG(INFO) << "WatchFileDescriptor failed on write, errno " << errno;
|
| - return MapPosixError(errno);
|
| - }
|
| -
|
| -
|
| - write_buf_ = buf;
|
| - write_buf_len_ = buf_len;
|
| - write_callback_ = callback;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) {
|
| - socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
| - if (socket_ == kInvalidSocket)
|
| - return MapPosixError(errno);
|
| -
|
| - if (SetNonBlocking(socket_))
|
| - return MapPosixError(errno);
|
| -
|
| - return OK;
|
| -}
|
| -
|
| -void TCPClientSocketLibevent::DoReadCallback(int rv) {
|
| - DCHECK_NE(rv, ERR_IO_PENDING);
|
| - DCHECK(read_callback_);
|
| -
|
| - // since Run may result in Read being called, clear read_callback_ up front.
|
| - CompletionCallback* c = read_callback_;
|
| - read_callback_ = NULL;
|
| - c->Run(rv);
|
| -}
|
| -
|
| -void TCPClientSocketLibevent::DoWriteCallback(int rv) {
|
| - DCHECK_NE(rv, ERR_IO_PENDING);
|
| - DCHECK(write_callback_);
|
| -
|
| - // since Run may result in Write being called, clear write_callback_ up front.
|
| - CompletionCallback* c = write_callback_;
|
| - write_callback_ = NULL;
|
| - c->Run(rv);
|
| -}
|
| -
|
| -void TCPClientSocketLibevent::DidCompleteConnect() {
|
| - int result = ERR_UNEXPECTED;
|
| -
|
| - TRACE_EVENT_END("socket.connect", this, "");
|
| -
|
| - // Check to see if connect succeeded
|
| - int error_code = 0;
|
| - socklen_t len = sizeof(error_code);
|
| - if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &error_code, &len) < 0)
|
| - error_code = errno;
|
| -
|
| - if (error_code == EINPROGRESS || error_code == EALREADY) {
|
| - NOTREACHED(); // This indicates a bug in libevent or our code.
|
| - result = ERR_IO_PENDING;
|
| - } else if (current_ai_->ai_next && (
|
| - error_code == EADDRNOTAVAIL ||
|
| - error_code == EAFNOSUPPORT ||
|
| - error_code == ECONNREFUSED ||
|
| - error_code == ENETUNREACH ||
|
| - error_code == EHOSTUNREACH ||
|
| - error_code == ETIMEDOUT)) {
|
| - // This address failed, try next one in list.
|
| - const addrinfo* next = current_ai_->ai_next;
|
| - Disconnect();
|
| - current_ai_ = next;
|
| - result = Connect(write_callback_);
|
| - } else {
|
| - result = MapPosixError(error_code);
|
| - bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
|
| - DCHECK(ok);
|
| - waiting_connect_ = false;
|
| - }
|
| -
|
| - if (result != ERR_IO_PENDING) {
|
| - DoWriteCallback(result);
|
| - }
|
| -}
|
| -
|
| -void TCPClientSocketLibevent::DidCompleteRead() {
|
| - int bytes_transferred;
|
| - bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
|
| - read_buf_len_));
|
| -
|
| - int result;
|
| - if (bytes_transferred >= 0) {
|
| - TRACE_EVENT_END("socket.read", this,
|
| - StringPrintf("%d bytes", bytes_transferred));
|
| - result = bytes_transferred;
|
| - } else {
|
| - result = MapPosixError(errno);
|
| - }
|
| -
|
| - if (result != ERR_IO_PENDING) {
|
| - read_buf_ = NULL;
|
| - read_buf_len_ = 0;
|
| - bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
|
| - DCHECK(ok);
|
| - DoReadCallback(result);
|
| - }
|
| -}
|
| -
|
| -void TCPClientSocketLibevent::DidCompleteWrite() {
|
| - int bytes_transferred;
|
| - bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
|
| - write_buf_len_));
|
| -
|
| - int result;
|
| - if (bytes_transferred >= 0) {
|
| - result = bytes_transferred;
|
| - TRACE_EVENT_END("socket.write", this,
|
| - StringPrintf("%d bytes", bytes_transferred));
|
| - } else {
|
| - result = MapPosixError(errno);
|
| - }
|
| -
|
| - if (result != ERR_IO_PENDING) {
|
| - write_buf_ = NULL;
|
| - write_buf_len_ = 0;
|
| - write_socket_watcher_.StopWatchingFileDescriptor();
|
| - DoWriteCallback(result);
|
| - }
|
| -}
|
| -
|
| -int TCPClientSocketLibevent::GetPeerName(struct sockaddr *name,
|
| - socklen_t *namelen) {
|
| - return ::getpeername(socket_, name, namelen);
|
| -}
|
| -
|
| -} // namespace net
|
|
|