OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/tools/flip_server/acceptor_thread.h" | |
6 | |
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> | |
12 | |
13 #include <string> | |
14 | |
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" | |
21 | |
22 namespace net { | |
23 | |
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; | |
39 } | |
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; | |
47 } | |
48 } | |
49 | |
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; | |
56 } | |
57 delete ssl_state_; | |
58 } | |
59 | |
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; | |
66 } | |
67 | |
68 SMConnection* SMAcceptorThread::FindOrMakeNewSMConnection() { | |
69 if (unused_server_connections_.empty()) { | |
70 return NewConnection(); | |
71 } | |
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; | |
76 } | |
77 | |
78 void SMAcceptorThread::InitWorker() { | |
79 epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET); | |
80 } | |
81 | |
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; | |
96 } | |
97 } | |
98 | |
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; | |
104 } | |
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); | |
116 } | |
117 | |
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); | |
129 } | |
130 break; | |
131 } | |
132 VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection"; | |
133 HandleConnection(fd, (struct sockaddr_in*)&address); | |
134 } | |
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); | |
145 } | |
146 break; | |
147 } | |
148 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection"; | |
149 HandleConnection(fd, (struct sockaddr_in*)&address); | |
150 } | |
151 } | |
152 } | |
153 | |
154 void SMAcceptorThread::HandleConnectionIdleTimeout() { | |
155 static time_t oldest_time = time(NULL); | |
156 | |
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; | |
162 | |
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; | |
173 } | |
174 if (conn->last_read_time_ < oldest_time) | |
175 oldest_time = conn->last_read_time_; | |
176 iter++; | |
177 } | |
178 if ((cur_time - oldest_time) >= idle_socket_timeout_s_) | |
179 oldest_time = cur_time; | |
180 } | |
181 | |
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(); | |
194 } | |
195 HandleConnectionIdleTimeout(); | |
196 } | |
197 } | |
198 | |
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(); | |
204 } | |
205 } | |
206 | |
207 void SMAcceptorThread::SMConnectionDone(SMConnection* sc) { | |
208 VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection."; | |
209 tmp_unused_server_connections_.push_back(sc); | |
210 } | |
211 | |
212 } // namespace net | |
OLD | NEW |