| OLD | NEW |
| (Empty) |
| 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 | |
| 23 namespace net { | |
| 24 | |
| 25 // static | |
| 26 bool SMConnection::force_spdy_ = false; | |
| 27 | |
| 28 DataFrame::~DataFrame() { | |
| 29 if (delete_when_done) | |
| 30 delete[] data; | |
| 31 } | |
| 32 | |
| 33 SMConnection::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 | |
| 59 SMConnection::~SMConnection() { | |
| 60 if (initialized()) | |
| 61 Reset(); | |
| 62 } | |
| 63 | |
| 64 EpollServer* SMConnection::epoll_server() { return epoll_server_; } | |
| 65 | |
| 66 void 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 | |
| 72 void 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 | |
| 79 void 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 | |
| 162 void 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 | |
| 169 void 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 | |
| 176 int 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 | |
| 223 void SMConnection::OnRegistration(EpollServer* eps, int fd, int event_mask) { | |
| 224 registered_in_epoll_server_ = true; | |
| 225 } | |
| 226 | |
| 227 void 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 | |
| 236 void SMConnection::OnUnregistration(int fd, bool replaced) { | |
| 237 registered_in_epoll_server_ = false; | |
| 238 } | |
| 239 | |
| 240 void SMConnection::OnShutdown(EpollServer* eps, int fd) { | |
| 241 Cleanup("OnShutdown"); | |
| 242 return; | |
| 243 } | |
| 244 | |
| 245 void 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 | |
| 257 void 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. | |
| 306 bool 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 | |
| 344 bool 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 | |
| 411 bool 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 | |
| 496 bool 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 | |
| 526 void SMConnection::HandleResponseFullyRead() { sm_interface_->Cleanup(); } | |
| 527 | |
| 528 bool 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 | |
| 626 void 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 | |
| 657 SMConnection* 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 | |
| OLD | NEW |