Home | History | Annotate | Download | only in flip_server
      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 <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 
     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 
     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 
     59 SMConnection* SMAcceptorThread::NewConnection() {
     60   SMConnection* server = SMConnection::NewSMConnection(
     61       &epoll_server_, ssl_state_, memory_cache_, acceptor_, "client_conn: ");
     62   allocated_server_connections_.push_back(server);
     63   VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Making new server.";
     64   return server;
     65 }
     66 
     67 SMConnection* SMAcceptorThread::FindOrMakeNewSMConnection() {
     68   if (unused_server_connections_.empty()) {
     69     return NewConnection();
     70   }
     71   SMConnection* server = unused_server_connections_.back();
     72   unused_server_connections_.pop_back();
     73   VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Reusing server.";
     74   return server;
     75 }
     76 
     77 void SMAcceptorThread::InitWorker() {
     78   epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET);
     79 }
     80 
     81 void SMAcceptorThread::HandleConnection(int server_fd,
     82                                         struct sockaddr_in* remote_addr) {
     83   int on = 1;
     84   int rc;
     85   if (acceptor_->disable_nagle_) {
     86     rc = setsockopt(server_fd,
     87                     IPPROTO_TCP,
     88                     TCP_NODELAY,
     89                     reinterpret_cast<char*>(&on),
     90                     sizeof(on));
     91     if (rc < 0) {
     92       close(server_fd);
     93       LOG(ERROR) << "setsockopt() failed fd=" << server_fd;
     94       return;
     95     }
     96   }
     97 
     98   SMConnection* server_connection = FindOrMakeNewSMConnection();
     99   if (server_connection == NULL) {
    100     VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Closing fd " << server_fd;
    101     close(server_fd);
    102     return;
    103   }
    104   std::string remote_ip = inet_ntoa(remote_addr->sin_addr);
    105   server_connection->InitSMConnection(this,
    106                                       NULL,
    107                                       &epoll_server_,
    108                                       server_fd,
    109                                       std::string(),
    110                                       std::string(),
    111                                       remote_ip,
    112                                       use_ssl_);
    113   if (server_connection->initialized())
    114     active_server_connections_.push_back(server_connection);
    115 }
    116 
    117 void SMAcceptorThread::AcceptFromListenFD() {
    118   if (acceptor_->accepts_per_wake_ > 0) {
    119     for (int i = 0; i < acceptor_->accepts_per_wake_; ++i) {
    120       struct sockaddr address;
    121       socklen_t socklen = sizeof(address);
    122       int fd = accept(acceptor_->listen_fd_, &address, &socklen);
    123       if (fd == -1) {
    124         if (errno != 11) {
    125           VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
    126                   << acceptor_->listen_fd_ << "): " << errno << ": "
    127                   << strerror(errno);
    128         }
    129         break;
    130       }
    131       VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection";
    132       HandleConnection(fd, (struct sockaddr_in*)&address);
    133     }
    134   } else {
    135     while (true) {
    136       struct sockaddr address;
    137       socklen_t socklen = sizeof(address);
    138       int fd = accept(acceptor_->listen_fd_, &address, &socklen);
    139       if (fd == -1) {
    140         if (errno != 11) {
    141           VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
    142                   << acceptor_->listen_fd_ << "): " << errno << ": "
    143                   << strerror(errno);
    144         }
    145         break;
    146       }
    147       VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection";
    148       HandleConnection(fd, (struct sockaddr_in*)&address);
    149     }
    150   }
    151 }
    152 
    153 void SMAcceptorThread::HandleConnectionIdleTimeout() {
    154   static time_t oldest_time = time(NULL);
    155 
    156   int cur_time = time(NULL);
    157   // Only iterate the list if we speculate that a connection is ready to be
    158   // expired
    159   if ((cur_time - oldest_time) < idle_socket_timeout_s_)
    160     return;
    161 
    162   // TODO(mbelshe): This code could be optimized, active_server_connections_
    163   //                is already in-order.
    164   std::list<SMConnection*>::iterator iter = active_server_connections_.begin();
    165   while (iter != active_server_connections_.end()) {
    166     SMConnection* conn = *iter;
    167     int elapsed_time = (cur_time - conn->last_read_time_);
    168     if (elapsed_time > idle_socket_timeout_s_) {
    169       conn->Cleanup("Connection idle timeout reached.");
    170       iter = active_server_connections_.erase(iter);
    171       continue;
    172     }
    173     if (conn->last_read_time_ < oldest_time)
    174       oldest_time = conn->last_read_time_;
    175     iter++;
    176   }
    177   if ((cur_time - oldest_time) >= idle_socket_timeout_s_)
    178     oldest_time = cur_time;
    179 }
    180 
    181 void SMAcceptorThread::Run() {
    182   while (!quitting_.HasBeenNotified()) {
    183     epoll_server_.set_timeout_in_us(10 * 1000);  // 10 ms
    184     epoll_server_.WaitForEventsAndExecuteCallbacks();
    185     if (tmp_unused_server_connections_.size()) {
    186       VLOG(2) << "have " << tmp_unused_server_connections_.size()
    187               << " additional unused connections.  Total = "
    188               << unused_server_connections_.size();
    189       unused_server_connections_.insert(unused_server_connections_.end(),
    190                                         tmp_unused_server_connections_.begin(),
    191                                         tmp_unused_server_connections_.end());
    192       tmp_unused_server_connections_.clear();
    193     }
    194     HandleConnectionIdleTimeout();
    195   }
    196 }
    197 
    198 void SMAcceptorThread::OnEvent(int fd, EpollEvent* event) {
    199   if (event->in_events | EPOLLIN) {
    200     VLOG(2) << ACCEPTOR_CLIENT_IDENT
    201             << "Acceptor: Accepting based upon epoll events";
    202     AcceptFromListenFD();
    203   }
    204 }
    205 
    206 void SMAcceptorThread::SMConnectionDone(SMConnection* sc) {
    207   VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection.";
    208   tmp_unused_server_connections_.push_back(sc);
    209 }
    210 
    211 }  // namespace net
    212