Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / tools / flip_server / sm_connection.cc
blob71e81a08ae94acc53560de5b08b5acdd27616143
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.
5 #include "net/tools/flip_server/sm_connection.h"
7 #include <errno.h>
8 #include <netinet/tcp.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
12 #include <list>
13 #include <string>
15 #include "net/tools/flip_server/constants.h"
16 #include "net/tools/flip_server/flip_config.h"
17 #include "net/tools/flip_server/http_interface.h"
18 #include "net/tools/flip_server/spdy_interface.h"
19 #include "net/tools/flip_server/spdy_ssl.h"
20 #include "net/tools/flip_server/streamer_interface.h"
22 namespace net {
24 // static
25 bool SMConnection::force_spdy_ = false;
27 DataFrame::~DataFrame() {
28 if (delete_when_done)
29 delete[] data;
32 SMConnection::SMConnection(EpollServer* epoll_server,
33 SSLState* ssl_state,
34 MemoryCache* memory_cache,
35 FlipAcceptor* acceptor,
36 std::string log_prefix)
37 : last_read_time_(0),
38 fd_(-1),
39 events_(0),
40 registered_in_epoll_server_(false),
41 initialized_(false),
42 protocol_detected_(false),
43 connection_complete_(false),
44 connection_pool_(NULL),
45 epoll_server_(epoll_server),
46 ssl_state_(ssl_state),
47 memory_cache_(memory_cache),
48 acceptor_(acceptor),
49 read_buffer_(kSpdySegmentSize * 40),
50 sm_spdy_interface_(NULL),
51 sm_http_interface_(NULL),
52 sm_streamer_interface_(NULL),
53 sm_interface_(NULL),
54 log_prefix_(log_prefix),
55 max_bytes_sent_per_dowrite_(4096),
56 ssl_(NULL) {
59 SMConnection::~SMConnection() {
60 if (initialized())
61 Reset();
64 EpollServer* SMConnection::epoll_server() {
65 return epoll_server_;
68 void SMConnection::ReadyToSend() {
69 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
70 << "Setting ready to send: EPOLLIN | EPOLLOUT";
71 epoll_server_->SetFDReady(fd_, EPOLLIN | EPOLLOUT);
74 void SMConnection::EnqueueDataFrame(DataFrame* df) {
75 output_list_.push_back(df);
76 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "EnqueueDataFrame: "
77 << "size = " << df->size << ": Setting FD ready.";
78 ReadyToSend();
81 void SMConnection::InitSMConnection(SMConnectionPoolInterface* connection_pool,
82 SMInterface* sm_interface,
83 EpollServer* epoll_server,
84 int fd,
85 std::string server_ip,
86 std::string server_port,
87 std::string remote_ip,
88 bool use_ssl) {
89 if (initialized_) {
90 LOG(FATAL) << "Attempted to initialize already initialized server";
91 return;
94 client_ip_ = remote_ip;
96 if (fd == -1) {
97 // If fd == -1, then we are initializing a new connection that will
98 // connect to the backend.
100 // ret: -1 == error
101 // 0 == connection in progress
102 // 1 == connection complete
103 // TODO(kelindsay): is_numeric_host_address value needs to be detected
104 server_ip_ = server_ip;
105 server_port_ = server_port;
106 int ret = CreateConnectedSocket(&fd_,
107 server_ip,
108 server_port,
109 true,
110 acceptor_->disable_nagle_);
112 if (ret < 0) {
113 LOG(ERROR) << "-1 Could not create connected socket";
114 return;
115 } else if (ret == 1) {
116 DCHECK_NE(-1, fd_);
117 connection_complete_ = true;
118 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
119 << "Connection complete to: " << server_ip_ << ":"
120 << server_port_ << " ";
122 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
123 << "Connecting to server: " << server_ip_ << ":"
124 << server_port_ << " ";
125 } else {
126 // If fd != -1 then we are initializing a connection that has just been
127 // accepted from the listen socket.
128 connection_complete_ = true;
129 if (epoll_server_ && registered_in_epoll_server_ && fd_ != -1) {
130 epoll_server_->UnregisterFD(fd_);
132 if (fd_ != -1) {
133 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
134 << "Closing pre-existing fd";
135 close(fd_);
136 fd_ = -1;
139 fd_ = fd;
142 registered_in_epoll_server_ = false;
143 // Set the last read time here as the idle checker will start from
144 // now.
145 last_read_time_ = time(NULL);
146 initialized_ = true;
148 connection_pool_ = connection_pool;
149 epoll_server_ = epoll_server;
151 if (sm_interface) {
152 sm_interface_ = sm_interface;
153 protocol_detected_ = true;
156 read_buffer_.Clear();
158 epoll_server_->RegisterFD(fd_, this, EPOLLIN | EPOLLOUT | EPOLLET);
160 if (use_ssl) {
161 ssl_ = CreateSSLContext(ssl_state_->ssl_ctx);
162 SSL_set_fd(ssl_, fd_);
163 PrintSslError();
167 void SMConnection::CorkSocket() {
168 int state = 1;
169 int rv = setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
170 if (rv < 0)
171 VLOG(1) << "setsockopt(CORK): " << errno;
174 void SMConnection::UncorkSocket() {
175 int state = 0;
176 int rv = setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
177 if (rv < 0)
178 VLOG(1) << "setsockopt(CORK): " << errno;
181 int SMConnection::Send(const char* data, int len, int flags) {
182 int rv = 0;
183 CorkSocket();
184 if (ssl_) {
185 ssize_t bytes_written = 0;
186 // Write smallish chunks to SSL so that we don't have large
187 // multi-packet TLS records to receive before being able to handle
188 // the data. We don't have to be too careful here, because our data
189 // frames are already getting chunked appropriately, and those are
190 // the most likely "big" frames.
191 while (len > 0) {
192 const int kMaxTLSRecordSize = 1500;
193 const char* ptr = &(data[bytes_written]);
194 int chunksize = std::min(len, kMaxTLSRecordSize);
195 rv = SSL_write(ssl_, ptr, chunksize);
196 VLOG(2) << "SSLWrite(" << chunksize << " bytes): " << rv;
197 if (rv <= 0) {
198 switch (SSL_get_error(ssl_, rv)) {
199 case SSL_ERROR_WANT_READ:
200 case SSL_ERROR_WANT_WRITE:
201 case SSL_ERROR_WANT_ACCEPT:
202 case SSL_ERROR_WANT_CONNECT:
203 rv = -2;
204 break;
205 default:
206 PrintSslError();
207 break;
209 break;
211 bytes_written += rv;
212 len -= rv;
213 if (rv != chunksize)
214 break; // If we couldn't write everything, we're implicitly stalled
216 // If we wrote some data, return that count. Otherwise
217 // return the stall error.
218 if (bytes_written > 0)
219 rv = bytes_written;
220 } else {
221 rv = send(fd_, data, len, flags);
223 if (!(flags & MSG_MORE))
224 UncorkSocket();
225 return rv;
228 void SMConnection::OnRegistration(EpollServer* eps, int fd, int event_mask) {
229 registered_in_epoll_server_ = true;
232 void SMConnection::OnEvent(int fd, EpollEvent* event) {
233 events_ |= event->in_events;
234 HandleEvents();
235 if (events_) {
236 event->out_ready_mask = events_;
237 events_ = 0;
241 void SMConnection::OnUnregistration(int fd, bool replaced) {
242 registered_in_epoll_server_ = false;
245 void SMConnection::OnShutdown(EpollServer* eps, int fd) {
246 Cleanup("OnShutdown");
247 return;
250 void SMConnection::Cleanup(const char* cleanup) {
251 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Cleanup: " << cleanup;
252 if (!initialized_)
253 return;
254 Reset();
255 if (connection_pool_)
256 connection_pool_->SMConnectionDone(this);
257 if (sm_interface_)
258 sm_interface_->ResetForNewConnection();
259 last_read_time_ = 0;
262 void SMConnection::HandleEvents() {
263 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Received: "
264 << EpollServer::EventMaskToString(events_).c_str();
266 if (events_ & EPOLLIN) {
267 if (!DoRead())
268 goto handle_close_or_error;
271 if (events_ & EPOLLOUT) {
272 // Check if we have connected or not
273 if (connection_complete_ == false) {
274 int sock_error;
275 socklen_t sock_error_len = sizeof(sock_error);
276 int ret = getsockopt(fd_, SOL_SOCKET, SO_ERROR, &sock_error,
277 &sock_error_len);
278 if (ret != 0) {
279 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
280 << "getsockopt error: " << errno << ": " << strerror(errno);
281 goto handle_close_or_error;
283 if (sock_error == 0) {
284 connection_complete_ = true;
285 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
286 << "Connection complete to " << server_ip_ << ":"
287 << server_port_ << " ";
288 } else if (sock_error == EINPROGRESS) {
289 return;
290 } else {
291 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
292 << "error connecting to server";
293 goto handle_close_or_error;
296 if (!DoWrite())
297 goto handle_close_or_error;
300 if (events_ & (EPOLLHUP | EPOLLERR)) {
301 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "!!! Got HUP or ERR";
302 goto handle_close_or_error;
304 return;
306 handle_close_or_error:
307 Cleanup("HandleEvents");
310 // Decide if SPDY was negotiated.
311 bool SMConnection::WasSpdyNegotiated() {
312 if (force_spdy())
313 return true;
315 // If this is an SSL connection, check if NPN specifies SPDY.
316 if (ssl_) {
317 const unsigned char *npn_proto;
318 unsigned int npn_proto_len;
319 SSL_get0_next_proto_negotiated(ssl_, &npn_proto, &npn_proto_len);
320 if (npn_proto_len > 0) {
321 std::string npn_proto_str((const char *)npn_proto, npn_proto_len);
322 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
323 << "NPN protocol detected: " << npn_proto_str;
324 if (!strncmp(reinterpret_cast<const char*>(npn_proto),
325 "spdy/2", npn_proto_len))
326 return true;
330 return false;
333 bool SMConnection::SetupProtocolInterfaces() {
334 DCHECK(!protocol_detected_);
335 protocol_detected_ = true;
337 bool spdy_negotiated = WasSpdyNegotiated();
338 bool using_ssl = ssl_ != NULL;
340 if (using_ssl)
341 VLOG(1) << (SSL_session_reused(ssl_) ? "Resumed" : "Renegotiated")
342 << " SSL Session.";
344 if (acceptor_->spdy_only_ && !spdy_negotiated) {
345 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
346 << "SPDY proxy only, closing HTTPS connection.";
347 return false;
350 switch (acceptor_->flip_handler_type_) {
351 case FLIP_HANDLER_HTTP_SERVER:
353 DCHECK(!spdy_negotiated);
354 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
355 << (sm_http_interface_ ? "Creating" : "Reusing")
356 << " HTTP interface.";
357 if (!sm_http_interface_)
358 sm_http_interface_ = new HttpSM(this,
359 NULL,
360 epoll_server_,
361 memory_cache_,
362 acceptor_);
363 sm_interface_ = sm_http_interface_;
365 break;
366 case FLIP_HANDLER_PROXY:
368 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
369 << (sm_streamer_interface_ ? "Creating" : "Reusing")
370 << " PROXY Streamer interface.";
371 if (!sm_streamer_interface_) {
372 sm_streamer_interface_ = new StreamerSM(this,
373 NULL,
374 epoll_server_,
375 acceptor_);
376 sm_streamer_interface_->set_is_request();
378 sm_interface_ = sm_streamer_interface_;
379 // If spdy is not negotiated, the streamer interface will proxy all
380 // data to the origin server.
381 if (!spdy_negotiated)
382 break;
384 // Otherwise fall through into the case below.
385 case FLIP_HANDLER_SPDY_SERVER:
387 DCHECK(spdy_negotiated);
388 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
389 << (sm_spdy_interface_ ? "Creating" : "Reusing")
390 << " SPDY interface.";
391 if (!sm_spdy_interface_)
392 sm_spdy_interface_ = new SpdySM(this,
393 NULL,
394 epoll_server_,
395 memory_cache_,
396 acceptor_);
397 sm_interface_ = sm_spdy_interface_;
399 break;
402 CorkSocket();
403 if (!sm_interface_->PostAcceptHook())
404 return false;
406 return true;
409 bool SMConnection::DoRead() {
410 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "DoRead()";
411 while (!read_buffer_.Full()) {
412 char* bytes;
413 int size;
414 if (fd_ == -1) {
415 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
416 << "DoRead(): fd_ == -1. Invalid FD. Returning false";
417 return false;
419 read_buffer_.GetWritablePtr(&bytes, &size);
420 ssize_t bytes_read = 0;
421 if (ssl_) {
422 bytes_read = SSL_read(ssl_, bytes, size);
423 if (bytes_read < 0) {
424 int err = SSL_get_error(ssl_, bytes_read);
425 switch (err) {
426 case SSL_ERROR_WANT_READ:
427 case SSL_ERROR_WANT_WRITE:
428 case SSL_ERROR_WANT_ACCEPT:
429 case SSL_ERROR_WANT_CONNECT:
430 events_ &= ~EPOLLIN;
431 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
432 << "DoRead: SSL WANT_XXX: " << err;
433 goto done;
434 default:
435 PrintSslError();
436 goto error_or_close;
439 } else {
440 bytes_read = recv(fd_, bytes, size, MSG_DONTWAIT);
442 int stored_errno = errno;
443 if (bytes_read == -1) {
444 switch (stored_errno) {
445 case EAGAIN:
446 events_ &= ~EPOLLIN;
447 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
448 << "Got EAGAIN while reading";
449 goto done;
450 case EINTR:
451 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
452 << "Got EINTR while reading";
453 continue;
454 default:
455 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
456 << "While calling recv, got error: "
457 << (ssl_?"(ssl error)":strerror(stored_errno));
458 goto error_or_close;
460 } else if (bytes_read > 0) {
461 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "read " << bytes_read
462 << " bytes";
463 last_read_time_ = time(NULL);
464 // If the protocol hasn't been detected yet, set up the handlers
465 // we'll need.
466 if (!protocol_detected_) {
467 if (!SetupProtocolInterfaces()) {
468 LOG(ERROR) << "Error setting up protocol interfaces.";
469 goto error_or_close;
472 read_buffer_.AdvanceWritablePtr(bytes_read);
473 if (!DoConsumeReadData())
474 goto error_or_close;
475 continue;
476 } else { // bytes_read == 0
477 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
478 << "0 bytes read with recv call.";
480 goto error_or_close;
482 done:
483 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "DoRead done!";
484 return true;
486 error_or_close:
487 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
488 << "DoRead(): error_or_close. "
489 << "Cleaning up, then returning false";
490 Cleanup("DoRead");
491 return false;
494 bool SMConnection::DoConsumeReadData() {
495 char* bytes;
496 int size;
497 read_buffer_.GetReadablePtr(&bytes, &size);
498 while (size != 0) {
499 size_t bytes_consumed = sm_interface_->ProcessReadInput(bytes, size);
500 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "consumed "
501 << bytes_consumed << " bytes";
502 if (bytes_consumed == 0) {
503 break;
505 read_buffer_.AdvanceReadablePtr(bytes_consumed);
506 if (sm_interface_->MessageFullyRead()) {
507 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
508 << "HandleRequestFullyRead: Setting EPOLLOUT";
509 HandleResponseFullyRead();
510 events_ |= EPOLLOUT;
511 } else if (sm_interface_->Error()) {
512 LOG(ERROR) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
513 << "Framer error detected: Setting EPOLLOUT: "
514 << sm_interface_->ErrorAsString();
515 // this causes everything to be closed/cleaned up.
516 events_ |= EPOLLOUT;
517 return false;
519 read_buffer_.GetReadablePtr(&bytes, &size);
521 return true;
524 void SMConnection::HandleResponseFullyRead() {
525 sm_interface_->Cleanup();
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;
536 if (output_list_.empty()) {
537 VLOG(2) << log_prefix_ << "DoWrite: Output list empty.";
538 if (sm_interface_) {
539 sm_interface_->GetOutput();
541 if (output_list_.empty()) {
542 events_ &= ~EPOLLOUT;
545 while (!output_list_.empty()) {
546 VLOG(2) << log_prefix_ << "DoWrite: Items in output list: "
547 << 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;
555 if (sm_interface_ && output_list_.size() < 2) {
556 sm_interface_->GetOutput();
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;
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;
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;
598 } else if (bytes_written > 0) {
599 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Wrote: "
600 << 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;
609 VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
610 << "0 bytes written with send call.";
611 goto error_or_close;
613 done:
614 UncorkSocket();
615 return true;
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;
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;
635 if (registered_in_epoll_server_) {
636 epoll_server_->UnregisterFD(fd_);
637 registered_in_epoll_server_ = false;
639 if (fd_ >= 0) {
640 VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Closing connection";
641 close(fd_);
642 fd_ = -1;
644 read_buffer_.Clear();
645 initialized_ = false;
646 protocol_detected_ = false;
647 events_ = 0;
648 for (std::list<DataFrame*>::iterator i =
649 output_list_.begin();
650 i != output_list_.end();
651 ++i) {
652 delete *i;
654 output_list_.clear();
657 // static
658 SMConnection* SMConnection::NewSMConnection(EpollServer* epoll_server,
659 SSLState *ssl_state,
660 MemoryCache* memory_cache,
661 FlipAcceptor *acceptor,
662 std::string log_prefix) {
663 return new SMConnection(epoll_server, ssl_state, memory_cache,
664 acceptor, log_prefix);
667 } // namespace net