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>
16 #include "net/tools/flip_server/constants.h"
17 #include "net/tools/flip_server/create_listener.h"
18 #include "net/tools/flip_server/flip_config.h"
19 #include "net/tools/flip_server/http_interface.h"
20 #include "net/tools/flip_server/spdy_interface.h"
21 #include "net/tools/flip_server/spdy_ssl.h"
22 #include "net/tools/flip_server/streamer_interface.h"
27 bool SMConnection::force_spdy_
= false;
29 DataFrame::~DataFrame() {
34 SMConnection::SMConnection(EpollServer
* epoll_server
,
36 MemoryCache
* memory_cache
,
37 FlipAcceptor
* acceptor
,
38 std::string log_prefix
)
42 registered_in_epoll_server_(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
),
51 read_buffer_(kSpdySegmentSize
* 40),
52 sm_spdy_interface_(NULL
),
53 sm_http_interface_(NULL
),
54 sm_streamer_interface_(NULL
),
56 log_prefix_(log_prefix
),
57 max_bytes_sent_per_dowrite_(4096),
60 SMConnection::~SMConnection() {
65 EpollServer
* SMConnection::epoll_server() { return epoll_server_
; }
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
);
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.";
80 void SMConnection::InitSMConnection(SMConnectionPoolInterface
* connection_pool
,
81 SMInterface
* sm_interface
,
82 EpollServer
* epoll_server
,
84 std::string server_ip
,
85 std::string server_port
,
86 std::string remote_ip
,
89 LOG(FATAL
) << "Attempted to initialize already initialized server";
93 client_ip_
= remote_ip
;
96 // If fd == -1, then we are initializing a new connection that will
97 // connect to the backend.
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
= CreateConnectedSocket(
106 &fd_
, server_ip
, server_port
, true, acceptor_
->disable_nagle_
);
109 LOG(ERROR
) << "-1 Could not create connected socket";
111 } else if (ret
== 1) {
113 connection_complete_
= true;
114 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
115 << "Connection complete to: " << server_ip_
<< ":" << server_port_
118 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
119 << "Connecting to server: " << server_ip_
<< ":" << server_port_
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_
);
129 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
130 << "Closing pre-existing fd";
138 registered_in_epoll_server_
= false;
139 // Set the last read time here as the idle checker will start from
141 last_read_time_
= time(NULL
);
144 connection_pool_
= connection_pool
;
145 epoll_server_
= epoll_server
;
148 sm_interface_
= sm_interface
;
149 protocol_detected_
= true;
152 read_buffer_
.Clear();
154 epoll_server_
->RegisterFD(fd_
, this, EPOLLIN
| EPOLLOUT
| EPOLLET
);
157 ssl_
= CreateSSLContext(ssl_state_
->ssl_ctx
);
158 SSL_set_fd(ssl_
, fd_
);
163 void SMConnection::CorkSocket() {
165 int rv
= setsockopt(fd_
, IPPROTO_TCP
, TCP_CORK
, &state
, sizeof(state
));
167 VLOG(1) << "setsockopt(CORK): " << errno
;
170 void SMConnection::UncorkSocket() {
172 int rv
= setsockopt(fd_
, IPPROTO_TCP
, TCP_CORK
, &state
, sizeof(state
));
174 VLOG(1) << "setsockopt(CORK): " << errno
;
177 int SMConnection::Send(const char* data
, int len
, int flags
) {
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.
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
;
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
:
210 break; // If we couldn't write everything, we're implicitly stalled
212 // If we wrote some data, return that count. Otherwise
213 // return the stall error.
214 if (bytes_written
> 0)
217 rv
= send(fd_
, data
, len
, flags
);
219 if (!(flags
& MSG_MORE
))
224 void SMConnection::OnRegistration(EpollServer
* eps
, int fd
, int event_mask
) {
225 registered_in_epoll_server_
= true;
228 void SMConnection::OnEvent(int fd
, EpollEvent
* event
) {
229 events_
|= event
->in_events
;
232 event
->out_ready_mask
= events_
;
237 void SMConnection::OnUnregistration(int fd
, bool replaced
) {
238 registered_in_epoll_server_
= false;
241 void SMConnection::OnShutdown(EpollServer
* eps
, int fd
) {
242 Cleanup("OnShutdown");
246 void SMConnection::Cleanup(const char* cleanup
) {
247 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Cleanup: " << cleanup
;
251 if (connection_pool_
)
252 connection_pool_
->SMConnectionDone(this);
254 sm_interface_
->ResetForNewConnection();
258 void SMConnection::HandleEvents() {
259 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
260 << "Received: " << EpollServer::EventMaskToString(events_
).c_str();
262 if (events_
& EPOLLIN
) {
264 goto handle_close_or_error
;
267 if (events_
& EPOLLOUT
) {
268 // Check if we have connected or not
269 if (connection_complete_
== false) {
271 socklen_t sock_error_len
= sizeof(sock_error
);
273 getsockopt(fd_
, SOL_SOCKET
, SO_ERROR
, &sock_error
, &sock_error_len
);
275 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
276 << "getsockopt error: " << errno
<< ": " << strerror(errno
);
277 goto handle_close_or_error
;
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
) {
287 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
288 << "error connecting to server";
289 goto handle_close_or_error
;
293 goto handle_close_or_error
;
296 if (events_
& (EPOLLHUP
| EPOLLERR
)) {
297 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "!!! Got HUP or ERR";
298 goto handle_close_or_error
;
302 handle_close_or_error
:
303 Cleanup("HandleEvents");
306 // Decide if SPDY was negotiated.
307 bool SMConnection::WasSpdyNegotiated(SpdyMajorVersion
* version_negotiated
) {
308 *version_negotiated
= SPDY3
;
312 // If this is an SSL connection, check if NPN specifies SPDY.
314 const unsigned char* npn_proto
;
315 unsigned int npn_proto_len
;
316 SSL_get0_next_proto_negotiated(ssl_
, &npn_proto
, &npn_proto_len
);
317 if (npn_proto_len
> 0) {
318 std::string
npn_proto_str((const char*)npn_proto
, npn_proto_len
);
319 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
320 << "NPN protocol detected: " << npn_proto_str
;
321 if (!strncmp(reinterpret_cast<const char*>(npn_proto
),
324 *version_negotiated
= SPDY2
;
327 if (!strncmp(reinterpret_cast<const char*>(npn_proto
),
330 *version_negotiated
= SPDY3
;
333 if (!strncmp(reinterpret_cast<const char*>(npn_proto
),
336 *version_negotiated
= HTTP2
;
345 bool SMConnection::SetupProtocolInterfaces() {
346 DCHECK(!protocol_detected_
);
347 protocol_detected_
= true;
349 SpdyMajorVersion version
;
350 bool spdy_negotiated
= WasSpdyNegotiated(&version
);
351 bool using_ssl
= ssl_
!= NULL
;
354 VLOG(1) << (SSL_session_reused(ssl_
) ? "Resumed" : "Renegotiated")
357 if (acceptor_
->spdy_only_
&& !spdy_negotiated
) {
358 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
359 << "SPDY proxy only, closing HTTPS connection.";
363 switch (acceptor_
->flip_handler_type_
) {
364 case FLIP_HANDLER_HTTP_SERVER
: {
365 DCHECK(!spdy_negotiated
);
366 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
367 << (sm_http_interface_
? "Creating" : "Reusing")
368 << " HTTP interface.";
369 if (!sm_http_interface_
)
370 sm_http_interface_
= new HttpSM(this, NULL
, memory_cache_
, acceptor_
);
371 sm_interface_
= sm_http_interface_
;
374 case FLIP_HANDLER_PROXY
: {
375 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
376 << (sm_streamer_interface_
? "Creating" : "Reusing")
377 << " PROXY Streamer interface.";
378 if (!sm_streamer_interface_
) {
379 sm_streamer_interface_
=
380 new StreamerSM(this, NULL
, epoll_server_
, acceptor_
);
381 sm_streamer_interface_
->set_is_request();
383 sm_interface_
= sm_streamer_interface_
;
384 // If spdy is not negotiated, the streamer interface will proxy all
385 // data to the origin server.
386 if (!spdy_negotiated
)
389 // Otherwise fall through into the case below.
390 case FLIP_HANDLER_SPDY_SERVER
: {
391 DCHECK(spdy_negotiated
);
392 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
393 << (sm_spdy_interface_
? "Creating" : "Reusing")
394 << " SPDY interface.";
395 if (sm_spdy_interface_
)
396 sm_spdy_interface_
->CreateFramer(version
);
398 sm_spdy_interface_
= new SpdySM(
399 this, NULL
, epoll_server_
, memory_cache_
, acceptor_
, version
);
400 sm_interface_
= sm_spdy_interface_
;
406 if (!sm_interface_
->PostAcceptHook())
412 bool SMConnection::DoRead() {
413 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "DoRead()";
414 while (!read_buffer_
.Full()) {
418 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
419 << "DoRead(): fd_ == -1. Invalid FD. Returning false";
422 read_buffer_
.GetWritablePtr(&bytes
, &size
);
423 ssize_t bytes_read
= 0;
425 bytes_read
= SSL_read(ssl_
, bytes
, size
);
426 if (bytes_read
< 0) {
427 int err
= SSL_get_error(ssl_
, bytes_read
);
429 case SSL_ERROR_WANT_READ
:
430 case SSL_ERROR_WANT_WRITE
:
431 case SSL_ERROR_WANT_ACCEPT
:
432 case SSL_ERROR_WANT_CONNECT
:
434 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
435 << "DoRead: SSL WANT_XXX: " << err
;
443 bytes_read
= recv(fd_
, bytes
, size
, MSG_DONTWAIT
);
445 int stored_errno
= errno
;
446 if (bytes_read
== -1) {
447 switch (stored_errno
) {
450 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
451 << "Got EAGAIN while reading";
454 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
455 << "Got EINTR while reading";
458 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
459 << "While calling recv, got error: "
460 << (ssl_
? "(ssl error)" : strerror(stored_errno
));
463 } else if (bytes_read
> 0) {
464 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "read " << bytes_read
466 last_read_time_
= time(NULL
);
467 // If the protocol hasn't been detected yet, set up the handlers
469 if (!protocol_detected_
) {
470 if (!SetupProtocolInterfaces()) {
471 LOG(ERROR
) << "Error setting up protocol interfaces.";
475 read_buffer_
.AdvanceWritablePtr(bytes_read
);
476 if (!DoConsumeReadData())
479 } else { // bytes_read == 0
480 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
481 << "0 bytes read with recv call.";
486 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "DoRead done!";
490 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
491 << "DoRead(): error_or_close. "
492 << "Cleaning up, then returning false";
497 bool SMConnection::DoConsumeReadData() {
500 read_buffer_
.GetReadablePtr(&bytes
, &size
);
502 size_t bytes_consumed
= sm_interface_
->ProcessReadInput(bytes
, size
);
503 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "consumed "
504 << bytes_consumed
<< " bytes";
505 if (bytes_consumed
== 0) {
508 read_buffer_
.AdvanceReadablePtr(bytes_consumed
);
509 if (sm_interface_
->MessageFullyRead()) {
510 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
511 << "HandleRequestFullyRead: Setting EPOLLOUT";
512 HandleResponseFullyRead();
514 } else if (sm_interface_
->Error()) {
515 LOG(ERROR
) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
516 << "Framer error detected: Setting EPOLLOUT: "
517 << sm_interface_
->ErrorAsString();
518 // this causes everything to be closed/cleaned up.
522 read_buffer_
.GetReadablePtr(&bytes
, &size
);
527 void SMConnection::HandleResponseFullyRead() { sm_interface_
->Cleanup(); }
529 bool SMConnection::DoWrite() {
530 size_t bytes_sent
= 0;
531 int flags
= MSG_NOSIGNAL
| MSG_DONTWAIT
;
533 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
534 << "DoWrite: fd == -1. Returning false.";
537 if (output_list_
.empty()) {
538 VLOG(2) << log_prefix_
<< "DoWrite: Output list empty.";
540 sm_interface_
->GetOutput();
542 if (output_list_
.empty()) {
543 events_
&= ~EPOLLOUT
;
546 while (!output_list_
.empty()) {
547 VLOG(2) << log_prefix_
548 << "DoWrite: Items in output list: " << output_list_
.size();
549 if (bytes_sent
>= max_bytes_sent_per_dowrite_
) {
550 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
551 << " byte sent >= max bytes sent per write: Setting EPOLLOUT: "
556 if (sm_interface_
&& output_list_
.size() < 2) {
557 sm_interface_
->GetOutput();
559 DataFrame
* data_frame
= output_list_
.front();
560 const char* bytes
= data_frame
->data
;
561 int size
= data_frame
->size
;
562 bytes
+= data_frame
->index
;
563 size
-= data_frame
->index
;
566 output_list_
.pop_front();
571 flags
= MSG_NOSIGNAL
| MSG_DONTWAIT
;
572 // Look for a queue size > 1 because |this| frame is remains on the list
573 // until it has finished sending.
574 if (output_list_
.size() > 1) {
575 VLOG(2) << log_prefix_
<< "Outlist size: " << output_list_
.size()
576 << ": Adding MSG_MORE flag";
579 VLOG(2) << log_prefix_
<< "Attempting to send " << size
<< " bytes.";
580 ssize_t bytes_written
= Send(bytes
, size
, flags
);
581 int stored_errno
= errno
;
582 if (bytes_written
== -1) {
583 switch (stored_errno
) {
585 events_
&= ~EPOLLOUT
;
586 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
587 << "Got EAGAIN while writing";
590 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
591 << "Got EINTR while writing";
594 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
595 << "While calling send, got error: " << stored_errno
<< ": "
596 << (ssl_
? "" : strerror(stored_errno
));
599 } else if (bytes_written
> 0) {
600 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
601 << "Wrote: " << bytes_written
<< " bytes";
602 data_frame
->index
+= bytes_written
;
603 bytes_sent
+= bytes_written
;
605 } else if (bytes_written
== -2) {
606 // -2 handles SSL_ERROR_WANT_* errors
607 events_
&= ~EPOLLOUT
;
610 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
611 << "0 bytes written with send call.";
619 VLOG(1) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
620 << "DoWrite: error_or_close. Returning false "
621 << "after cleaning up";
627 void SMConnection::Reset() {
628 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Resetting";
636 if (registered_in_epoll_server_
) {
637 epoll_server_
->UnregisterFD(fd_
);
638 registered_in_epoll_server_
= false;
641 VLOG(2) << log_prefix_
<< ACCEPTOR_CLIENT_IDENT
<< "Closing connection";
645 read_buffer_
.Clear();
646 initialized_
= false;
647 protocol_detected_
= false;
649 for (std::list
<DataFrame
*>::iterator i
= 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(
664 epoll_server
, ssl_state
, memory_cache
, acceptor
, log_prefix
);