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