1f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/*
2f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *
4f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
5f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
6f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
7f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
8f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org */
10f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
11f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(_MSC_VER) && _MSC_VER < 1300
12f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#pragma warning(disable:4786)
13f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif
14f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
15f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <time.h>
16f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <errno.h>
17f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
18f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(WEBRTC_WIN)
19f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#define WIN32_LEAN_AND_MEAN
20f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <windows.h>
21f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <winsock2.h>
22f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <ws2tcpip.h>
23f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#define SECURITY_WIN32
24f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <security.h>
25f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif
26f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
27ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org#include <algorithm>
28ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org
29f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/bytebuffer.h"
30f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/common.h"
31f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/httpcommon.h"
32f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/logging.h"
33f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/socketadapters.h"
34f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/stringencode.h"
35f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/stringutils.h"
36f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
37f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(WEBRTC_WIN)
38f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/sec_buffer.h"
39f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif  // WEBRTC_WIN
40f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
41f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgnamespace rtc {
42f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
43f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgBufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t size)
44f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    : AsyncSocketAdapter(socket), buffer_size_(size),
45f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      data_len_(0), buffering_(false) {
46f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffer_ = new char[buffer_size_];
47f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
48f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
49f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgBufferedReadAdapter::~BufferedReadAdapter() {
50f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  delete [] buffer_;
51f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
52f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
53f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint BufferedReadAdapter::Send(const void *pv, size_t cb) {
54f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buffering_) {
55f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    // TODO: Spoof error better; Signal Writeable
56f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    socket_->SetError(EWOULDBLOCK);
57f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return -1;
58f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
59f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return AsyncSocketAdapter::Send(pv, cb);
60f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
61f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
62f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint BufferedReadAdapter::Recv(void *pv, size_t cb) {
63f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (buffering_) {
64f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    socket_->SetError(EWOULDBLOCK);
65f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return -1;
66f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
67f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
68f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t read = 0;
69f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
70f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (data_len_) {
71ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org    read = std::min(cb, data_len_);
72f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    memcpy(pv, buffer_, read);
73f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    data_len_ -= read;
74f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (data_len_ > 0) {
75f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      memmove(buffer_, buffer_ + read, data_len_);
76f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
77f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    pv = static_cast<char *>(pv) + read;
78f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    cb -= read;
79f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
80f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
81f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // FIX: If cb == 0, we won't generate another read event
82f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
83f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int res = AsyncSocketAdapter::Recv(pv, cb);
84c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef  if (res >= 0) {
85c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef    // Read from socket and possibly buffer; return combined length
86c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef    return res + static_cast<int>(read);
87c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef  }
88c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef
89c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef  if (read > 0) {
90c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef    // Failed to read from socket, but still read something from buffer
91c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef    return static_cast<int>(read);
92c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef  }
93f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
94c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef  // Didn't read anything; return error from socket
95c5d0d95fd8957a7a6645b1196e5f1e9cee33525cdeadbeef  return res;
96f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
97f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
98f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid BufferedReadAdapter::BufferInput(bool on) {
99f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  buffering_ = on;
100f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
101f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
102f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) {
103f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ASSERT(socket == socket_);
104f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
105f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!buffering_) {
106f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    AsyncSocketAdapter::OnReadEvent(socket);
107f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
108f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
109f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
110f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (data_len_ >= buffer_size_) {
111f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    LOG(INFO) << "Input buffer overflow";
112f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    ASSERT(false);
113f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    data_len_ = 0;
114f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
115f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
116f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int len = socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_);
117f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (len < 0) {
118f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    // TODO: Do something better like forwarding the error to the user.
119f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    LOG_ERR(INFO) << "Recv";
120f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
121f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
122f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
123f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  data_len_ += len;
124f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
125f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ProcessInput(buffer_, &data_len_);
126f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
127f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
12867186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.orgAsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
12967186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.org                                               size_t buffer_size)
13067186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.org    : BufferedReadAdapter(socket, buffer_size) {
13167186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.org}
13267186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.org
13367186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.orgAsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
13467186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.org
135f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
136f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
137f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// This is a SSL v2 CLIENT_HELLO message.
138f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// TODO: Should this have a session id? The response doesn't have a
139f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// certificate, so the hello should have a session id.
1400c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmstatic const uint8_t kSslClientHello[] = {
1410c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x80, 0x46,                                            // msg len
1420c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x01,                                                  // CLIENT_HELLO
1430c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x03, 0x01,                                            // SSL 3.1
1440c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x2d,                                            // ciphersuite len
1450c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x00,                                            // session id len
1460c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x10,                                            // challenge len
1470c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0,  // ciphersuites
1480c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80,  //
1490c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a,  //
1500c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64,  //
1510c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06,  //
1520c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc,        // challenge
1530c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea         //
154f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org};
155f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
156f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// This is a TLSv1 SERVER_HELLO message.
1570c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmstatic const uint8_t kSslServerHello[] = {
1580c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x16,                                            // handshake message
1590c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x03, 0x01,                                      // SSL 3.1
1600c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x4a,                                      // message len
1610c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x02,                                            // SERVER_HELLO
1620c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x00, 0x46,                                // handshake len
1630c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x03, 0x01,                                      // SSL 3.1
1640c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0,  // server random
1650c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f,  //
1660c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1,  //
1670c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f,  //
1680c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x20,                                            // session id len
1690c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f,  // session id
1700c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b,  //
1710c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38,  //
1720c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c,  //
1730c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00, 0x04,                                      // RSA/RC4-128/MD5
1740c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    0x00                                             // null compression
175f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org};
176f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
177f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgAsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
178f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    : BufferedReadAdapter(socket, 1024) {
179f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
180f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
181f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint AsyncSSLSocket::Connect(const SocketAddress& addr) {
182f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Begin buffering before we connect, so that there isn't a race condition
183f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // between potential senders and receiving the OnConnectEvent signal
184f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(true);
185f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return BufferedReadAdapter::Connect(addr);
186f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
187f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
188f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) {
189f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ASSERT(socket == socket_);
190f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: we could buffer output too...
191f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  VERIFY(sizeof(kSslClientHello) ==
192f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      DirectSend(kSslClientHello, sizeof(kSslClientHello)));
193f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
194f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
195f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSSLSocket::ProcessInput(char* data, size_t* len) {
196f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (*len < sizeof(kSslServerHello))
197f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
198f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
199f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (memcmp(kSslServerHello, data, sizeof(kSslServerHello)) != 0) {
200f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Close();
201f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SignalCloseEvent(this, 0);  // TODO: error code?
202f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
203f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
204f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
205f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  *len -= sizeof(kSslServerHello);
206f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (*len > 0) {
207f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    memmove(data, data + sizeof(kSslServerHello), *len);
208f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
209f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
210f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  bool remainder = (*len > 0);
211f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
212f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalConnectEvent(this);
213f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
214f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
215f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (remainder)
216f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SignalReadEvent(this);
217f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
218f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
219f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgAsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
220f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org     : BufferedReadAdapter(socket, 1024) {
221f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(true);
222f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
223f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
224f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
225f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // We only accept client hello messages.
226f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (*len < sizeof(kSslClientHello)) {
227f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
228f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
229f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
230f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (memcmp(kSslClientHello, data, sizeof(kSslClientHello)) != 0) {
231f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Close();
232f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SignalCloseEvent(this, 0);
233f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
234f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
235f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
236f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  *len -= sizeof(kSslClientHello);
237f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
238f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Clients should not send more data until the handshake is completed.
239f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ASSERT(*len == 0);
240f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
241f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Send a server hello back to the client.
242f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(kSslServerHello, sizeof(kSslServerHello));
243f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
244f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Handshake completed for us, redirect input to our parent.
245f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
246f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
247f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
248f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
249f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
250f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgAsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
251f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const std::string& user_agent,
252f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const SocketAddress& proxy,
253f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const std::string& username,
254f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const CryptString& password)
255f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  : BufferedReadAdapter(socket, 1024), proxy_(proxy), agent_(user_agent),
256f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    user_(username), pass_(password), force_connect_(false), state_(PS_ERROR),
257f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    context_(0) {
258f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
259f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
260f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgAsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
261f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  delete context_;
262f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
263f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
264f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
265f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int ret;
266f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect("
267f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                  << proxy_.ToSensitiveString() << ")";
268f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  dest_ = addr;
269f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = PS_INIT;
270f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (ShouldIssueConnect()) {
271f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    BufferInput(true);
272f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
273f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ret = BufferedReadAdapter::Connect(proxy_);
274f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: Set state_ appropriately if Connect fails.
275f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return ret;
276f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
277f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
278f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgSocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
279f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return dest_;
280f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
281f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
282f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint AsyncHttpsProxySocket::Close() {
283f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  headers_.clear();
284f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = PS_ERROR;
285f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  dest_.Clear();
286f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  delete context_;
287f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  context_ = NULL;
288f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return BufferedReadAdapter::Close();
289f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
290f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
291f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgSocket::ConnState AsyncHttpsProxySocket::GetState() const {
292f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ < PS_TUNNEL) {
293f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return CS_CONNECTING;
294f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == PS_TUNNEL) {
295f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return CS_CONNECTED;
296f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
297f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return CS_CLOSED;
298f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
299f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
300f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
301f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) {
302f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
303f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!ShouldIssueConnect()) {
304f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    state_ = PS_TUNNEL;
305f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    BufferedReadAdapter::OnConnectEvent(socket);
306f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
307f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
308f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SendRequest();
309f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
310f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
311f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) {
312f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
313f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
314f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    state_ = PS_ERROR;
315f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Connect(dest_);
316f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
317f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    BufferedReadAdapter::OnCloseEvent(socket, err);
318f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
319f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
320f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
321f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::ProcessInput(char* data, size_t* len) {
322f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t start = 0;
323f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  for (size_t pos = start; state_ < PS_TUNNEL && pos < *len;) {
324f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (state_ == PS_SKIP_BODY) {
325ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org      size_t consume = std::min(*len - pos, content_length_);
326f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      pos += consume;
327f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      start = pos;
328f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      content_length_ -= consume;
329f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (content_length_ == 0) {
330f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        EndResponse();
331f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
332f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      continue;
333f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
334f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
335f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (data[pos++] != '\n')
336f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      continue;
337f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
338f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    size_t len = pos - start - 1;
339f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((len > 0) && (data[start + len - 1] == '\r'))
340f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      --len;
341f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
342f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    data[start + len] = 0;
343f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    ProcessLine(data + start, len);
344f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    start = pos;
345f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
346f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
347f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  *len -= start;
348f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (*len > 0) {
349f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    memmove(data, data + start, *len);
350f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
351f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
352f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ != PS_TUNNEL)
353f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
354f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
355f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  bool remainder = (*len > 0);
356f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
357f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalConnectEvent(this);
358f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
359f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
360f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (remainder)
361f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SignalReadEvent(this);  // TODO: signal this??
362f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
363f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
364f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgbool AsyncHttpsProxySocket::ShouldIssueConnect() const {
365f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: Think about whether a more sophisticated test
366f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // than dest port == 80 is needed.
367f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return force_connect_ || (dest_.port() != 80);
368f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
369f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
370f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::SendRequest() {
371f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  std::stringstream ss;
372f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
373f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << "User-Agent: " << agent_ << "\r\n";
374f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << "Host: " << dest_.HostAsURIString() << "\r\n";
375f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << "Content-Length: 0\r\n";
376f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << "Proxy-Connection: Keep-Alive\r\n";
377f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << headers_;
378f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ss << "\r\n";
379f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  std::string str = ss.str();
380f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(str.c_str(), str.size());
381f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = PS_LEADER;
382f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  expect_close_ = true;
383f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  content_length_ = 0;
384f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  headers_.clear();
385f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
386f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
387f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
388f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
389f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) {
390f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
391f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
392f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (len == 0) {
393f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (state_ == PS_TUNNEL_HEADERS) {
394f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_TUNNEL;
395f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if (state_ == PS_ERROR_HEADERS) {
396f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(defer_error_);
397f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
398f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if (state_ == PS_SKIP_HEADERS) {
399f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (content_length_) {
400f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        state_ = PS_SKIP_BODY;
401f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      } else {
402f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        EndResponse();
403f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        return;
404f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
405f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
406f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      static bool report = false;
407f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (!unknown_mechanisms_.empty() && !report) {
408f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        report = true;
409f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        std::string msg(
410f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "Unable to connect to the Google Talk service due to an incompatibility "
411f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "with your proxy.\r\nPlease help us resolve this issue by submitting the "
412f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "following information to us using our technical issue submission form "
413f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "at:\r\n\r\n"
414f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
415f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "We apologize for the inconvenience.\r\n\r\n"
416f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          "Information to submit to Google: "
417f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          );
418f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: ");
419f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        msg.append(unknown_mechanisms_);
420f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(WEBRTC_WIN)
421f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
422f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif
423f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(WEBRTC_POSIX)
424f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        // TODO: Raise a signal so the UI can be separated.
425f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        LOG(LS_ERROR) << "Oops!\n\n" << msg;
426f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif
427f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      }
428f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      // Unexpected end of headers
429f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
430f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
431f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
432f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == PS_LEADER) {
433f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    unsigned int code;
434f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (sscanf(data, "HTTP/%*u.%*u %u", &code) != 1) {
435f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
436f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
437f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
438f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    switch (code) {
439f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case 200:
440f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      // connection good!
441f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_TUNNEL_HEADERS;
442f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
443f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
444f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
445f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif
446f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case 407:  // HTTP_STATUS_PROXY_AUTH_REQ
447f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_AUTHENTICATE;
448f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
449f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    default:
450f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      defer_error_ = 0;
451f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_ERROR_HEADERS;
452f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
453f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
454f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if ((state_ == PS_AUTHENTICATE)
455f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org             && (_strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
456f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    std::string response, auth_method;
457f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    switch (HttpAuthenticate(data + 19, len - 19,
458f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                             proxy_, "CONNECT", "/",
459f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                             user_, pass_, context_, response, auth_method)) {
460f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case HAR_IGNORE:
461f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
462f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (!unknown_mechanisms_.empty())
463f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        unknown_mechanisms_.append(", ");
464f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      unknown_mechanisms_.append(auth_method);
465f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      break;
466f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case HAR_RESPONSE:
467f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      headers_ = "Proxy-Authorization: ";
468f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      headers_.append(response);
469f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      headers_.append("\r\n");
470f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_SKIP_HEADERS;
471f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      unknown_mechanisms_.clear();
472f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      break;
473f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case HAR_CREDENTIALS:
474f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      defer_error_ = SOCKET_EACCES;
475f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_ERROR_HEADERS;
476f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      unknown_mechanisms_.clear();
477f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      break;
478f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    case HAR_ERROR:
479f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      defer_error_ = 0;
480f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      state_ = PS_ERROR_HEADERS;
481f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      unknown_mechanisms_.clear();
482f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      break;
483f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
484f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (_strnicmp(data, "Content-Length:", 15) == 0) {
485f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    content_length_ = strtoul(data + 15, 0, 0);
486f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (_strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) {
487f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    expect_close_ = false;
488f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    /*
489f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (_strnicmp(data, "Connection: close", 17) == 0) {
490f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    expect_close_ = true;
491f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    */
492f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
493f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
494f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
495f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::EndResponse() {
496f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!expect_close_) {
497f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SendRequest();
498f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
499f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
500f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
501f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // No point in waiting for the server to close... let's close now
502f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: Refactor out PS_WAIT_CLOSE
503f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = PS_WAIT_CLOSE;
504f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferedReadAdapter::Close();
505f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  OnCloseEvent(this, 0);
506f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
507f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
508f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncHttpsProxySocket::Error(int error) {
509f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
510f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  Close();
511f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SetError(error);
512f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalCloseEvent(this, error);
513f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
514f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
515f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
516f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
517f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgAsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket,
518f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const SocketAddress& proxy,
519f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const std::string& username,
520f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                             const CryptString& password)
521f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    : BufferedReadAdapter(socket, 1024), state_(SS_ERROR), proxy_(proxy),
522f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      user_(username), pass_(password) {
523f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
524f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
52567186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.orgAsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
52667186fe00cc68cbe03aa66d17fb4962458ca96d2kwiberg@webrtc.org
527f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
528f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int ret;
529f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  dest_ = addr;
530f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_INIT;
531f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(true);
532f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ret = BufferedReadAdapter::Connect(proxy_);
533f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: Set state_ appropriately if Connect fails.
534f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return ret;
535f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
536f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
537f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgSocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
538f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return dest_;
539f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
540f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
541f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint AsyncSocksProxySocket::Close() {
542f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_ERROR;
543f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  dest_.Clear();
544f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return BufferedReadAdapter::Close();
545f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
546f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
547f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgSocket::ConnState AsyncSocksProxySocket::GetState() const {
548f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ < SS_TUNNEL) {
549f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return CS_CONNECTING;
550f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == SS_TUNNEL) {
551f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return CS_CONNECTED;
552f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
553f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return CS_CLOSED;
554f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
555f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
556f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
557f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxySocket::OnConnectEvent(AsyncSocket* socket) {
558f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SendHello();
559f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
560f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
561f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
562f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ASSERT(state_ < SS_TUNNEL);
563f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
564f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer response(data, *len);
565f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
566f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ == SS_HELLO) {
5670c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    uint8_t ver, method;
568f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (!response.ReadUInt8(&ver) ||
569f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        !response.ReadUInt8(&method))
570f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
571f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
572f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (ver != 5) {
573f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
574f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
575f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
576f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
577f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (method == 0) {
578f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      SendConnect();
579f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if (method == 2) {
580f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      SendAuth();
581f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
582f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
583f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
584f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
585f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == SS_AUTH) {
5860c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    uint8_t ver, status;
587f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (!response.ReadUInt8(&ver) ||
588f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        !response.ReadUInt8(&status))
589f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
590f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
591f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ver != 1) || (status != 0)) {
592f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(SOCKET_EACCES);
593f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
594f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
595f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
596f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SendConnect();
597f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == SS_CONNECT) {
5980c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    uint8_t ver, rep, rsv, atyp;
599f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (!response.ReadUInt8(&ver) ||
600f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        !response.ReadUInt8(&rep) ||
601f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        !response.ReadUInt8(&rsv) ||
602f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        !response.ReadUInt8(&atyp))
603f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
604f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
605f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if ((ver != 5) || (rep != 0)) {
606f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
607f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
608f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
609f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
6100c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    uint16_t port;
611f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    if (atyp == 1) {
6120c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström      uint32_t addr;
613f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (!response.ReadUInt32(&addr) ||
614f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          !response.ReadUInt16(&port))
615f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        return;
616f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
617f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if (atyp == 3) {
6180c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström      uint8_t len;
619f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      std::string addr;
620f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (!response.ReadUInt8(&len) ||
621f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          !response.ReadString(&addr, len) ||
622f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          !response.ReadUInt16(&port))
623f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        return;
624f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
625f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else if (atyp == 4) {
626f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      std::string addr;
627f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      if (!response.ReadString(&addr, 16) ||
628f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org          !response.ReadUInt16(&port))
629f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org        return;
630f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
631f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    } else {
632f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
633f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
634f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    }
635f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
636f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    state_ = SS_TUNNEL;
637f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
638f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
639f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Consume parsed data
640f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  *len = response.Length();
641f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  memcpy(data, response.Data(), *len);
642f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
643f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ != SS_TUNNEL)
644f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
645f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
646f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  bool remainder = (*len > 0);
647f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
648f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalConnectEvent(this);
649f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
650f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
651f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (remainder)
652f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    SignalReadEvent(this);  // TODO: signal this??
653f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
654f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
655f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxySocket::SendHello() {
656f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer request;
657f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteUInt8(5);    // Socks Version
658f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (user_.empty()) {
659f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(1);  // Authentication Mechanisms
660f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(0);  // No authentication
661f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
662f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(2);  // Authentication Mechanisms
663f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(0);  // No authentication
664f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(2);  // Username/Password
665f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
666f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(request.Data(), request.Length());
667f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_HELLO;
668f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
669f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
670f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxySocket::SendAuth() {
671f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer request;
672f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteUInt8(1);           // Negotiation Version
6730c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  request.WriteUInt8(static_cast<uint8_t>(user_.size()));
674f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteString(user_);      // Username
6750c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
676f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  size_t len = pass_.GetLength() + 1;
677f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  char * sensitive = new char[len];
678f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  pass_.CopyTo(sensitive, true);
679f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteString(sensitive);  // Password
680f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  memset(sensitive, 0, len);
681f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  delete [] sensitive;
682f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(request.Data(), request.Length());
683f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_AUTH;
684f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
685f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
686f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxySocket::SendConnect() {
687f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer request;
688f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteUInt8(5);              // Socks Version
689f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteUInt8(1);              // CONNECT
690f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteUInt8(0);              // Reserved
69120a34619080005c3b0e49d85b307113ea2b180c3tfarina  if (dest_.IsUnresolvedIP()) {
692f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    std::string hostname = dest_.hostname();
693f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(3);            // DOMAINNAME
6940c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
695f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteString(hostname);    // Destination Hostname
696f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
697f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt8(1);            // IPV4
698f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    request.WriteUInt32(dest_.ip());  // Destination IP
699f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
700f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  request.WriteUInt16(dest_.port());  // Destination Port
701f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(request.Data(), request.Length());
702f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_CONNECT;
703f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
704f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
705f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxySocket::Error(int error) {
706f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_ERROR;
707f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
708f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  Close();
709f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SetError(SOCKET_EACCES);
710f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalCloseEvent(this, error);
711f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
712f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
713f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgAsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
714f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
715f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(true);
716f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
717f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
718f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
719f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: See if the whole message has arrived
720f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ASSERT(state_ < SS_CONNECT_PENDING);
721f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
722f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer response(data, *len);
723f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ == SS_HELLO) {
724f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    HandleHello(&response);
725f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == SS_AUTH) {
726f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    HandleAuth(&response);
727f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (state_ == SS_CONNECT) {
728f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    HandleConnect(&response);
729f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
730f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
731f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Consume parsed data
732f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  *len = response.Length();
733f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  memcpy(data, response.Data(), *len);
734f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
735f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
736f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::DirectSend(const ByteBuffer& buf) {
737f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
738f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
739f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
740f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::HandleHello(ByteBuffer* request) {
7410c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint8_t ver, num_methods;
742f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!request->ReadUInt8(&ver) ||
743f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt8(&num_methods)) {
744f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Error(0);
745f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
746f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
747f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
748f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (ver != 5) {
749f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Error(0);
750f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
751f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
752f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
753f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // Handle either no-auth (0) or user/pass auth (2)
7540c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint8_t method = 0xFF;
755f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (num_methods > 0 && !request->ReadUInt8(&method)) {
756f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Error(0);
757f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
758f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
759f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
760f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: Ask the server which method to use.
761f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SendHelloReply(method);
762f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (method == 0) {
763f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    state_ = SS_CONNECT;
764f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else if (method == 2) {
765f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    state_ = SS_AUTH;
766f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  } else {
767f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    state_ = SS_ERROR;
768f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
769f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
770f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
7710c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmvoid AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
772f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer response;
773f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(5);  // Socks Version
774f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(method);  // Auth method
775f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(response);
776f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
777f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
778f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::HandleAuth(ByteBuffer* request) {
7790c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint8_t ver, user_len, pass_len;
780f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  std::string user, pass;
781f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!request->ReadUInt8(&ver) ||
782f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt8(&user_len) ||
783f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadString(&user, user_len) ||
784f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt8(&pass_len) ||
785f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadString(&pass, pass_len)) {
786f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    Error(0);
787f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
788f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
789f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
790f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  // TODO: Allow for checking of credentials.
791f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SendAuthReply(0);
792f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_CONNECT;
793f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
794f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
7950c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmvoid AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
796f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer response;
797f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(1);  // Negotiation Version
798f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(result);
799f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(response);
800f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
801f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
802f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::HandleConnect(ByteBuffer* request) {
8030c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint8_t ver, command, reserved, addr_type;
8040c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint32_t ip;
8050c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint16_t port;
806f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (!request->ReadUInt8(&ver) ||
807f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt8(&command) ||
808f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt8(&reserved) ||
809f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt8(&addr_type) ||
810f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt32(&ip) ||
811f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      !request->ReadUInt16(&port)) {
812f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
813f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
814f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
815f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
816f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (ver != 5 || command != 1 ||
817f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      reserved != 0 || addr_type != 1) {
818f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      Error(0);
819f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org      return;
820f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  }
821f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
822f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalConnectRequest(this, SocketAddress(ip, port));
823f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_CONNECT_PENDING;
824f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
825f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
826f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::SendConnectResult(int result,
827f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                                    const SocketAddress& addr) {
828f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (state_ != SS_CONNECT_PENDING)
829f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    return;
830f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
831f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  ByteBuffer response;
832f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(5);  // Socks version
833f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8((result != 0));  // 0x01 is generic error
834f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(0);  // reserved
835f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt8(1);  // IPv4 address
836f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt32(addr.ip());
837f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  response.WriteUInt16(addr.port());
838f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  DirectSend(response);
839f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
840f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_TUNNEL;
841f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
842f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
843f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid AsyncSocksProxyServerSocket::Error(int error) {
844f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  state_ = SS_ERROR;
845f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  BufferInput(false);
846f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  Close();
847f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SetError(SOCKET_EACCES);
848f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  SignalCloseEvent(this, error);
849f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
850f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
851f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
852f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
853f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgLoggingSocketAdapter::LoggingSocketAdapter(AsyncSocket* socket,
854f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                           LoggingSeverity level,
855f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                                           const char * label, bool hex_mode)
856f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    : AsyncSocketAdapter(socket), level_(level), hex_mode_(hex_mode) {
857f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  label_.append("[");
858f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  label_.append(label);
859f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  label_.append("]");
860f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
861f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
862f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint LoggingSocketAdapter::Send(const void *pv, size_t cb) {
863f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int res = AsyncSocketAdapter::Send(pv, cb);
864f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (res > 0)
865f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    LogMultiline(level_, label_.c_str(), false, pv, res, hex_mode_, &lms_);
866f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return res;
867f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
868f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
869f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint LoggingSocketAdapter::SendTo(const void *pv, size_t cb,
870f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org                             const SocketAddress& addr) {
871f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int res = AsyncSocketAdapter::SendTo(pv, cb, addr);
872f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (res > 0)
873f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    LogMultiline(level_, label_.c_str(), false, pv, res, hex_mode_, &lms_);
874f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return res;
875f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
876f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
877f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint LoggingSocketAdapter::Recv(void *pv, size_t cb) {
878f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int res = AsyncSocketAdapter::Recv(pv, cb);
879f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (res > 0)
880f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    LogMultiline(level_, label_.c_str(), true, pv, res, hex_mode_, &lms_);
881f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return res;
882f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
883f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
884f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint LoggingSocketAdapter::RecvFrom(void *pv, size_t cb, SocketAddress *paddr) {
885f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
886f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  if (res > 0)
887f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org    LogMultiline(level_, label_.c_str(), true, pv, res, hex_mode_, &lms_);
888f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return res;
889f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
890f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
891f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgint LoggingSocketAdapter::Close() {
892f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LogMultiline(level_, label_.c_str(), false, NULL, 0, hex_mode_, &lms_);
893f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LogMultiline(level_, label_.c_str(), true, NULL, 0, hex_mode_, &lms_);
894f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG_V(level_) << label_ << " Closed locally";
895f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  return socket_->Close();
896f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
897f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
898f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid LoggingSocketAdapter::OnConnectEvent(AsyncSocket * socket) {
899f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG_V(level_) << label_ << " Connected";
900f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  AsyncSocketAdapter::OnConnectEvent(socket);
901f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
902f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
903f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgvoid LoggingSocketAdapter::OnCloseEvent(AsyncSocket * socket, int err) {
904f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LogMultiline(level_, label_.c_str(), false, NULL, 0, hex_mode_, &lms_);
905f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LogMultiline(level_, label_.c_str(), true, NULL, 0, hex_mode_, &lms_);
906f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  LOG_V(level_) << label_ << " Closed with error: " << err;
907f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org  AsyncSocketAdapter::OnCloseEvent(socket, err);
908f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}
909f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
910f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
911f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org
912f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}  // namespace rtc
913