1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifndef NET_SOCKET_TCP_CLIENT_SOCKET_LIBEVENT_H_
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define NET_SOCKET_TCP_CLIENT_SOCKET_LIBEVENT_H_
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#pragma once
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/non_thread_safe.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/address_list.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/completion_callback.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/client_socket.h"
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct event;  // From libevent
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BoundNetLog;
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A client socket that uses TCP as the transport layer.
253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass TCPClientSocketLibevent : public ClientSocket, base::NonThreadSafe {
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The IP address(es) and port number to connect to.  The TCP socket will try
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // each IP address in the list until it succeeds in establishing a
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // connection.
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TCPClientSocketLibevent(const AddressList& addresses,
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          net::NetLog* net_log,
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          const net::NetLog::Source& source);
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual ~TCPClientSocketLibevent();
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // AdoptSocket causes the given, connected socket to be adopted as a TCP
374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // socket. This object must not be connected. This object takes ownership of
384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // the given socket and then acts as if Connect() had been called. This
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // function is used by TCPServerSocket() to adopt accepted connections
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // and for testing.
414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  void AdoptSocket(int socket);
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // ClientSocket methods:
447b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen  virtual int Connect(CompletionCallback* callback
457b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
467b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                      , bool wait_for_connect
47e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                      , bool valid_uid
48e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                      , uid_t calling_uid
497b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
507b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                     );
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void Disconnect();
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual bool IsConnected() const;
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual bool IsConnectedAndIdle() const;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual int GetPeerAddress(AddressList* address) const;
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual int GetLocalAddress(IPEndPoint* address) const;
5621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual const BoundNetLog& NetLog() const;
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void SetSubresourceSpeculation();
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void SetOmniboxSpeculation();
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual bool WasEverUsed() const;
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual bool UsingTCPFastOpen() const;
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Socket methods:
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Multiple outstanding requests are not supported.
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Full duplex mode (reading and writing at the same time) is supported
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual bool SetReceiveBufferSize(int32 size);
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual bool SetSendBufferSize(int32 size);
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // State machine for connecting the socket.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  enum ConnectState {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CONNECT_STATE_CONNECT,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CONNECT_STATE_CONNECT_COMPLETE,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CONNECT_STATE_NONE,
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  class ReadWatcher : public MessageLoopForIO::Watcher {
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott   public:
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    explicit ReadWatcher(TCPClientSocketLibevent* socket) : socket_(socket) {}
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // MessageLoopForIO::Watcher methods
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    virtual void OnFileCanReadWithoutBlocking(int /* fd */) {
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (socket_->read_callback_)
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        socket_->DidCompleteRead();
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    virtual void OnFileCanWriteWithoutBlocking(int /* fd */) {}
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott   private:
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TCPClientSocketLibevent* const socket_;
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DISALLOW_COPY_AND_ASSIGN(ReadWatcher);
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  };
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  class WriteWatcher : public MessageLoopForIO::Watcher {
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott   public:
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    explicit WriteWatcher(TCPClientSocketLibevent* socket) : socket_(socket) {}
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // MessageLoopForIO::Watcher methods
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    virtual void OnFileCanReadWithoutBlocking(int /* fd */) {}
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    virtual void OnFileCanWriteWithoutBlocking(int /* fd */) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (socket_->waiting_connect()) {
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        socket_->DidCompleteConnect();
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      } else if (socket_->write_callback_) {
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        socket_->DidCompleteWrite();
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott   private:
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TCPClientSocketLibevent* const socket_;
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DISALLOW_COPY_AND_ASSIGN(WriteWatcher);
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  };
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // State machine used by Connect().
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoConnectLoop(int result);
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int DoConnect();
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int DoConnectComplete(int result);
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Helper used by Disconnect(), which disconnects minus the logging and
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // resetting of current_ai_.
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void DoDisconnect();
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DoReadCallback(int rv);
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DoWriteCallback(int rv);
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DidCompleteRead();
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DidCompleteWrite();
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DidCompleteConnect();
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns true if a Connect() is in progress.
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool waiting_connect() const {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return next_connect_state_ != CONNECT_STATE_NONE;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns the OS error code (or 0 on success).
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int CreateSocket(const struct addrinfo* ai);
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Returns the OS error code (or 0 on success).
1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int SetupSocket();
1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Helper to add a TCP_CONNECT (end) event to the NetLog.
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void LogConnectCompletion(int net_error);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Internal function to write to a socket.
149513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int InternalWrite(IOBuffer* buf, int buf_len);
150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int socket_;
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The list of addresses we should try in order to establish a connection.
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AddressList addresses_;
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Where we are in above list, or NULL if all addrinfos have been tried.
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const struct addrinfo* current_ai_;
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The socket's libevent wrappers
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoopForIO::FileDescriptorWatcher read_socket_watcher_;
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoopForIO::FileDescriptorWatcher write_socket_watcher_;
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The corresponding watchers for reads and writes.
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ReadWatcher read_watcher_;
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WriteWatcher write_watcher_;
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The buffer used by OnSocketReady to retry Read requests
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<IOBuffer> read_buf_;
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int read_buf_len_;
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The buffer used by OnSocketReady to retry Write requests
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<IOBuffer> write_buf_;
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int write_buf_len_;
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // External callback; called when read is complete.
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* read_callback_;
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // External callback; called when write is complete.
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* write_callback_;
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The next state for the Connect() state machine.
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConnectState next_connect_state_;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The OS error that CONNECT_STATE_CONNECT last completed with.
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int connect_os_error_;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BoundNetLog net_log_;
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // This socket was previously disconnected and has not been re-connected.
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool previously_disconnected_;
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Record of connectivity and transmissions, for use in speculative connection
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // histograms.
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UseHistory use_history_;
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Enables experimental TCP FastOpen option.
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool use_tcp_fastopen_;
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
199513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // True when TCP FastOpen is in use and we have done the connect.
200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool tcp_fastopen_connected_;
201513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
2027b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
2037b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen  // True if connect should block and not return before the socket is connected
2047b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen  bool wait_for_connect_;
205e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma  bool valid_uid_;
206e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma  uid_t calling_uid_;
2077b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent);
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif  // NET_SOCKET_TCP_CLIENT_SOCKET_LIBEVENT_H_
214