1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2009 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#include "net/socket/socks_client_socket.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/basictypes.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/compiler_specific.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/trace_event.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/load_log.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_util.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/sys_addrinfo.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Every SOCKS server requests a user-id from the client. It is optional
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// and we send an empty string.
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char kEmptyUserId[] = "";
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The SOCKS4a implementation suggests to use an invalid IP in case the DNS
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// resolution at client fails.
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kInvalidIp[] = { 0, 0, 0, 127 };
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// For SOCKS4, the client sends 8 bytes  plus the size of the user-id.
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// For SOCKS4A, this increases to accomodate the unresolved hostname.
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const unsigned int kWriteHeaderSize = 8;
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// For SOCKS4 and SOCKS4a, the server sends 8 bytes for acknowledgement.
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const unsigned int kReadHeaderSize = 8;
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Server Response codes for SOCKS.
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseOk  = 0x5A;
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseRejected = 0x5B;
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseNotReachable = 0x5C;
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseMismatchedUserId = 0x5D;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kSOCKSVersion4 = 0x04;
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kSOCKSStreamRequest = 0x01;
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A struct holding the essential details of the SOCKS4/4a Server Request.
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The port in the header is stored in network byte order.
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct SOCKS4ServerRequest {
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 version;
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 command;
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint16 nw_port;
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 ip[4];
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(sizeof(SOCKS4ServerRequest) == kWriteHeaderSize,
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               socks4_server_request_struct_wrong_size);
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A struct holding details of the SOCKS4/4a Server Response.
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct SOCKS4ServerResponse {
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 reserved_null;
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 code;
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint16 port;
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 ip[4];
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(sizeof(SOCKS4ServerResponse) == kReadHeaderSize,
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               socks4_server_response_struct_wrong_size);
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSOCKSClientSocket::SOCKSClientSocket(ClientSocket* transport_socket,
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                     const HostResolver::RequestInfo& req_info,
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                     HostResolver* host_resolver)
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : ALLOW_THIS_IN_INITIALIZER_LIST(
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          io_callback_(this, &SOCKSClientSocket::OnIOComplete)),
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      transport_(transport_socket),
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_(STATE_NONE),
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      socks_version_(kSOCKS4Unresolved),
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      user_callback_(NULL),
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      completed_handshake_(false),
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bytes_sent_(0),
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bytes_received_(0),
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      host_resolver_(host_resolver),
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      host_request_info_(req_info) {
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSOCKSClientSocket::~SOCKSClientSocket() {
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Disconnect();
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::Connect(CompletionCallback* callback,
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                               LoadLog* load_log) {
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(transport_.get());
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(transport_->IsConnected());
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(STATE_NONE, next_state_);
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!user_callback_);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If already connected, then just return OK.
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (completed_handshake_)
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return OK;
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_HOST;
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  load_log_ = load_log;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LoadLog::BeginEvent(load_log, LoadLog::TYPE_SOCKS_CONNECT);
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv = DoLoop(OK);
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == ERR_IO_PENDING) {
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    user_callback_ = callback;
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LoadLog::EndEvent(load_log, LoadLog::TYPE_SOCKS_CONNECT);
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    load_log_ = NULL;
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SOCKSClientSocket::Disconnect() {
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  completed_handshake_ = false;
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  host_resolver_.Cancel();
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  transport_->Disconnect();
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Reset other states to make sure they aren't mistakenly used later.
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // These are the states initialized by Connect().
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_NONE;
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  user_callback_ = NULL;
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  load_log_ = NULL;
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::IsConnected() const {
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return completed_handshake_ && transport_->IsConnected();
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::IsConnectedAndIdle() const {
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return completed_handshake_ && transport_->IsConnectedAndIdle();
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Read is called by the transport layer above to read. This can only be done
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// if the SOCKS handshake is complete.
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::Read(IOBuffer* buf, int buf_len,
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            CompletionCallback* callback) {
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(completed_handshake_);
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(STATE_NONE, next_state_);
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!user_callback_);
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->Read(buf, buf_len, callback);
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Write is called by the transport layer. This can only be done if the
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// SOCKS handshake is complete.
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::Write(IOBuffer* buf, int buf_len,
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             CompletionCallback* callback) {
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(completed_handshake_);
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(STATE_NONE, next_state_);
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!user_callback_);
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->Write(buf, buf_len, callback);
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::SetReceiveBufferSize(int32 size) {
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->SetReceiveBufferSize(size);
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::SetSendBufferSize(int32 size) {
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->SetSendBufferSize(size);
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SOCKSClientSocket::DoCallback(int result) {
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(ERR_IO_PENDING, result);
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(user_callback_);
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Since Run() may result in Read being called,
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // clear user_callback_ up front.
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* c = user_callback_;
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  user_callback_ = NULL;
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DLOG(INFO) << "Finished setting up SOCKS handshake";
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  c->Run(result);
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SOCKSClientSocket::OnIOComplete(int result) {
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(STATE_NONE, next_state_);
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv = DoLoop(result);
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv != ERR_IO_PENDING) {
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LoadLog::EndEvent(load_log_, LoadLog::TYPE_SOCKS_CONNECT);
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    load_log_ = NULL;
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DoCallback(rv);
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoLoop(int last_io_result) {
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(next_state_, STATE_NONE);
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv = last_io_result;
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  do {
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    State state = next_state_;
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_NONE;
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    switch (state) {
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_HOST:
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, rv);
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoResolveHost();
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_HOST_COMPLETE:
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoResolveHostComplete(rv);
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_WRITE:
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, rv);
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeWrite();
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_WRITE_COMPLETE:
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeWriteComplete(rv);
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_READ:
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, rv);
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeRead();
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_READ_COMPLETE:
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeReadComplete(rv);
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      default:
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        NOTREACHED() << "bad state";
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = ERR_UNEXPECTED;
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoResolveHost() {
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kSOCKS4Unresolved, socks_version_);
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_HOST_COMPLETE;
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return host_resolver_.Resolve(
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      host_request_info_, &addresses_, &io_callback_, load_log_);
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoResolveHostComplete(int result) {
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kSOCKS4Unresolved, socks_version_);
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool ok = (result == OK);
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_HANDSHAKE_WRITE;
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (ok) {
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(addresses_.head());
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // If the host is resolved to an IPv6 address, we revert to SOCKS4a
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // since IPv6 is unsupported by SOCKS4/4a protocol.
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct sockaddr *host_info = addresses_.head()->ai_addr;
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (host_info->sa_family == AF_INET) {
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DLOG(INFO) << "Resolved host. Using SOCKS4 to communicate";
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      socks_version_ = kSOCKS4;
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DLOG(INFO) << "Resolved host but to IPv6. Using SOCKS4a to communicate";
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      socks_version_ = kSOCKS4a;
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DLOG(INFO) << "Could not resolve host. Using SOCKS4a to communicate";
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    socks_version_ = kSOCKS4a;
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Even if DNS resolution fails, we send OK since the server
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // resolves the domain.
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Builds the buffer that is to be sent to the server.
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We check whether the SOCKS proxy is 4 or 4A.
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// In case it is 4A, the record size increases by size of the hostname.
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst std::string SOCKSClientSocket::BuildHandshakeWriteBuffer() const {
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(kSOCKS4Unresolved, socks_version_);
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SOCKS4ServerRequest request;
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request.version = kSOCKSVersion4;
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request.command = kSOCKSStreamRequest;
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request.nw_port = htons(host_request_info_.port());
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (socks_version_ == kSOCKS4) {
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const struct addrinfo* ai = addresses_.head();
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(ai);
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // If the sockaddr is IPv6, we have already marked the version to socks4a
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // and so this step does not get hit.
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    struct sockaddr_in* ipv4_host =
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memcpy(&request.ip, &(ipv4_host->sin_addr), sizeof(ipv4_host->sin_addr));
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DLOG(INFO) << "Resolved Host is : " << NetAddressToString(ai);
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (socks_version_ == kSOCKS4a) {
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // invalid IP of the form 0.0.0.127
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memcpy(&request.ip, kInvalidIp, arraysize(kInvalidIp));
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string handshake_data(reinterpret_cast<char*>(&request),
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             sizeof(request));
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handshake_data.append(kEmptyUserId, arraysize(kEmptyUserId));
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // In case we are passing the domain also, pass the hostname
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // terminated with a null character.
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (socks_version_ == kSOCKS4a) {
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    handshake_data.append(host_request_info_.hostname());
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    handshake_data.push_back('\0');
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return handshake_data;
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Writes the SOCKS handshake data to the underlying socket connection.
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeWrite() {
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE;
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (buffer_.empty()) {
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    buffer_ = BuildHandshakeWriteBuffer();
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bytes_sent_ = 0;
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int handshake_buf_len = buffer_.size() - bytes_sent_;
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_GT(handshake_buf_len, 0);
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handshake_buf_ = new IOBuffer(handshake_buf_len);
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(handshake_buf_->data(), &buffer_[bytes_sent_],
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         handshake_buf_len);
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->Write(handshake_buf_, handshake_buf_len, &io_callback_);
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeWriteComplete(int result) {
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(kSOCKS4Unresolved, socks_version_);
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < 0)
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We ignore the case when result is 0, since the underlying Write
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // may return spurious writes while waiting on the socket.
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bytes_sent_ += result;
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bytes_sent_ == buffer_.size()) {
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_HANDSHAKE_READ;
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    buffer_.clear();
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (bytes_sent_ < buffer_.size()) {
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_HANDSHAKE_WRITE;
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeRead() {
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(kSOCKS4Unresolved, socks_version_);
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (buffer_.empty()) {
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bytes_received_ = 0;
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int handshake_buf_len = kReadHeaderSize - bytes_received_;
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handshake_buf_ = new IOBuffer(handshake_buf_len);
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->Read(handshake_buf_, handshake_buf_len, &io_callback_);
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeReadComplete(int result) {
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(kSOCKS4Unresolved, socks_version_);
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < 0)
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The underlying socket closed unexpectedly.
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == 0)
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_CONNECTION_CLOSED;
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bytes_received_ + result > kReadHeaderSize)
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_INVALID_RESPONSE;
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  buffer_.append(handshake_buf_->data(), result);
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bytes_received_ += result;
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bytes_received_ < kReadHeaderSize) {
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_HANDSHAKE_READ;
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return OK;
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const SOCKS4ServerResponse* response =
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<const SOCKS4ServerResponse*>(buffer_.data());
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (response->reserved_null != 0x00) {
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Unknown response from SOCKS server.";
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_INVALID_RESPONSE;
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(arindam): Add SOCKS specific failure codes in net_error_list.h
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (response->code) {
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseOk:
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      completed_handshake_ = true;
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return OK;
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseRejected:
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS request rejected or failed";
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_FAILED;
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseNotReachable:
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS request failed because client is not running "
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                 << "identd (or not reachable from the server)";
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_NAME_NOT_RESOLVED;
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseMismatchedUserId:
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS request failed because client's identd could "
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                 << "not confirm the user ID string in the request";
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_FAILED;
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS server sent unknown response";
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_INVALID_RESPONSE;
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Note: we ignore the last 6 bytes as specified by the SOCKS protocol
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::GetPeerName(struct sockaddr* name,
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   socklen_t* namelen) {
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return transport_->GetPeerName(name, namelen);
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
406