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