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