1// Copyright (c) 2012 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/tools/flip_server/acceptor_thread.h" 6 7#include <netinet/in.h> 8#include <netinet/tcp.h> // For TCP_NODELAY 9#include <sys/socket.h> 10#include <sys/types.h> 11 12#include <string> 13 14#include "net/tools/flip_server/constants.h" 15#include "net/tools/flip_server/flip_config.h" 16#include "net/tools/flip_server/sm_connection.h" 17#include "net/tools/flip_server/spdy_ssl.h" 18#include "openssl/err.h" 19#include "openssl/ssl.h" 20 21namespace net { 22 23SMAcceptorThread::SMAcceptorThread(FlipAcceptor* acceptor, 24 MemoryCache* memory_cache) 25 : SimpleThread("SMAcceptorThread"), 26 acceptor_(acceptor), 27 ssl_state_(NULL), 28 use_ssl_(false), 29 idle_socket_timeout_s_(acceptor->idle_socket_timeout_s_), 30 quitting_(false), 31 memory_cache_(memory_cache) { 32 if (!acceptor->ssl_cert_filename_.empty() && 33 !acceptor->ssl_key_filename_.empty()) { 34 ssl_state_ = new SSLState; 35 bool use_npn = true; 36 if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { 37 use_npn = false; 38 } 39 InitSSL(ssl_state_, 40 acceptor_->ssl_cert_filename_, 41 acceptor_->ssl_key_filename_, 42 use_npn, 43 acceptor_->ssl_session_expiry_, 44 acceptor_->ssl_disable_compression_); 45 use_ssl_ = true; 46 } 47} 48 49SMAcceptorThread::~SMAcceptorThread() { 50 for (std::vector<SMConnection*>::iterator i = 51 allocated_server_connections_.begin(); 52 i != allocated_server_connections_.end(); 53 ++i) { 54 delete *i; 55 } 56 delete ssl_state_; 57} 58 59SMConnection* SMAcceptorThread::NewConnection() { 60 SMConnection* server = SMConnection::NewSMConnection( 61 &epoll_server_, ssl_state_, memory_cache_, acceptor_, "client_conn: "); 62 allocated_server_connections_.push_back(server); 63 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Making new server."; 64 return server; 65} 66 67SMConnection* SMAcceptorThread::FindOrMakeNewSMConnection() { 68 if (unused_server_connections_.empty()) { 69 return NewConnection(); 70 } 71 SMConnection* server = unused_server_connections_.back(); 72 unused_server_connections_.pop_back(); 73 VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Reusing server."; 74 return server; 75} 76 77void SMAcceptorThread::InitWorker() { 78 epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET); 79} 80 81void SMAcceptorThread::HandleConnection(int server_fd, 82 struct sockaddr_in* remote_addr) { 83 int on = 1; 84 int rc; 85 if (acceptor_->disable_nagle_) { 86 rc = setsockopt(server_fd, 87 IPPROTO_TCP, 88 TCP_NODELAY, 89 reinterpret_cast<char*>(&on), 90 sizeof(on)); 91 if (rc < 0) { 92 close(server_fd); 93 LOG(ERROR) << "setsockopt() failed fd=" << server_fd; 94 return; 95 } 96 } 97 98 SMConnection* server_connection = FindOrMakeNewSMConnection(); 99 if (server_connection == NULL) { 100 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Closing fd " << server_fd; 101 close(server_fd); 102 return; 103 } 104 std::string remote_ip = inet_ntoa(remote_addr->sin_addr); 105 server_connection->InitSMConnection(this, 106 NULL, 107 &epoll_server_, 108 server_fd, 109 std::string(), 110 std::string(), 111 remote_ip, 112 use_ssl_); 113 if (server_connection->initialized()) 114 active_server_connections_.push_back(server_connection); 115} 116 117void SMAcceptorThread::AcceptFromListenFD() { 118 if (acceptor_->accepts_per_wake_ > 0) { 119 for (int i = 0; i < acceptor_->accepts_per_wake_; ++i) { 120 struct sockaddr address; 121 socklen_t socklen = sizeof(address); 122 int fd = accept(acceptor_->listen_fd_, &address, &socklen); 123 if (fd == -1) { 124 if (errno != 11) { 125 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail(" 126 << acceptor_->listen_fd_ << "): " << errno << ": " 127 << strerror(errno); 128 } 129 break; 130 } 131 VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection"; 132 HandleConnection(fd, (struct sockaddr_in*)&address); 133 } 134 } else { 135 while (true) { 136 struct sockaddr address; 137 socklen_t socklen = sizeof(address); 138 int fd = accept(acceptor_->listen_fd_, &address, &socklen); 139 if (fd == -1) { 140 if (errno != 11) { 141 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail(" 142 << acceptor_->listen_fd_ << "): " << errno << ": " 143 << strerror(errno); 144 } 145 break; 146 } 147 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection"; 148 HandleConnection(fd, (struct sockaddr_in*)&address); 149 } 150 } 151} 152 153void SMAcceptorThread::HandleConnectionIdleTimeout() { 154 static time_t oldest_time = time(NULL); 155 156 int cur_time = time(NULL); 157 // Only iterate the list if we speculate that a connection is ready to be 158 // expired 159 if ((cur_time - oldest_time) < idle_socket_timeout_s_) 160 return; 161 162 // TODO(mbelshe): This code could be optimized, active_server_connections_ 163 // is already in-order. 164 std::list<SMConnection*>::iterator iter = active_server_connections_.begin(); 165 while (iter != active_server_connections_.end()) { 166 SMConnection* conn = *iter; 167 int elapsed_time = (cur_time - conn->last_read_time_); 168 if (elapsed_time > idle_socket_timeout_s_) { 169 conn->Cleanup("Connection idle timeout reached."); 170 iter = active_server_connections_.erase(iter); 171 continue; 172 } 173 if (conn->last_read_time_ < oldest_time) 174 oldest_time = conn->last_read_time_; 175 iter++; 176 } 177 if ((cur_time - oldest_time) >= idle_socket_timeout_s_) 178 oldest_time = cur_time; 179} 180 181void SMAcceptorThread::Run() { 182 while (!quitting_.HasBeenNotified()) { 183 epoll_server_.set_timeout_in_us(10 * 1000); // 10 ms 184 epoll_server_.WaitForEventsAndExecuteCallbacks(); 185 if (tmp_unused_server_connections_.size()) { 186 VLOG(2) << "have " << tmp_unused_server_connections_.size() 187 << " additional unused connections. Total = " 188 << unused_server_connections_.size(); 189 unused_server_connections_.insert(unused_server_connections_.end(), 190 tmp_unused_server_connections_.begin(), 191 tmp_unused_server_connections_.end()); 192 tmp_unused_server_connections_.clear(); 193 } 194 HandleConnectionIdleTimeout(); 195 } 196} 197 198void SMAcceptorThread::OnEvent(int fd, EpollEvent* event) { 199 if (event->in_events | EPOLLIN) { 200 VLOG(2) << ACCEPTOR_CLIENT_IDENT 201 << "Acceptor: Accepting based upon epoll events"; 202 AcceptFromListenFD(); 203 } 204} 205 206void SMAcceptorThread::SMConnectionDone(SMConnection* sc) { 207 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection."; 208 tmp_unused_server_connections_.push_back(sc); 209} 210 211} // namespace net 212