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"
8 #include <netinet/tcp.h>
9 #include <sys/socket.h>
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"
25 bool SMConnection::force_spdy_
= false;
27 DataFrame::~DataFrame() {
32 SMConnection::SMConnection(EpollServer
* epoll_server
,
34 MemoryCache
* memory_cache
,
35 FlipAcceptor
* acceptor
,
36 std::string log_prefix
)
40 registered_in_epoll_server_(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
),
49 read_buffer_(kSpdySegmentSize
* 40),
50 sm_spdy_interface_(NULL
),
51 sm_http_interface_(NULL
),
52 sm_streamer_interface_(NULL
),
54 log_prefix_(log_prefix
),
55 max_bytes_sent_per_dowrite_(4096),
59 SMConnection::~SMConnection() {
64 EpollServer
* SMConnection::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.";
81 void SMConnection::InitSMConnection(SMConnectionPoolInterface
* connection_pool
,
82 SMInterface
* sm_interface
,
83 EpollServer
* epoll_server
,
85 std::string server_ip
,
86 std::string server_port
,
87 std::string remote_ip
,
90 LOG(FATAL
) << "Attempted to initialize already initialized server";
94 client_ip_
= remote_ip
;
97 // If fd == -1, then we are initializing a new connection that will
98 // connect to the backend.
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_
,
110 acceptor_
->disable_nagle_
);
113 LOG(ERROR
) << "-1 Could not create connected socket";
115 } else if (ret
== 1) {
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_
<< " ";
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_
);
133 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
134 << "Closing pre-existing fd";
142 registered_in_epoll_server_
= false;
143 // Set the last read time here as the idle checker will start from
145 last_read_time_
= time(NULL
);
148 connection_pool_
= connection_pool
;
149 epoll_server_
= epoll_server
;
152 sm_interface_
= sm_interface
;
153 protocol_detected_
= true;
156 read_buffer_
.Clear();
158 epoll_server_
->RegisterFD(fd_
, this, EPOLLIN
| EPOLLOUT
| EPOLLET
);
161 ssl_
= CreateSSLContext(ssl_state_
->ssl_ctx
);
162 SSL_set_fd(ssl_
, fd_
);
167 void SMConnection::CorkSocket() {
169 int rv
= setsockopt(fd_
, IPPROTO_TCP
, TCP_CORK
, &state
, sizeof(state
));
171 VLOG(1) << "setsockopt(CORK): " << errno
;
174 void SMConnection::UncorkSocket() {
176 int rv
= setsockopt(fd_
, IPPROTO_TCP
, TCP_CORK
, &state
, sizeof(state
));
178 VLOG(1) << "setsockopt(CORK): " << errno
;
181 int SMConnection::Send(const char* data
, int len
, int flags
) {
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.
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
;
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
:
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)
221 rv
= send(fd_
, data
, len
, flags
);
223 if (!(flags
& MSG_MORE
))
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
;
236 event
->out_ready_mask
= events_
;
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");
250 void SMConnection::Cleanup(const char* cleanup
) {
251 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Cleanup: " << cleanup
;
255 if (connection_pool_
)
256 connection_pool_
->SMConnectionDone(this);
258 sm_interface_
->ResetForNewConnection();
262 void SMConnection::HandleEvents() {
263 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Received: "
264 << EpollServer::EventMaskToString(events_
).c_str();
266 if (events_
& EPOLLIN
) {
268 goto handle_close_or_error
;
271 if (events_
& EPOLLOUT
) {
272 // Check if we have connected or not
273 if (connection_complete_
== false) {
275 socklen_t sock_error_len
= sizeof(sock_error
);
276 int ret
= getsockopt(fd_
, SOL_SOCKET
, SO_ERROR
, &sock_error
,
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
) {
291 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
292 << "error connecting to server";
293 goto handle_close_or_error
;
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
;
306 handle_close_or_error
:
307 Cleanup("HandleEvents");
310 // Decide if SPDY was negotiated.
311 bool SMConnection::WasSpdyNegotiated() {
315 // If this is an SSL connection, check if NPN specifies SPDY.
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
))
333 bool SMConnection::SetupProtocolInterfaces() {
334 DCHECK(!protocol_detected_
);
335 protocol_detected_
= true;
337 bool spdy_negotiated
= WasSpdyNegotiated();
338 bool using_ssl
= ssl_
!= NULL
;
341 VLOG(1) << (SSL_session_reused(ssl_
) ? "Resumed" : "Renegotiated")
344 if (acceptor_
->spdy_only_
&& !spdy_negotiated
) {
345 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
346 << "SPDY proxy only, closing HTTPS connection.";
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,
363 sm_interface_
= sm_http_interface_
;
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,
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
)
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,
397 sm_interface_
= sm_spdy_interface_
;
403 if (!sm_interface_
->PostAcceptHook())
409 bool SMConnection::DoRead() {
410 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "DoRead()";
411 while (!read_buffer_
.Full()) {
415 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
416 << "DoRead(): fd_ == -1. Invalid FD. Returning false";
419 read_buffer_
.GetWritablePtr(&bytes
, &size
);
420 ssize_t bytes_read
= 0;
422 bytes_read
= SSL_read(ssl_
, bytes
, size
);
423 if (bytes_read
< 0) {
424 int err
= SSL_get_error(ssl_
, bytes_read
);
426 case SSL_ERROR_WANT_READ
:
427 case SSL_ERROR_WANT_WRITE
:
428 case SSL_ERROR_WANT_ACCEPT
:
429 case SSL_ERROR_WANT_CONNECT
:
431 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
432 << "DoRead: SSL WANT_XXX: " << err
;
440 bytes_read
= recv(fd_
, bytes
, size
, MSG_DONTWAIT
);
442 int stored_errno
= errno
;
443 if (bytes_read
== -1) {
444 switch (stored_errno
) {
447 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
448 << "Got EAGAIN while reading";
451 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
452 << "Got EINTR while reading";
455 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
456 << "While calling recv, got error: "
457 << (ssl_
?"(ssl error)":strerror(stored_errno
));
460 } else if (bytes_read
> 0) {
461 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "read " << bytes_read
463 last_read_time_
= time(NULL
);
464 // If the protocol hasn't been detected yet, set up the handlers
466 if (!protocol_detected_
) {
467 if (!SetupProtocolInterfaces()) {
468 LOG(ERROR
) << "Error setting up protocol interfaces.";
472 read_buffer_
.AdvanceWritablePtr(bytes_read
);
473 if (!DoConsumeReadData())
476 } else { // bytes_read == 0
477 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
478 << "0 bytes read with recv call.";
483 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "DoRead done!";
487 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
488 << "DoRead(): error_or_close. "
489 << "Cleaning up, then returning false";
494 bool SMConnection::DoConsumeReadData() {
497 read_buffer_
.GetReadablePtr(&bytes
, &size
);
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) {
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();
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.
519 read_buffer_
.GetReadablePtr(&bytes
, &size
);
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
;
532 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
533 << "DoWrite: fd == -1. Returning false.";
536 if (output_list_
.empty()) {
537 VLOG(2) << log_prefix_
<< "DoWrite: Output list empty.";
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: "
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
;
565 output_list_
.pop_front();
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";
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
) {
584 events_
&= ~EPOLLOUT
;
585 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
586 << "Got EAGAIN while writing";
589 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
590 << "Got EINTR while writing";
593 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
594 << "While calling send, got error: " << stored_errno
595 << ": " << (ssl_
?"":strerror(stored_errno
));
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
;
604 } else if (bytes_written
== -2) {
605 // -2 handles SSL_ERROR_WANT_* errors
606 events_
&= ~EPOLLOUT
;
609 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
610 << "0 bytes written with send call.";
618 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
619 << "DoWrite: error_or_close. Returning false "
620 << "after cleaning up";
626 void SMConnection::Reset() {
627 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Resetting";
635 if (registered_in_epoll_server_
) {
636 epoll_server_
->UnregisterFD(fd_
);
637 registered_in_epoll_server_
= false;
640 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Closing connection";
644 read_buffer_
.Clear();
645 initialized_
= false;
646 protocol_detected_
= false;
648 for (std::list
<DataFrame
*>::iterator i
=
649 output_list_
.begin();
650 i
!= output_list_
.end();
654 output_list_
.clear();
658 SMConnection
* SMConnection::NewSMConnection(EpollServer
* epoll_server
,
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
);