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
SMAcceptorThread(FlipAcceptor * acceptor,MemoryCache * memory_cache)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
~SMAcceptorThread()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
NewConnection()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
FindOrMakeNewSMConnection()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
InitWorker()79 void SMAcceptorThread::InitWorker() {
80 epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET);
81 }
82
HandleConnection(int server_fd,struct sockaddr_in * remote_addr)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
AcceptFromListenFD()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
HandleConnectionIdleTimeout()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
Run()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
OnEvent(int fd,EpollEvent * event)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
SMConnectionDone(SMConnection * sc)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