Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / tools / flip_server / acceptor_thread.cc
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