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