Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / tools / flip_server / acceptor_thread.cc
blob2b65e5d43afe7cd524e4cc83f0a3316ac6fabf57
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.
5 #include "net/tools/flip_server/acceptor_thread.h"
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>
13 #include <string>
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"
22 namespace net {
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;
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;
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;
57 delete ssl_state_;
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;
68 SMConnection* SMAcceptorThread::FindOrMakeNewSMConnection() {
69 if (unused_server_connections_.empty()) {
70 return NewConnection();
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;
78 void SMAcceptorThread::InitWorker() {
79 epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET);
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;
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;
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);
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);
130 break;
132 VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection";
133 HandleConnection(fd, (struct sockaddr_in*)&address);
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);
146 break;
148 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection";
149 HandleConnection(fd, (struct sockaddr_in*)&address);
154 void SMAcceptorThread::HandleConnectionIdleTimeout() {
155 static time_t oldest_time = time(NULL);
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;
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;
174 if (conn->last_read_time_ < oldest_time)
175 oldest_time = conn->last_read_time_;
176 iter++;
178 if ((cur_time - oldest_time) >= idle_socket_timeout_s_)
179 oldest_time = cur_time;
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();
195 HandleConnectionIdleTimeout();
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();
207 void SMAcceptorThread::SMConnectionDone(SMConnection* sc) {
208 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection.";
209 tmp_unused_server_connections_.push_back(sc);
212 } // namespace net