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"
8 #include <netinet/in.h>
9 #include <netinet/tcp.h> // For TCP_NODELAY
10 #include <sys/socket.h>
11 #include <sys/types.h>
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"
24 SMAcceptorThread::SMAcceptorThread(FlipAcceptor
* acceptor
,
25 MemoryCache
* memory_cache
)
26 : SimpleThread("SMAcceptorThread"),
30 idle_socket_timeout_s_(acceptor
->idle_socket_timeout_s_
),
32 memory_cache_(memory_cache
) {
33 if (!acceptor
->ssl_cert_filename_
.empty() &&
34 !acceptor
->ssl_key_filename_
.empty()) {
35 ssl_state_
= new SSLState
;
37 if (acceptor_
->flip_handler_type_
== FLIP_HANDLER_HTTP_SERVER
) {
41 acceptor_
->ssl_cert_filename_
,
42 acceptor_
->ssl_key_filename_
,
44 acceptor_
->ssl_session_expiry_
,
45 acceptor_
->ssl_disable_compression_
);
50 SMAcceptorThread::~SMAcceptorThread() {
51 for (std::vector
<SMConnection
*>::iterator i
=
52 allocated_server_connections_
.begin();
53 i
!= allocated_server_connections_
.end();
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.";
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.";
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
) {
86 if (acceptor_
->disable_nagle_
) {
87 rc
= setsockopt(server_fd
,
90 reinterpret_cast<char*>(&on
),
94 LOG(ERROR
) << "setsockopt() failed fd=" << server_fd
;
99 SMConnection
* server_connection
= FindOrMakeNewSMConnection();
100 if (server_connection
== NULL
) {
101 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: Closing fd " << server_fd
;
105 std::string remote_ip
= inet_ntoa(remote_addr
->sin_addr
);
106 server_connection
->InitSMConnection(this,
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
);
126 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: accept fail("
127 << acceptor_
->listen_fd_
<< "): " << errno
<< ": "
132 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< " Accepted connection";
133 HandleConnection(fd
, (struct sockaddr_in
*)&address
);
137 struct sockaddr address
;
138 socklen_t socklen
= sizeof(address
);
139 int fd
= accept(acceptor_
->listen_fd_
, &address
, &socklen
);
142 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: accept fail("
143 << acceptor_
->listen_fd_
<< "): " << errno
<< ": "
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
160 if ((cur_time
- oldest_time
) < idle_socket_timeout_s_
)
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
);
174 if (conn
->last_read_time_
< oldest_time
)
175 oldest_time
= conn
->last_read_time_
;
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
);