1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/socket/tcp_server_socket_libevent.h" 6 7#include <errno.h> 8#include <fcntl.h> 9#include <netdb.h> 10#include <sys/socket.h> 11 12#include "build/build_config.h" 13 14#if defined(OS_POSIX) 15#include <netinet/in.h> 16#endif 17#if defined(USE_SYSTEM_LIBEVENT) 18#include <event.h> 19#else 20#include "third_party/libevent/event.h" 21#endif 22 23#include "base/eintr_wrapper.h" 24#include "net/base/ip_endpoint.h" 25#include "net/base/net_errors.h" 26#include "net/base/net_util.h" 27#include "net/socket/tcp_client_socket.h" 28 29namespace net { 30 31namespace { 32 33const int kInvalidSocket = -1; 34 35} // namespace 36 37TCPServerSocketLibevent::TCPServerSocketLibevent( 38 net::NetLog* net_log, 39 const net::NetLog::Source& source) 40 : socket_(kInvalidSocket), 41 accept_socket_(NULL), 42 accept_callback_(NULL), 43 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 44 scoped_refptr<NetLog::EventParameters> params; 45 if (source.is_valid()) 46 params = new NetLogSourceParameter("source_dependency", source); 47 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params); 48} 49 50TCPServerSocketLibevent::~TCPServerSocketLibevent() { 51 if (socket_ != kInvalidSocket) 52 Close(); 53 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL); 54} 55 56int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) { 57 DCHECK(CalledOnValidThread()); 58 DCHECK_GT(backlog, 0); 59 DCHECK_EQ(socket_, kInvalidSocket); 60 61 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 62 if (socket_ < 0) { 63 PLOG(ERROR) << "socket() returned an error"; 64 return MapSystemError(errno); 65 } 66 67 if (SetNonBlocking(socket_)) { 68 int result = MapSystemError(errno); 69 Close(); 70 return result; 71 } 72 73 struct sockaddr_storage addr_storage; 74 size_t addr_len = sizeof(addr_storage); 75 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); 76 if (!address.ToSockAddr(addr, &addr_len)) 77 return ERR_INVALID_ARGUMENT; 78 79 int result = bind(socket_, addr, addr_len); 80 if (result < 0) { 81 PLOG(ERROR) << "bind() returned an error"; 82 result = MapSystemError(errno); 83 Close(); 84 return result; 85 } 86 87 result = listen(socket_, backlog); 88 if (result < 0) { 89 PLOG(ERROR) << "listen() returned an error"; 90 result = MapSystemError(errno); 91 Close(); 92 return result; 93 } 94 95 return OK; 96} 97 98int TCPServerSocketLibevent::GetLocalAddress(IPEndPoint* address) const { 99 DCHECK(CalledOnValidThread()); 100 DCHECK(address); 101 102 struct sockaddr_storage addr_storage; 103 socklen_t addr_len = sizeof(addr_storage); 104 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); 105 if (getsockname(socket_, addr, &addr_len) < 0) 106 return MapSystemError(errno); 107 if (!address->FromSockAddr(addr, addr_len)) 108 return ERR_FAILED; 109 110 return OK; 111} 112 113int TCPServerSocketLibevent::Accept( 114 scoped_ptr<ClientSocket>* socket, CompletionCallback* callback) { 115 DCHECK(CalledOnValidThread()); 116 DCHECK(socket); 117 DCHECK(callback); 118 DCHECK(!accept_callback_); 119 120 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT, NULL); 121 122 int result = AcceptInternal(socket); 123 124 if (result == ERR_IO_PENDING) { 125 if (!MessageLoopForIO::current()->WatchFileDescriptor( 126 socket_, true, MessageLoopForIO::WATCH_READ, 127 &accept_socket_watcher_, this)) { 128 PLOG(ERROR) << "WatchFileDescriptor failed on read"; 129 return MapSystemError(errno); 130 } 131 132 accept_socket_ = socket; 133 accept_callback_ = callback; 134 } 135 136 return result; 137} 138 139int TCPServerSocketLibevent::AcceptInternal( 140 scoped_ptr<ClientSocket>* socket) { 141 struct sockaddr_storage addr_storage; 142 socklen_t addr_len = sizeof(addr_storage); 143 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); 144 145 int result = HANDLE_EINTR(accept(socket_, addr, &addr_len)); 146 if (result < 0) { 147 int net_error = MapSystemError(errno); 148 if (net_error != ERR_IO_PENDING) 149 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error); 150 return net_error; 151 } 152 153 IPEndPoint address; 154 if (!address.FromSockAddr(addr, addr_len)) { 155 NOTREACHED(); 156 if (HANDLE_EINTR(close(result)) < 0) 157 PLOG(ERROR) << "close"; 158 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED); 159 return ERR_FAILED; 160 } 161 TCPClientSocket* tcp_socket = new TCPClientSocket( 162 AddressList(address.address(), address.port(), false), 163 net_log_.net_log(), net_log_.source()); 164 tcp_socket->AdoptSocket(result); 165 socket->reset(tcp_socket); 166 net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT, 167 make_scoped_refptr(new NetLogStringParameter( 168 "address", address.ToString()))); 169 return OK; 170} 171 172void TCPServerSocketLibevent::Close() { 173 if (socket_ != kInvalidSocket) { 174 if (HANDLE_EINTR(close(socket_)) < 0) 175 PLOG(ERROR) << "close"; 176 socket_ = kInvalidSocket; 177 } 178} 179 180void TCPServerSocketLibevent::OnFileCanReadWithoutBlocking(int fd) { 181 DCHECK(CalledOnValidThread()); 182 183 int result = AcceptInternal(accept_socket_); 184 if (result != ERR_IO_PENDING) { 185 CompletionCallback* c = accept_callback_; 186 accept_callback_ = NULL; 187 accept_socket_ = NULL; 188 c->Run(result); 189 } 190} 191 192void TCPServerSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) { 193 NOTREACHED(); 194} 195 196} // namespace net 197