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/sm_connection.h" 6 7#include <errno.h> 8#include <netinet/tcp.h> 9#include <sys/socket.h> 10#include <unistd.h> 11 12#include <algorithm> 13#include <list> 14#include <string> 15 16#include "net/tools/flip_server/constants.h" 17#include "net/tools/flip_server/flip_config.h" 18#include "net/tools/flip_server/http_interface.h" 19#include "net/tools/flip_server/spdy_interface.h" 20#include "net/tools/flip_server/spdy_ssl.h" 21#include "net/tools/flip_server/streamer_interface.h" 22 23namespace net { 24 25// static 26bool SMConnection::force_spdy_ = false; 27 28DataFrame::~DataFrame() { 29 if (delete_when_done) 30 delete[] data; 31} 32 33SMConnection::SMConnection(EpollServer* epoll_server, 34 SSLState* ssl_state, 35 MemoryCache* memory_cache, 36 FlipAcceptor* acceptor, 37 std::string log_prefix) 38 : last_read_time_(0), 39 fd_(-1), 40 events_(0), 41 registered_in_epoll_server_(false), 42 initialized_(false), 43 protocol_detected_(false), 44 connection_complete_(false), 45 connection_pool_(NULL), 46 epoll_server_(epoll_server), 47 ssl_state_(ssl_state), 48 memory_cache_(memory_cache), 49 acceptor_(acceptor), 50 read_buffer_(kSpdySegmentSize * 40), 51 sm_spdy_interface_(NULL), 52 sm_http_interface_(NULL), 53 sm_streamer_interface_(NULL), 54 sm_interface_(NULL), 55 log_prefix_(log_prefix), 56 max_bytes_sent_per_dowrite_(4096), 57 ssl_(NULL) {} 58 59SMConnection::~SMConnection() { 60 if (initialized()) 61 Reset(); 62} 63 64EpollServer* SMConnection::epoll_server() { return epoll_server_; } 65 66void SMConnection::ReadyToSend() { 67 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 68 << "Setting ready to send: EPOLLIN | EPOLLOUT"; 69 epoll_server_->SetFDReady(fd_, EPOLLIN | EPOLLOUT); 70} 71 72void SMConnection::EnqueueDataFrame(DataFrame* df) { 73 output_list_.push_back(df); 74 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "EnqueueDataFrame: " 75 << "size = " << df->size << ": Setting FD ready."; 76 ReadyToSend(); 77} 78 79void SMConnection::InitSMConnection(SMConnectionPoolInterface* connection_pool, 80 SMInterface* sm_interface, 81 EpollServer* epoll_server, 82 int fd, 83 std::string server_ip, 84 std::string server_port, 85 std::string remote_ip, 86 bool use_ssl) { 87 if (initialized_) { 88 LOG(FATAL) << "Attempted to initialize already initialized server"; 89 return; 90 } 91 92 client_ip_ = remote_ip; 93 94 if (fd == -1) { 95 // If fd == -1, then we are initializing a new connection that will 96 // connect to the backend. 97 // 98 // ret: -1 == error 99 // 0 == connection in progress 100 // 1 == connection complete 101 // TODO(kelindsay): is_numeric_host_address value needs to be detected 102 server_ip_ = server_ip; 103 server_port_ = server_port; 104 int ret = CreateConnectedSocket( 105 &fd_, server_ip, server_port, true, acceptor_->disable_nagle_); 106 107 if (ret < 0) { 108 LOG(ERROR) << "-1 Could not create connected socket"; 109 return; 110 } else if (ret == 1) { 111 DCHECK_NE(-1, fd_); 112 connection_complete_ = true; 113 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 114 << "Connection complete to: " << server_ip_ << ":" << server_port_ 115 << " "; 116 } 117 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 118 << "Connecting to server: " << server_ip_ << ":" << server_port_ 119 << " "; 120 } else { 121 // If fd != -1 then we are initializing a connection that has just been 122 // accepted from the listen socket. 123 connection_complete_ = true; 124 if (epoll_server_ && registered_in_epoll_server_ && fd_ != -1) { 125 epoll_server_->UnregisterFD(fd_); 126 } 127 if (fd_ != -1) { 128 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 129 << "Closing pre-existing fd"; 130 close(fd_); 131 fd_ = -1; 132 } 133 134 fd_ = fd; 135 } 136 137 registered_in_epoll_server_ = false; 138 // Set the last read time here as the idle checker will start from 139 // now. 140 last_read_time_ = time(NULL); 141 initialized_ = true; 142 143 connection_pool_ = connection_pool; 144 epoll_server_ = epoll_server; 145 146 if (sm_interface) { 147 sm_interface_ = sm_interface; 148 protocol_detected_ = true; 149 } 150 151 read_buffer_.Clear(); 152 153 epoll_server_->RegisterFD(fd_, this, EPOLLIN | EPOLLOUT | EPOLLET); 154 155 if (use_ssl) { 156 ssl_ = CreateSSLContext(ssl_state_->ssl_ctx); 157 SSL_set_fd(ssl_, fd_); 158 PrintSslError(); 159 } 160} 161 162void SMConnection::CorkSocket() { 163 int state = 1; 164 int rv = setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); 165 if (rv < 0) 166 VLOG(1) << "setsockopt(CORK): " << errno; 167} 168 169void SMConnection::UncorkSocket() { 170 int state = 0; 171 int rv = setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); 172 if (rv < 0) 173 VLOG(1) << "setsockopt(CORK): " << errno; 174} 175 176int SMConnection::Send(const char* data, int len, int flags) { 177 int rv = 0; 178 CorkSocket(); 179 if (ssl_) { 180 ssize_t bytes_written = 0; 181 // Write smallish chunks to SSL so that we don't have large 182 // multi-packet TLS records to receive before being able to handle 183 // the data. We don't have to be too careful here, because our data 184 // frames are already getting chunked appropriately, and those are 185 // the most likely "big" frames. 186 while (len > 0) { 187 const int kMaxTLSRecordSize = 1500; 188 const char* ptr = &(data[bytes_written]); 189 int chunksize = std::min(len, kMaxTLSRecordSize); 190 rv = SSL_write(ssl_, ptr, chunksize); 191 VLOG(2) << "SSLWrite(" << chunksize << " bytes): " << rv; 192 if (rv <= 0) { 193 switch (SSL_get_error(ssl_, rv)) { 194 case SSL_ERROR_WANT_READ: 195 case SSL_ERROR_WANT_WRITE: 196 case SSL_ERROR_WANT_ACCEPT: 197 case SSL_ERROR_WANT_CONNECT: 198 rv = -2; 199 break; 200 default: 201 PrintSslError(); 202 break; 203 } 204 break; 205 } 206 bytes_written += rv; 207 len -= rv; 208 if (rv != chunksize) 209 break; // If we couldn't write everything, we're implicitly stalled 210 } 211 // If we wrote some data, return that count. Otherwise 212 // return the stall error. 213 if (bytes_written > 0) 214 rv = bytes_written; 215 } else { 216 rv = send(fd_, data, len, flags); 217 } 218 if (!(flags & MSG_MORE)) 219 UncorkSocket(); 220 return rv; 221} 222 223void SMConnection::OnRegistration(EpollServer* eps, int fd, int event_mask) { 224 registered_in_epoll_server_ = true; 225} 226 227void SMConnection::OnEvent(int fd, EpollEvent* event) { 228 events_ |= event->in_events; 229 HandleEvents(); 230 if (events_) { 231 event->out_ready_mask = events_; 232 events_ = 0; 233 } 234} 235 236void SMConnection::OnUnregistration(int fd, bool replaced) { 237 registered_in_epoll_server_ = false; 238} 239 240void SMConnection::OnShutdown(EpollServer* eps, int fd) { 241 Cleanup("OnShutdown"); 242 return; 243} 244 245void SMConnection::Cleanup(const char* cleanup) { 246 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Cleanup: " << cleanup; 247 if (!initialized_) 248 return; 249 Reset(); 250 if (connection_pool_) 251 connection_pool_->SMConnectionDone(this); 252 if (sm_interface_) 253 sm_interface_->ResetForNewConnection(); 254 last_read_time_ = 0; 255} 256 257void SMConnection::HandleEvents() { 258 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 259 << "Received: " << EpollServer::EventMaskToString(events_).c_str(); 260 261 if (events_ & EPOLLIN) { 262 if (!DoRead()) 263 goto handle_close_or_error; 264 } 265 266 if (events_ & EPOLLOUT) { 267 // Check if we have connected or not 268 if (connection_complete_ == false) { 269 int sock_error; 270 socklen_t sock_error_len = sizeof(sock_error); 271 int ret = 272 getsockopt(fd_, SOL_SOCKET, SO_ERROR, &sock_error, &sock_error_len); 273 if (ret != 0) { 274 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 275 << "getsockopt error: " << errno << ": " << strerror(errno); 276 goto handle_close_or_error; 277 } 278 if (sock_error == 0) { 279 connection_complete_ = true; 280 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 281 << "Connection complete to " << server_ip_ << ":" 282 << server_port_ << " "; 283 } else if (sock_error == EINPROGRESS) { 284 return; 285 } else { 286 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 287 << "error connecting to server"; 288 goto handle_close_or_error; 289 } 290 } 291 if (!DoWrite()) 292 goto handle_close_or_error; 293 } 294 295 if (events_ & (EPOLLHUP | EPOLLERR)) { 296 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "!!! Got HUP or ERR"; 297 goto handle_close_or_error; 298 } 299 return; 300 301 handle_close_or_error: 302 Cleanup("HandleEvents"); 303} 304 305// Decide if SPDY was negotiated. 306bool SMConnection::WasSpdyNegotiated(SpdyMajorVersion* version_negotiated) { 307 *version_negotiated = SPDY3; 308 if (force_spdy()) 309 return true; 310 311 // If this is an SSL connection, check if NPN specifies SPDY. 312 if (ssl_) { 313 const unsigned char* npn_proto; 314 unsigned int npn_proto_len; 315 SSL_get0_next_proto_negotiated(ssl_, &npn_proto, &npn_proto_len); 316 if (npn_proto_len > 0) { 317 std::string npn_proto_str((const char*)npn_proto, npn_proto_len); 318 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 319 << "NPN protocol detected: " << npn_proto_str; 320 if (!strncmp(reinterpret_cast<const char*>(npn_proto), 321 "spdy/2", 322 npn_proto_len)) { 323 *version_negotiated = SPDY2; 324 return true; 325 } 326 if (!strncmp(reinterpret_cast<const char*>(npn_proto), 327 "spdy/3", 328 npn_proto_len)) { 329 *version_negotiated = SPDY3; 330 return true; 331 } 332 if (!strncmp(reinterpret_cast<const char*>(npn_proto), 333 "spdy/4a2", 334 npn_proto_len)) { 335 *version_negotiated = SPDY4; 336 return true; 337 } 338 } 339 } 340 341 return false; 342} 343 344bool SMConnection::SetupProtocolInterfaces() { 345 DCHECK(!protocol_detected_); 346 protocol_detected_ = true; 347 348 SpdyMajorVersion version; 349 bool spdy_negotiated = WasSpdyNegotiated(&version); 350 bool using_ssl = ssl_ != NULL; 351 352 if (using_ssl) 353 VLOG(1) << (SSL_session_reused(ssl_) ? "Resumed" : "Renegotiated") 354 << " SSL Session."; 355 356 if (acceptor_->spdy_only_ && !spdy_negotiated) { 357 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 358 << "SPDY proxy only, closing HTTPS connection."; 359 return false; 360 } 361 362 switch (acceptor_->flip_handler_type_) { 363 case FLIP_HANDLER_HTTP_SERVER: { 364 DCHECK(!spdy_negotiated); 365 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 366 << (sm_http_interface_ ? "Creating" : "Reusing") 367 << " HTTP interface."; 368 if (!sm_http_interface_) 369 sm_http_interface_ = new HttpSM(this, NULL, memory_cache_, acceptor_); 370 sm_interface_ = sm_http_interface_; 371 break; 372 } 373 case FLIP_HANDLER_PROXY: { 374 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 375 << (sm_streamer_interface_ ? "Creating" : "Reusing") 376 << " PROXY Streamer interface."; 377 if (!sm_streamer_interface_) { 378 sm_streamer_interface_ = 379 new StreamerSM(this, NULL, epoll_server_, acceptor_); 380 sm_streamer_interface_->set_is_request(); 381 } 382 sm_interface_ = sm_streamer_interface_; 383 // If spdy is not negotiated, the streamer interface will proxy all 384 // data to the origin server. 385 if (!spdy_negotiated) 386 break; 387 } 388 // Otherwise fall through into the case below. 389 case FLIP_HANDLER_SPDY_SERVER: { 390 DCHECK(spdy_negotiated); 391 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 392 << (sm_spdy_interface_ ? "Creating" : "Reusing") 393 << " SPDY interface."; 394 if (sm_spdy_interface_) 395 sm_spdy_interface_->CreateFramer(version); 396 else 397 sm_spdy_interface_ = new SpdySM( 398 this, NULL, epoll_server_, memory_cache_, acceptor_, version); 399 sm_interface_ = sm_spdy_interface_; 400 break; 401 } 402 } 403 404 CorkSocket(); 405 if (!sm_interface_->PostAcceptHook()) 406 return false; 407 408 return true; 409} 410 411bool SMConnection::DoRead() { 412 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "DoRead()"; 413 while (!read_buffer_.Full()) { 414 char* bytes; 415 int size; 416 if (fd_ == -1) { 417 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 418 << "DoRead(): fd_ == -1. Invalid FD. Returning false"; 419 return false; 420 } 421 read_buffer_.GetWritablePtr(&bytes, &size); 422 ssize_t bytes_read = 0; 423 if (ssl_) { 424 bytes_read = SSL_read(ssl_, bytes, size); 425 if (bytes_read < 0) { 426 int err = SSL_get_error(ssl_, bytes_read); 427 switch (err) { 428 case SSL_ERROR_WANT_READ: 429 case SSL_ERROR_WANT_WRITE: 430 case SSL_ERROR_WANT_ACCEPT: 431 case SSL_ERROR_WANT_CONNECT: 432 events_ &= ~EPOLLIN; 433 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 434 << "DoRead: SSL WANT_XXX: " << err; 435 goto done; 436 default: 437 PrintSslError(); 438 goto error_or_close; 439 } 440 } 441 } else { 442 bytes_read = recv(fd_, bytes, size, MSG_DONTWAIT); 443 } 444 int stored_errno = errno; 445 if (bytes_read == -1) { 446 switch (stored_errno) { 447 case EAGAIN: 448 events_ &= ~EPOLLIN; 449 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 450 << "Got EAGAIN while reading"; 451 goto done; 452 case EINTR: 453 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 454 << "Got EINTR while reading"; 455 continue; 456 default: 457 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 458 << "While calling recv, got error: " 459 << (ssl_ ? "(ssl error)" : strerror(stored_errno)); 460 goto error_or_close; 461 } 462 } else if (bytes_read > 0) { 463 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "read " << bytes_read 464 << " bytes"; 465 last_read_time_ = time(NULL); 466 // If the protocol hasn't been detected yet, set up the handlers 467 // we'll need. 468 if (!protocol_detected_) { 469 if (!SetupProtocolInterfaces()) { 470 LOG(ERROR) << "Error setting up protocol interfaces."; 471 goto error_or_close; 472 } 473 } 474 read_buffer_.AdvanceWritablePtr(bytes_read); 475 if (!DoConsumeReadData()) 476 goto error_or_close; 477 continue; 478 } else { // bytes_read == 0 479 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 480 << "0 bytes read with recv call."; 481 } 482 goto error_or_close; 483 } 484 done: 485 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "DoRead done!"; 486 return true; 487 488 error_or_close: 489 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 490 << "DoRead(): error_or_close. " 491 << "Cleaning up, then returning false"; 492 Cleanup("DoRead"); 493 return false; 494} 495 496bool SMConnection::DoConsumeReadData() { 497 char* bytes; 498 int size; 499 read_buffer_.GetReadablePtr(&bytes, &size); 500 while (size != 0) { 501 size_t bytes_consumed = sm_interface_->ProcessReadInput(bytes, size); 502 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "consumed " 503 << bytes_consumed << " bytes"; 504 if (bytes_consumed == 0) { 505 break; 506 } 507 read_buffer_.AdvanceReadablePtr(bytes_consumed); 508 if (sm_interface_->MessageFullyRead()) { 509 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 510 << "HandleRequestFullyRead: Setting EPOLLOUT"; 511 HandleResponseFullyRead(); 512 events_ |= EPOLLOUT; 513 } else if (sm_interface_->Error()) { 514 LOG(ERROR) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 515 << "Framer error detected: Setting EPOLLOUT: " 516 << sm_interface_->ErrorAsString(); 517 // this causes everything to be closed/cleaned up. 518 events_ |= EPOLLOUT; 519 return false; 520 } 521 read_buffer_.GetReadablePtr(&bytes, &size); 522 } 523 return true; 524} 525 526void SMConnection::HandleResponseFullyRead() { sm_interface_->Cleanup(); } 527 528bool SMConnection::DoWrite() { 529 size_t bytes_sent = 0; 530 int flags = MSG_NOSIGNAL | MSG_DONTWAIT; 531 if (fd_ == -1) { 532 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 533 << "DoWrite: fd == -1. Returning false."; 534 return false; 535 } 536 if (output_list_.empty()) { 537 VLOG(2) << log_prefix_ << "DoWrite: Output list empty."; 538 if (sm_interface_) { 539 sm_interface_->GetOutput(); 540 } 541 if (output_list_.empty()) { 542 events_ &= ~EPOLLOUT; 543 } 544 } 545 while (!output_list_.empty()) { 546 VLOG(2) << log_prefix_ 547 << "DoWrite: Items in output list: " << output_list_.size(); 548 if (bytes_sent >= max_bytes_sent_per_dowrite_) { 549 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 550 << " byte sent >= max bytes sent per write: Setting EPOLLOUT: " 551 << bytes_sent; 552 events_ |= EPOLLOUT; 553 break; 554 } 555 if (sm_interface_ && output_list_.size() < 2) { 556 sm_interface_->GetOutput(); 557 } 558 DataFrame* data_frame = output_list_.front(); 559 const char* bytes = data_frame->data; 560 int size = data_frame->size; 561 bytes += data_frame->index; 562 size -= data_frame->index; 563 DCHECK_GE(size, 0); 564 if (size <= 0) { 565 output_list_.pop_front(); 566 delete data_frame; 567 continue; 568 } 569 570 flags = MSG_NOSIGNAL | MSG_DONTWAIT; 571 // Look for a queue size > 1 because |this| frame is remains on the list 572 // until it has finished sending. 573 if (output_list_.size() > 1) { 574 VLOG(2) << log_prefix_ << "Outlist size: " << output_list_.size() 575 << ": Adding MSG_MORE flag"; 576 flags |= MSG_MORE; 577 } 578 VLOG(2) << log_prefix_ << "Attempting to send " << size << " bytes."; 579 ssize_t bytes_written = Send(bytes, size, flags); 580 int stored_errno = errno; 581 if (bytes_written == -1) { 582 switch (stored_errno) { 583 case EAGAIN: 584 events_ &= ~EPOLLOUT; 585 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 586 << "Got EAGAIN while writing"; 587 goto done; 588 case EINTR: 589 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 590 << "Got EINTR while writing"; 591 continue; 592 default: 593 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 594 << "While calling send, got error: " << stored_errno << ": " 595 << (ssl_ ? "" : strerror(stored_errno)); 596 goto error_or_close; 597 } 598 } else if (bytes_written > 0) { 599 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 600 << "Wrote: " << bytes_written << " bytes"; 601 data_frame->index += bytes_written; 602 bytes_sent += bytes_written; 603 continue; 604 } else if (bytes_written == -2) { 605 // -2 handles SSL_ERROR_WANT_* errors 606 events_ &= ~EPOLLOUT; 607 goto done; 608 } 609 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 610 << "0 bytes written with send call."; 611 goto error_or_close; 612 } 613 done: 614 UncorkSocket(); 615 return true; 616 617 error_or_close: 618 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT 619 << "DoWrite: error_or_close. Returning false " 620 << "after cleaning up"; 621 Cleanup("DoWrite"); 622 UncorkSocket(); 623 return false; 624} 625 626void SMConnection::Reset() { 627 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Resetting"; 628 if (ssl_) { 629 SSL_shutdown(ssl_); 630 PrintSslError(); 631 SSL_free(ssl_); 632 PrintSslError(); 633 ssl_ = NULL; 634 } 635 if (registered_in_epoll_server_) { 636 epoll_server_->UnregisterFD(fd_); 637 registered_in_epoll_server_ = false; 638 } 639 if (fd_ >= 0) { 640 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Closing connection"; 641 close(fd_); 642 fd_ = -1; 643 } 644 read_buffer_.Clear(); 645 initialized_ = false; 646 protocol_detected_ = false; 647 events_ = 0; 648 for (std::list<DataFrame*>::iterator i = output_list_.begin(); 649 i != output_list_.end(); 650 ++i) { 651 delete *i; 652 } 653 output_list_.clear(); 654} 655 656// static 657SMConnection* SMConnection::NewSMConnection(EpollServer* epoll_server, 658 SSLState* ssl_state, 659 MemoryCache* memory_cache, 660 FlipAcceptor* acceptor, 661 std::string log_prefix) { 662 return new SMConnection( 663 epoll_server, ssl_state, memory_cache, acceptor, log_prefix); 664} 665 666} // namespace net 667