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 <netinet/in.h>
8 #include <netinet/tcp.h> // For TCP_NODELAY
9 #include <sys/socket.h>
10 #include <sys/types.h>
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"
23 SMAcceptorThread::SMAcceptorThread(FlipAcceptor
*acceptor
,
24 MemoryCache
* memory_cache
)
25 : SimpleThread("SMAcceptorThread"),
29 idle_socket_timeout_s_(acceptor
->idle_socket_timeout_s_
),
31 memory_cache_(memory_cache
) {
32 if (!acceptor
->ssl_cert_filename_
.empty() &&
33 !acceptor
->ssl_key_filename_
.empty()) {
34 ssl_state_
= new SSLState
;
36 if (acceptor_
->flip_handler_type_
== FLIP_HANDLER_HTTP_SERVER
) {
40 acceptor_
->ssl_cert_filename_
,
41 acceptor_
->ssl_key_filename_
,
43 acceptor_
->ssl_session_expiry_
,
44 acceptor_
->ssl_disable_compression_
);
49 SMAcceptorThread::~SMAcceptorThread() {
50 for (std::vector
<SMConnection
*>::iterator i
=
51 allocated_server_connections_
.begin();
52 i
!= allocated_server_connections_
.end();
59 SMConnection
* SMAcceptorThread::NewConnection() {
60 SMConnection
* server
=
61 SMConnection::NewSMConnection(&epoll_server_
, ssl_state_
,
62 memory_cache_
, acceptor_
,
64 allocated_server_connections_
.push_back(server
);
65 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: Making new server.";
69 SMConnection
* SMAcceptorThread::FindOrMakeNewSMConnection() {
70 if (unused_server_connections_
.empty()) {
71 return NewConnection();
73 SMConnection
* server
= unused_server_connections_
.back();
74 unused_server_connections_
.pop_back();
75 VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: Reusing server.";
79 void SMAcceptorThread::InitWorker() {
80 epoll_server_
.RegisterFD(acceptor_
->listen_fd_
, this, EPOLLIN
| EPOLLET
);
83 void SMAcceptorThread::HandleConnection(int server_fd
,
84 struct sockaddr_in
*remote_addr
) {
87 if (acceptor_
->disable_nagle_
) {
88 rc
= setsockopt(server_fd
, IPPROTO_TCP
, TCP_NODELAY
,
89 reinterpret_cast<char*>(&on
), sizeof(on
));
92 LOG(ERROR
) << "setsockopt() failed fd=" << server_fd
;
97 SMConnection
* server_connection
= FindOrMakeNewSMConnection();
98 if (server_connection
== NULL
) {
99 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: Closing fd " << server_fd
;
103 std::string remote_ip
= inet_ntoa(remote_addr
->sin_addr
);
104 server_connection
->InitSMConnection(this,
112 if (server_connection
->initialized())
113 active_server_connections_
.push_back(server_connection
);
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
);
124 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: accept fail("
125 << acceptor_
->listen_fd_
<< "): " << errno
<< ": "
130 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< " Accepted connection";
131 HandleConnection(fd
, (struct sockaddr_in
*)&address
);
135 struct sockaddr address
;
136 socklen_t socklen
= sizeof(address
);
137 int fd
= accept(acceptor_
->listen_fd_
, &address
, &socklen
);
140 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Acceptor: accept fail("
141 << acceptor_
->listen_fd_
<< "): " << errno
<< ": "
146 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Accepted connection";
147 HandleConnection(fd
, (struct sockaddr_in
*)&address
);
152 void SMAcceptorThread::HandleConnectionIdleTimeout() {
153 static time_t oldest_time
= time(NULL
);
155 int cur_time
= time(NULL
);
156 // Only iterate the list if we speculate that a connection is ready to be
158 if ((cur_time
- oldest_time
) < idle_socket_timeout_s_
)
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
);
172 if (conn
->last_read_time_
< oldest_time
)
173 oldest_time
= conn
->last_read_time_
;
176 if ((cur_time
- oldest_time
) >= idle_socket_timeout_s_
)
177 oldest_time
= cur_time
;
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();
193 HandleConnectionIdleTimeout();
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();
205 void SMAcceptorThread::SMConnectionDone(SMConnection
* sc
) {
206 VLOG(1) << ACCEPTOR_CLIENT_IDENT
<< "Done with connection.";
207 tmp_unused_server_connections_
.push_back(sc
);