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 <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
    213