• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~DataFrame()28 DataFrame::~DataFrame() {
29   if (delete_when_done)
30     delete[] data;
31 }
32 
SMConnection(EpollServer * epoll_server,SSLState * ssl_state,MemoryCache * memory_cache,FlipAcceptor * acceptor,std::string log_prefix)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 
~SMConnection()59 SMConnection::~SMConnection() {
60   if (initialized())
61     Reset();
62 }
63 
epoll_server()64 EpollServer* SMConnection::epoll_server() { return epoll_server_; }
65 
ReadyToSend()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 
EnqueueDataFrame(DataFrame * df)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 
InitSMConnection(SMConnectionPoolInterface * connection_pool,SMInterface * sm_interface,EpollServer * epoll_server,int fd,std::string server_ip,std::string server_port,std::string remote_ip,bool use_ssl)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 
CorkSocket()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 
UncorkSocket()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 
Send(const char * data,int len,int flags)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 
OnRegistration(EpollServer * eps,int fd,int event_mask)223 void SMConnection::OnRegistration(EpollServer* eps, int fd, int event_mask) {
224   registered_in_epoll_server_ = true;
225 }
226 
OnEvent(int fd,EpollEvent * event)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 
OnUnregistration(int fd,bool replaced)236 void SMConnection::OnUnregistration(int fd, bool replaced) {
237   registered_in_epoll_server_ = false;
238 }
239 
OnShutdown(EpollServer * eps,int fd)240 void SMConnection::OnShutdown(EpollServer* eps, int fd) {
241   Cleanup("OnShutdown");
242   return;
243 }
244 
Cleanup(const char * cleanup)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 
HandleEvents()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.
WasSpdyNegotiated(SpdyMajorVersion * version_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 
SetupProtocolInterfaces()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 
DoRead()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 
DoConsumeReadData()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 
HandleResponseFullyRead()526 void SMConnection::HandleResponseFullyRead() { sm_interface_->Cleanup(); }
527 
DoWrite()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 
Reset()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
NewSMConnection(EpollServer * epoll_server,SSLState * ssl_state,MemoryCache * memory_cache,FlipAcceptor * acceptor,std::string log_prefix)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
667