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 |