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 =
     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 
     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 
     79 void SMAcceptorThread::InitWorker() {
     80   epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET);
     81 }
     82 
     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                                       std::string(),
    109                                       std::string(),
    110                                       remote_ip,
    111                                       use_ssl_);
    112   if (server_connection->initialized())
    113     active_server_connections_.push_back(server_connection);
    114 }
    115 
    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);
    122       if (fd == -1) {
    123         if (errno != 11) {
    124           VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
    125                   << acceptor_->listen_fd_ << "): " << errno << ": "
    126                   << strerror(errno);
    127         }
    128         break;
    129       }
    130       VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection";
    131       HandleConnection(fd, (struct sockaddr_in *)&address);
    132     }
    133   } else {
    134     while (true) {
    135       struct sockaddr address;
    136       socklen_t socklen = sizeof(address);
    137       int fd = accept(acceptor_->listen_fd_, &address, &socklen);
    138       if (fd == -1) {
    139         if (errno != 11) {
    140           VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
    141                   << acceptor_->listen_fd_ << "): " << errno << ": "
    142                   << strerror(errno);
    143         }
    144         break;
    145       }
    146       VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection";
    147       HandleConnection(fd, (struct sockaddr_in *)&address);
    148     }
    149   }
    150 }
    151 
    152 void SMAcceptorThread::HandleConnectionIdleTimeout() {
    153   static time_t oldest_time = time(NULL);
    154 
    155   int cur_time = time(NULL);
    156   // Only iterate the list if we speculate that a connection is ready to be
    157   // expired
    158   if ((cur_time - oldest_time) < idle_socket_timeout_s_)
    159     return;
    160 
    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);
    170       continue;
    171     }
    172     if (conn->last_read_time_ < oldest_time)
    173       oldest_time = conn->last_read_time_;
    174     iter++;
    175   }
    176   if ((cur_time - oldest_time) >= idle_socket_timeout_s_)
    177     oldest_time = cur_time;
    178 }
    179 
    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();
    192     }
    193     HandleConnectionIdleTimeout();
    194   }
    195 }
    196 
    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();
    202   }
    203 }
    204 
    205 void SMAcceptorThread::SMConnectionDone(SMConnection* sc) {
    206   VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection.";
    207   tmp_unused_server_connections_.push_back(sc);
    208 }
    209 
    210 }  // namespace net
    211 
    212 
    213