1 // Copyright (c) 2009 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 "", "", remote_ip, 109 use_ssl_); 110 if (server_connection->initialized()) 111 active_server_connections_.push_back(server_connection); 112 } 113 114 void SMAcceptorThread::AcceptFromListenFD() { 115 if (acceptor_->accepts_per_wake_ > 0) { 116 for (int i = 0; i < acceptor_->accepts_per_wake_; ++i) { 117 struct sockaddr address; 118 socklen_t socklen = sizeof(address); 119 int fd = accept(acceptor_->listen_fd_, &address, &socklen); 120 if (fd == -1) { 121 if (errno != 11) { 122 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail(" 123 << acceptor_->listen_fd_ << "): " << errno << ": " 124 << strerror(errno); 125 } 126 break; 127 } 128 VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection"; 129 HandleConnection(fd, (struct sockaddr_in *)&address); 130 } 131 } else { 132 while (true) { 133 struct sockaddr address; 134 socklen_t socklen = sizeof(address); 135 int fd = accept(acceptor_->listen_fd_, &address, &socklen); 136 if (fd == -1) { 137 if (errno != 11) { 138 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail(" 139 << acceptor_->listen_fd_ << "): " << errno << ": " 140 << strerror(errno); 141 } 142 break; 143 } 144 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection"; 145 HandleConnection(fd, (struct sockaddr_in *)&address); 146 } 147 } 148 } 149 150 void SMAcceptorThread::HandleConnectionIdleTimeout() { 151 static time_t oldest_time = time(NULL); 152 153 int cur_time = time(NULL); 154 // Only iterate the list if we speculate that a connection is ready to be 155 // expired 156 if ((cur_time - oldest_time) < idle_socket_timeout_s_) 157 return; 158 159 // TODO(mbelshe): This code could be optimized, active_server_connections_ 160 // is already in-order. 161 std::list<SMConnection*>::iterator iter = active_server_connections_.begin(); 162 while (iter != active_server_connections_.end()) { 163 SMConnection *conn = *iter; 164 int elapsed_time = (cur_time - conn->last_read_time_); 165 if (elapsed_time > idle_socket_timeout_s_) { 166 conn->Cleanup("Connection idle timeout reached."); 167 iter = active_server_connections_.erase(iter); 168 continue; 169 } 170 if (conn->last_read_time_ < oldest_time) 171 oldest_time = conn->last_read_time_; 172 iter++; 173 } 174 if ((cur_time - oldest_time) >= idle_socket_timeout_s_) 175 oldest_time = cur_time; 176 } 177 178 void SMAcceptorThread::Run() { 179 while (!quitting_.HasBeenNotified()) { 180 epoll_server_.set_timeout_in_us(10 * 1000); // 10 ms 181 epoll_server_.WaitForEventsAndExecuteCallbacks(); 182 if (tmp_unused_server_connections_.size()) { 183 VLOG(2) << "have " << tmp_unused_server_connections_.size() 184 << " additional unused connections. Total = " 185 << unused_server_connections_.size(); 186 unused_server_connections_.insert(unused_server_connections_.end(), 187 tmp_unused_server_connections_.begin(), 188 tmp_unused_server_connections_.end()); 189 tmp_unused_server_connections_.clear(); 190 } 191 HandleConnectionIdleTimeout(); 192 } 193 } 194 195 void SMAcceptorThread::OnEvent(int fd, EpollEvent* event) { 196 if (event->in_events | EPOLLIN) { 197 VLOG(2) << ACCEPTOR_CLIENT_IDENT 198 << "Acceptor: Accepting based upon epoll events"; 199 AcceptFromListenFD(); 200 } 201 } 202 203 void SMAcceptorThread::SMConnectionDone(SMConnection* sc) { 204 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection."; 205 tmp_unused_server_connections_.push_back(sc); 206 } 207 208 } // namespace net 209 210 211