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#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 "net/base/io_buffer.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_util.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/sys_addrinfo.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/socket/client_socket_handle.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// For SOCKS4, the client sends 8 bytes  plus the size of the user-id.
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const unsigned int kWriteHeaderSize = 8;
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// For SOCKS4 the server sends 8 bytes for acknowledgement.
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const unsigned int kReadHeaderSize = 8;
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Server Response codes for SOCKS.
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseOk  = 0x5A;
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseRejected = 0x5B;
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseNotReachable = 0x5C;
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kServerResponseMismatchedUserId = 0x5D;
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kSOCKSVersion4 = 0x04;
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const uint8 kSOCKSStreamRequest = 0x01;
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// A struct holding the essential details of the SOCKS4 Server Request.
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The port in the header is stored in network byte order.
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct SOCKS4ServerRequest {
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 version;
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 command;
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint16 nw_port;
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 ip[4];
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(sizeof(SOCKS4ServerRequest) == kWriteHeaderSize,
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               socks4_server_request_struct_wrong_size);
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// A struct holding details of the SOCKS4 Server Response.
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct SOCKS4ServerResponse {
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 reserved_null;
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 code;
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint16 port;
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 ip[4];
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(sizeof(SOCKS4ServerResponse) == kReadHeaderSize,
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott               socks4_server_response_struct_wrong_size);
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSOCKSClientSocket::SOCKSClientSocket(ClientSocketHandle* transport_socket,
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                     const HostResolver::RequestInfo& req_info,
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                     HostResolver* host_resolver)
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : ALLOW_THIS_IN_INITIALIZER_LIST(
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          io_callback_(this, &SOCKSClientSocket::OnIOComplete)),
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      transport_(transport_socket),
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_(STATE_NONE),
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      user_callback_(NULL),
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      completed_handshake_(false),
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bytes_sent_(0),
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bytes_received_(0),
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      host_resolver_(host_resolver),
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      host_request_info_(req_info),
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_(transport_socket->socket()->NetLog()) {
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSOCKSClientSocket::SOCKSClientSocket(ClientSocket* transport_socket,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const HostResolver::RequestInfo& req_info,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     HostResolver* host_resolver)
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : ALLOW_THIS_IN_INITIALIZER_LIST(
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          io_callback_(this, &SOCKSClientSocket::OnIOComplete)),
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transport_(new ClientSocketHandle()),
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_state_(STATE_NONE),
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      user_callback_(NULL),
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      completed_handshake_(false),
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bytes_sent_(0),
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bytes_received_(0),
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      host_resolver_(host_resolver),
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      host_request_info_(req_info),
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_(transport_socket->NetLog()) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transport_->set_socket(transport_socket);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSOCKSClientSocket::~SOCKSClientSocket() {
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Disconnect();
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
947b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
957b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen// TODO(kristianm): find out if Connect should block
967b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
977b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsenint SOCKSClientSocket::Connect(CompletionCallback* callback
987b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#ifdef ANDROID
997b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                               , bool wait_for_connect
100e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                               , bool valid_uid
101e14dcc5a172cad1c4716af7ab94121a73c0c698eAshish Sharma                               , uid_t calling_uid
1027b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen#endif
1037b9ca917061470268bf3395c8925d4b9cc52d8e1Kristian Monsen                              ) {
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(transport_.get());
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transport_->socket());
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(STATE_NONE, next_state_);
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!user_callback_);
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If already connected, then just return OK.
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (completed_handshake_)
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return OK;
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_HOST;
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net_log_.BeginEvent(NetLog::TYPE_SOCKS_CONNECT, NULL);
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv = DoLoop(OK);
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv == ERR_IO_PENDING) {
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    user_callback_ = callback;
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS_CONNECT, rv);
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SOCKSClientSocket::Disconnect() {
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  completed_handshake_ = false;
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  host_resolver_.Cancel();
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transport_->socket()->Disconnect();
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Reset other states to make sure they aren't mistakenly used later.
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // These are the states initialized by Connect().
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_NONE;
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  user_callback_ = NULL;
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::IsConnected() const {
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return completed_handshake_ && transport_->socket()->IsConnected();
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::IsConnectedAndIdle() const {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst BoundNetLog& SOCKSClientSocket::NetLog() const {
14621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return net_log_;
14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SOCKSClientSocket::SetSubresourceSpeculation() {
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetSubresourceSpeculation();
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SOCKSClientSocket::SetOmniboxSpeculation() {
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    transport_->socket()->SetOmniboxSpeculation();
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool SOCKSClientSocket::WasEverUsed() const {
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (transport_.get() && transport_->socket()) {
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return transport_->socket()->WasEverUsed();
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTREACHED();
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool SOCKSClientSocket::UsingTCPFastOpen() const {
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (transport_.get() && transport_->socket()) {
175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return transport_->socket()->UsingTCPFastOpen();
176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
177513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NOTREACHED();
178513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Read is called by the transport layer above to read. This can only be done
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// if the SOCKS handshake is complete.
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::Read(IOBuffer* buf, int buf_len,
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            CompletionCallback* callback) {
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(completed_handshake_);
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(STATE_NONE, next_state_);
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!user_callback_);
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Read(buf, buf_len, callback);
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Write is called by the transport layer. This can only be done if the
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// SOCKS handshake is complete.
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::Write(IOBuffer* buf, int buf_len,
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             CompletionCallback* callback) {
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(completed_handshake_);
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(STATE_NONE, next_state_);
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!user_callback_);
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Write(buf, buf_len, callback);
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::SetReceiveBufferSize(int32 size) {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetReceiveBufferSize(size);
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SOCKSClientSocket::SetSendBufferSize(int32 size) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->SetSendBufferSize(size);
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SOCKSClientSocket::DoCallback(int result) {
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(ERR_IO_PENDING, result);
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(user_callback_);
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Since Run() may result in Read being called,
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // clear user_callback_ up front.
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* c = user_callback_;
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  user_callback_ = NULL;
220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DVLOG(1) << "Finished setting up SOCKS handshake";
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  c->Run(result);
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SOCKSClientSocket::OnIOComplete(int result) {
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(STATE_NONE, next_state_);
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv = DoLoop(result);
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (rv != ERR_IO_PENDING) {
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS_CONNECT, rv);
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DoCallback(rv);
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoLoop(int last_io_result) {
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_NE(next_state_, STATE_NONE);
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv = last_io_result;
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  do {
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    State state = next_state_;
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_NONE;
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    switch (state) {
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_HOST:
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, rv);
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoResolveHost();
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_HOST_COMPLETE:
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoResolveHostComplete(rv);
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_WRITE:
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, rv);
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeWrite();
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_WRITE_COMPLETE:
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeWriteComplete(rv);
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_READ:
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, rv);
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeRead();
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_HANDSHAKE_READ_COMPLETE:
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = DoHandshakeReadComplete(rv);
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      default:
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        NOTREACHED() << "bad state";
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        rv = ERR_UNEXPECTED;
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoResolveHost() {
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_HOST_COMPLETE;
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // SOCKS4 only supports IPv4 addresses, so only try getting the IPv4
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // addresses for the target host.
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  host_request_info_.set_address_family(ADDRESS_FAMILY_IPV4);
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return host_resolver_.Resolve(
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      host_request_info_, &addresses_, &io_callback_, net_log_);
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoResolveHostComplete(int result) {
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (result != OK) {
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Resolving the hostname failed; fail the request rather than automatically
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // falling back to SOCKS4a (since it can be confusing to see invalid IP
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // addresses being sent to the SOCKS4 server when it doesn't support 4A.)
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return result;
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  next_state_ = STATE_HANDSHAKE_WRITE;
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Builds the buffer that is to be sent to the server.
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst std::string SOCKSClientSocket::BuildHandshakeWriteBuffer() const {
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SOCKS4ServerRequest request;
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request.version = kSOCKSVersion4;
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request.command = kSOCKSStreamRequest;
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request.nw_port = htons(host_request_info_.port());
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const struct addrinfo* ai = addresses_.head();
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(ai);
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We disabled IPv6 results when resolving the hostname, so none of the
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // results in the list will be IPv6.
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(eroman): we only ever use the first address in the list. It would be
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //               more robust to try all the IP addresses we have before
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //               failing the connect attempt.
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_EQ(AF_INET, ai->ai_addr->sa_family);
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  struct sockaddr_in* ipv4_host =
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  memcpy(&request.ip, &ipv4_host->sin_addr, sizeof(ipv4_host->sin_addr));
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DVLOG(1) << "Resolved Host is : " << NetAddressToString(ai);
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string handshake_data(reinterpret_cast<char*>(&request),
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             sizeof(request));
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handshake_data.append(kEmptyUserId, arraysize(kEmptyUserId));
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return handshake_data;
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Writes the SOCKS handshake data to the underlying socket connection.
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeWrite() {
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE;
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (buffer_.empty()) {
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    buffer_ = BuildHandshakeWriteBuffer();
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bytes_sent_ = 0;
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int handshake_buf_len = buffer_.size() - bytes_sent_;
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_GT(handshake_buf_len, 0);
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handshake_buf_ = new IOBuffer(handshake_buf_len);
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(handshake_buf_->data(), &buffer_[bytes_sent_],
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         handshake_buf_len);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Write(handshake_buf_, handshake_buf_len,
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     &io_callback_);
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeWriteComplete(int result) {
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < 0)
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We ignore the case when result is 0, since the underlying Write
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // may return spurious writes while waiting on the socket.
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bytes_sent_ += result;
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bytes_sent_ == buffer_.size()) {
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_HANDSHAKE_READ;
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    buffer_.clear();
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (bytes_sent_ < buffer_.size()) {
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_HANDSHAKE_WRITE;
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeRead() {
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (buffer_.empty()) {
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bytes_received_ = 0;
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int handshake_buf_len = kReadHeaderSize - bytes_received_;
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  handshake_buf_ = new IOBuffer(handshake_buf_len);
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->Read(handshake_buf_, handshake_buf_len,
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    &io_callback_);
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SOCKSClientSocket::DoHandshakeReadComplete(int result) {
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < 0)
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The underlying socket closed unexpectedly.
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == 0)
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_CONNECTION_CLOSED;
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bytes_received_ + result > kReadHeaderSize) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(eroman): Describe failure in NetLog.
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_SOCKS_CONNECTION_FAILED;
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  buffer_.append(handshake_buf_->data(), result);
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bytes_received_ += result;
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bytes_received_ < kReadHeaderSize) {
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_HANDSHAKE_READ;
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return OK;
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const SOCKS4ServerResponse* response =
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<const SOCKS4ServerResponse*>(buffer_.data());
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (response->reserved_null != 0x00) {
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Unknown response from SOCKS server.";
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_SOCKS_CONNECTION_FAILED;
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (response->code) {
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseOk:
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      completed_handshake_ = true;
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return OK;
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseRejected:
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS request rejected or failed";
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_SOCKS_CONNECTION_FAILED;
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseNotReachable:
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS request failed because client is not running "
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                 << "identd (or not reachable from the server)";
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_SOCKS_CONNECTION_HOST_UNREACHABLE;
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case kServerResponseMismatchedUserId:
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS request failed because client's identd could "
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                 << "not confirm the user ID string in the request";
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_SOCKS_CONNECTION_FAILED;
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "SOCKS server sent unknown response";
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_SOCKS_CONNECTION_FAILED;
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Note: we ignore the last 6 bytes as specified by the SOCKS protocol
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SOCKSClientSocket::GetPeerAddress(AddressList* address) const {
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transport_->socket()->GetPeerAddress(address);
424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint SOCKSClientSocket::GetLocalAddress(IPEndPoint* address) const {
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return transport_->socket()->GetLocalAddress(address);
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
431