Home | History | Annotate | Download | only in flip_server
      1 // Copyright (c) 2009 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                                       "", "", remote_ip,
    109                                       use_ssl_);
    110   if (server_connection->initialized())
    111     active_server_connections_.push_back(server_connection);
    112 }
    113 
    114 void SMAcceptorThread::AcceptFromListenFD() {
    115   if (acceptor_->accepts_per_wake_ > 0) {
    116     for (int i = 0; i < acceptor_->accepts_per_wake_; ++i) {
    117       struct sockaddr address;
    118       socklen_t socklen = sizeof(address);
    119       int fd = accept(acceptor_->listen_fd_, &address, &socklen);
    120       if (fd == -1) {
    121         if (errno != 11) {
    122           VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
    123                   << acceptor_->listen_fd_ << "): " << errno << ": "
    124                   << strerror(errno);
    125         }
    126         break;
    127       }
    128       VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection";
    129       HandleConnection(fd, (struct sockaddr_in *)&address);
    130     }
    131   } else {
    132     while (true) {
    133       struct sockaddr address;
    134       socklen_t socklen = sizeof(address);
    135       int fd = accept(acceptor_->listen_fd_, &address, &socklen);
    136       if (fd == -1) {
    137         if (errno != 11) {
    138           VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
    139                   << acceptor_->listen_fd_ << "): " << errno << ": "
    140                   << strerror(errno);
    141         }
    142         break;
    143       }
    144       VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection";
    145       HandleConnection(fd, (struct sockaddr_in *)&address);
    146     }
    147   }
    148 }
    149 
    150 void SMAcceptorThread::HandleConnectionIdleTimeout() {
    151   static time_t oldest_time = time(NULL);
    152 
    153   int cur_time = time(NULL);
    154   // Only iterate the list if we speculate that a connection is ready to be
    155   // expired
    156   if ((cur_time - oldest_time) < idle_socket_timeout_s_)
    157     return;
    158 
    159   // TODO(mbelshe): This code could be optimized, active_server_connections_
    160   //                is already in-order.
    161   std::list<SMConnection*>::iterator iter = active_server_connections_.begin();
    162   while (iter != active_server_connections_.end()) {
    163     SMConnection *conn = *iter;
    164     int elapsed_time = (cur_time - conn->last_read_time_);
    165     if (elapsed_time > idle_socket_timeout_s_) {
    166       conn->Cleanup("Connection idle timeout reached.");
    167       iter = active_server_connections_.erase(iter);
    168       continue;
    169     }
    170     if (conn->last_read_time_ < oldest_time)
    171       oldest_time = conn->last_read_time_;
    172     iter++;
    173   }
    174   if ((cur_time - oldest_time) >= idle_socket_timeout_s_)
    175     oldest_time = cur_time;
    176 }
    177 
    178 void SMAcceptorThread::Run() {
    179   while (!quitting_.HasBeenNotified()) {
    180     epoll_server_.set_timeout_in_us(10 * 1000);  // 10 ms
    181     epoll_server_.WaitForEventsAndExecuteCallbacks();
    182     if (tmp_unused_server_connections_.size()) {
    183       VLOG(2) << "have " << tmp_unused_server_connections_.size()
    184               << " additional unused connections.  Total = "
    185               << unused_server_connections_.size();
    186       unused_server_connections_.insert(unused_server_connections_.end(),
    187                                         tmp_unused_server_connections_.begin(),
    188                                         tmp_unused_server_connections_.end());
    189       tmp_unused_server_connections_.clear();
    190     }
    191     HandleConnectionIdleTimeout();
    192   }
    193 }
    194 
    195 void SMAcceptorThread::OnEvent(int fd, EpollEvent* event) {
    196   if (event->in_events | EPOLLIN) {
    197     VLOG(2) << ACCEPTOR_CLIENT_IDENT
    198             << "Acceptor: Accepting based upon epoll events";
    199     AcceptFromListenFD();
    200   }
    201 }
    202 
    203 void SMAcceptorThread::SMConnectionDone(SMConnection* sc) {
    204   VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection.";
    205   tmp_unused_server_connections_.push_back(sc);
    206 }
    207 
    208 }  // namespace net
    209 
    210 
    211