Introduce PPB_TCPSocket_Dev.

This change exposes the PPB_TCPSocket_Dev interface and makes it to share the same backend as PPB_TCPSocket_Private.

It doesn't include:
- apps permission check;
- TCP socket options that PPB_TCPSocket_Private doesn't support.
These will be implemented in separate CLs.

BUG=247225
TEST=newly added test_tcp_socket.{h,cc}.

Review URL: https://chromiumcodereview.appspot.com/16667002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@206014 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/api/dev/ppb_tcp_socket_dev.idl b/ppapi/api/dev/ppb_tcp_socket_dev.idl
new file mode 100644
index 0000000..dfc038ad
--- /dev/null
+++ b/ppapi/api/dev/ppb_tcp_socket_dev.idl
@@ -0,0 +1,115 @@
+/* Copyright 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * This file defines the <code>PPB_TCPSocket_Dev</code> interface.
+ */
+
+[generate_thunk]
+
+label Chrome {
+  M29 = 0.1
+};
+
+[assert_size(4)]
+enum PP_TCPSocket_Option_Dev {
+  // Disables coalescing of small writes to make TCP segments, and instead
+  // deliver data immediately. Value type is PP_VARTYPE_BOOL.
+  PP_TCPSOCKET_OPTION_NO_DELAY = 0,
+
+  // Specifies the socket send buffer in bytes. Value's type should be
+  // PP_VARTYPE_INT32.
+  // Note: This is only treated as a hint for the browser to set the buffer
+  // size. Even if SetOption() reports that this option has been successfully
+  // set, the browser doesn't guarantee to conform to it.
+  PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE = 1,
+
+  // Specifies the socket receive buffer in bytes. Value's type should be
+  // PP_VARTYPE_INT32.
+  // Note: This is only treated as a hint for the browser to set the buffer
+  // size. Even if SetOption() reports that this option has been successfully
+  // set, the browser doesn't guarantee to conform to it.
+  PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE = 2
+};
+
+/**
+ * The <code>PPB_TCPSocket_Dev</code> interface provides TCP socket operations.
+ */
+interface PPB_TCPSocket_Dev {
+  /**
+   * Allocates a TCP socket resource.
+   */
+  PP_Resource Create([in] PP_Instance instance);
+
+  /**
+   * Determines if a given resource is TCP socket.
+   */
+  PP_Bool IsTCPSocket([in] PP_Resource resource);
+
+  /**
+   * Connects to an address given by |addr|, which is a PPB_NetAddress_Dev
+   * resource.
+   */
+  int32_t Connect([in] PP_Resource tcp_socket,
+                  [in] PP_Resource addr,
+                  [in] PP_CompletionCallback callback);
+
+  /**
+   * Gets the local address of the socket, if it has been connected.
+   * Returns a PPB_NetAddress_Dev resource on success; returns 0 on failure.
+   */
+  PP_Resource GetLocalAddress([in] PP_Resource tcp_socket);
+
+  /**
+   * Gets the remote address of the socket, if it has been connected.
+   * Returns a PPB_NetAddress_Dev resource on success; returns 0 on failure.
+   */
+  PP_Resource GetRemoteAddress([in] PP_Resource tcp_socket);
+
+  /**
+   * Reads data from the socket. The size of |buffer| must be at least as large
+   * as |bytes_to_read|. May perform a partial read. Returns the number of bytes
+   * read or an error code. If the return value is 0, then it indicates that
+   * end-of-file was reached.
+   *
+   * Multiple outstanding read requests are not supported.
+   */
+  int32_t Read([in] PP_Resource tcp_socket,
+               [out] str_t buffer,
+               [in] int32_t bytes_to_read,
+               [in] PP_CompletionCallback callback);
+
+  /**
+   * Writes data to the socket. May perform a partial write. Returns the number
+   * of bytes written or an error code.
+   *
+   * Multiple outstanding write requests are not supported.
+   */
+  int32_t Write([in] PP_Resource tcp_socket,
+                [in] str_t buffer,
+                [in] int32_t bytes_to_write,
+                [in] PP_CompletionCallback callback);
+
+  /**
+   * Cancels any IO that may be pending, and disconnects the socket. Any pending
+   * callbacks will still run, reporting PP_ERROR_ABORTED if pending IO was
+   * interrupted. It is NOT valid to call Connect() again after a call to this
+   * method. Note: If the socket is destroyed when it is still connected, then
+   * it will be implicitly disconnected, so you are not required to call this
+   * method.
+   */
+  void Close([in] PP_Resource tcp_socket);
+
+  /**
+   * Sets an option on |tcp_socket|.  Supported |name| and |value| parameters
+   * are as described for PP_TCPSocketOption_Dev.  |callback| will be
+   * invoked with PP_OK if setting the option succeeds, or an error code
+   * otherwise. The socket must be connected before SetOption is called.
+   */
+  int32_t SetOption([in] PP_Resource tcp_socket,
+                    [in] PP_TCPSocket_Option_Dev name,
+                    [in] PP_Var value,
+                    [in] PP_CompletionCallback callback);
+};
diff --git a/ppapi/c/dev/ppb_tcp_socket_dev.h b/ppapi/c/dev/ppb_tcp_socket_dev.h
new file mode 100644
index 0000000..d59bc31
--- /dev/null
+++ b/ppapi/c/dev/ppb_tcp_socket_dev.h
@@ -0,0 +1,136 @@
+/* Copyright 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* From dev/ppb_tcp_socket_dev.idl modified Wed Jun 12 11:16:37 2013. */
+
+#ifndef PPAPI_C_DEV_PPB_TCP_SOCKET_DEV_H_
+#define PPAPI_C_DEV_PPB_TCP_SOCKET_DEV_H_
+
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_macros.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/c/pp_var.h"
+
+#define PPB_TCPSOCKET_DEV_INTERFACE_0_1 "PPB_TCPSocket(Dev);0.1"
+#define PPB_TCPSOCKET_DEV_INTERFACE PPB_TCPSOCKET_DEV_INTERFACE_0_1
+
+/**
+ * @file
+ * This file defines the <code>PPB_TCPSocket_Dev</code> interface.
+ */
+
+
+/**
+ * @addtogroup Enums
+ * @{
+ */
+typedef enum {
+  /* Disables coalescing of small writes to make TCP segments, and instead
+   * deliver data immediately. Value type is PP_VARTYPE_BOOL. */
+  PP_TCPSOCKET_OPTION_NO_DELAY = 0,
+  /* Specifies the socket send buffer in bytes. Value's type should be
+   * PP_VARTYPE_INT32.
+   * Note: This is only treated as a hint for the browser to set the buffer
+   * size. Even if SetOption() reports that this option has been successfully
+   * set, the browser doesn't guarantee to conform to it. */
+  PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE = 1,
+  /* Specifies the socket receive buffer in bytes. Value's type should be
+   * PP_VARTYPE_INT32.
+   * Note: This is only treated as a hint for the browser to set the buffer
+   * size. Even if SetOption() reports that this option has been successfully
+   * set, the browser doesn't guarantee to conform to it. */
+  PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE = 2
+} PP_TCPSocket_Option_Dev;
+PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TCPSocket_Option_Dev, 4);
+/**
+ * @}
+ */
+
+/**
+ * @addtogroup Interfaces
+ * @{
+ */
+/**
+ * The <code>PPB_TCPSocket_Dev</code> interface provides TCP socket operations.
+ */
+struct PPB_TCPSocket_Dev_0_1 {
+  /**
+   * Allocates a TCP socket resource.
+   */
+  PP_Resource (*Create)(PP_Instance instance);
+  /**
+   * Determines if a given resource is TCP socket.
+   */
+  PP_Bool (*IsTCPSocket)(PP_Resource resource);
+  /**
+   * Connects to an address given by |addr|, which is a PPB_NetAddress_Dev
+   * resource.
+   */
+  int32_t (*Connect)(PP_Resource tcp_socket,
+                     PP_Resource addr,
+                     struct PP_CompletionCallback callback);
+  /**
+   * Gets the local address of the socket, if it has been connected.
+   * Returns a PPB_NetAddress_Dev resource on success; returns 0 on failure.
+   */
+  PP_Resource (*GetLocalAddress)(PP_Resource tcp_socket);
+  /**
+   * Gets the remote address of the socket, if it has been connected.
+   * Returns a PPB_NetAddress_Dev resource on success; returns 0 on failure.
+   */
+  PP_Resource (*GetRemoteAddress)(PP_Resource tcp_socket);
+  /**
+   * Reads data from the socket. The size of |buffer| must be at least as large
+   * as |bytes_to_read|. May perform a partial read. Returns the number of bytes
+   * read or an error code. If the return value is 0, then it indicates that
+   * end-of-file was reached.
+   *
+   * Multiple outstanding read requests are not supported.
+   */
+  int32_t (*Read)(PP_Resource tcp_socket,
+                  char* buffer,
+                  int32_t bytes_to_read,
+                  struct PP_CompletionCallback callback);
+  /**
+   * Writes data to the socket. May perform a partial write. Returns the number
+   * of bytes written or an error code.
+   *
+   * Multiple outstanding write requests are not supported.
+   */
+  int32_t (*Write)(PP_Resource tcp_socket,
+                   const char* buffer,
+                   int32_t bytes_to_write,
+                   struct PP_CompletionCallback callback);
+  /**
+   * Cancels any IO that may be pending, and disconnects the socket. Any pending
+   * callbacks will still run, reporting PP_ERROR_ABORTED if pending IO was
+   * interrupted. It is NOT valid to call Connect() again after a call to this
+   * method. Note: If the socket is destroyed when it is still connected, then
+   * it will be implicitly disconnected, so you are not required to call this
+   * method.
+   */
+  void (*Close)(PP_Resource tcp_socket);
+  /**
+   * Sets an option on |tcp_socket|.  Supported |name| and |value| parameters
+   * are as described for PP_TCPSocketOption_Dev.  |callback| will be
+   * invoked with PP_OK if setting the option succeeds, or an error code
+   * otherwise. The socket must be connected before SetOption is called.
+   */
+  int32_t (*SetOption)(PP_Resource tcp_socket,
+                       PP_TCPSocket_Option_Dev name,
+                       struct PP_Var value,
+                       struct PP_CompletionCallback callback);
+};
+
+typedef struct PPB_TCPSocket_Dev_0_1 PPB_TCPSocket_Dev;
+/**
+ * @}
+ */
+
+#endif  /* PPAPI_C_DEV_PPB_TCP_SOCKET_DEV_H_ */
+
diff --git a/ppapi/cpp/dev/tcp_socket_dev.cc b/ppapi/cpp/dev/tcp_socket_dev.cc
new file mode 100644
index 0000000..4ff9514
--- /dev/null
+++ b/ppapi/cpp/dev/tcp_socket_dev.cc
@@ -0,0 +1,117 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/cpp/dev/tcp_socket_dev.h"
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/instance_handle.h"
+#include "ppapi/cpp/module_impl.h"
+
+namespace pp {
+
+namespace {
+
+template <> const char* interface_name<PPB_TCPSocket_Dev_0_1>() {
+  return PPB_TCPSOCKET_DEV_INTERFACE_0_1;
+}
+
+}  // namespace
+
+TCPSocket_Dev::TCPSocket_Dev() {
+}
+
+TCPSocket_Dev::TCPSocket_Dev(const InstanceHandle& instance) {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    PassRefFromConstructor(get_interface<PPB_TCPSocket_Dev_0_1>()->Create(
+        instance.pp_instance()));
+  }
+}
+
+TCPSocket_Dev::TCPSocket_Dev(PassRef, PP_Resource resource)
+    : Resource(PASS_REF, resource) {
+}
+
+TCPSocket_Dev::TCPSocket_Dev(const TCPSocket_Dev& other) : Resource(other) {
+}
+
+TCPSocket_Dev::~TCPSocket_Dev() {
+}
+
+TCPSocket_Dev& TCPSocket_Dev::operator=(const TCPSocket_Dev& other) {
+  Resource::operator=(other);
+  return *this;
+}
+
+// static
+bool TCPSocket_Dev::IsAvailable() {
+  return has_interface<PPB_TCPSocket_Dev_0_1>();
+}
+
+int32_t TCPSocket_Dev::Connect(const NetAddress_Dev& addr,
+                               const CompletionCallback& callback) {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    return get_interface<PPB_TCPSocket_Dev_0_1>()->Connect(
+        pp_resource(), addr.pp_resource(), callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+NetAddress_Dev TCPSocket_Dev::GetLocalAddress() const {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    return NetAddress_Dev(
+        PASS_REF,
+        get_interface<PPB_TCPSocket_Dev_0_1>()->GetLocalAddress(pp_resource()));
+  }
+  return NetAddress_Dev();
+}
+
+NetAddress_Dev TCPSocket_Dev::GetRemoteAddress() const {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    return NetAddress_Dev(
+        PASS_REF,
+        get_interface<PPB_TCPSocket_Dev_0_1>()->GetRemoteAddress(
+            pp_resource()));
+  }
+  return NetAddress_Dev();
+}
+
+int32_t TCPSocket_Dev::Read(char* buffer,
+                            int32_t bytes_to_read,
+                            const CompletionCallback& callback) {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    return get_interface<PPB_TCPSocket_Dev_0_1>()->Read(
+        pp_resource(), buffer, bytes_to_read,
+        callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+int32_t TCPSocket_Dev::Write(const char* buffer,
+                             int32_t bytes_to_write,
+                             const CompletionCallback& callback) {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    return get_interface<PPB_TCPSocket_Dev_0_1>()->Write(
+        pp_resource(), buffer, bytes_to_write,
+        callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+void TCPSocket_Dev::Close() {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>())
+    get_interface<PPB_TCPSocket_Dev_0_1>()->Close(pp_resource());
+}
+
+int32_t TCPSocket_Dev::SetOption(PP_TCPSocket_Option_Dev name,
+                                 const Var& value,
+                                 const CompletionCallback& callback) {
+  if (has_interface<PPB_TCPSocket_Dev_0_1>()) {
+    return get_interface<PPB_TCPSocket_Dev_0_1>()->SetOption(
+        pp_resource(), name, value.pp_var(), callback.pp_completion_callback());
+  }
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+}  // namespace pp
diff --git a/ppapi/cpp/dev/tcp_socket_dev.h b/ppapi/cpp/dev/tcp_socket_dev.h
new file mode 100644
index 0000000..16d7dee
--- /dev/null
+++ b/ppapi/cpp/dev/tcp_socket_dev.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_CPP_DEV_TCP_SOCKET_DEV_H_
+#define PPAPI_CPP_DEV_TCP_SOCKET_DEV_H_
+
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
+#include "ppapi/cpp/dev/net_address_dev.h"
+#include "ppapi/cpp/pass_ref.h"
+#include "ppapi/cpp/resource.h"
+
+namespace pp {
+
+class CompletionCallback;
+class InstanceHandle;
+
+class TCPSocket_Dev: public Resource {
+ public:
+  TCPSocket_Dev();
+
+  explicit TCPSocket_Dev(const InstanceHandle& instance);
+
+  TCPSocket_Dev(PassRef, PP_Resource resource);
+
+  TCPSocket_Dev(const TCPSocket_Dev& other);
+
+  virtual ~TCPSocket_Dev();
+
+  TCPSocket_Dev& operator=(const TCPSocket_Dev& other);
+
+  // Returns true if the required interface is available.
+  static bool IsAvailable();
+
+  int32_t Connect(const NetAddress_Dev& addr,
+                  const CompletionCallback& callback);
+  NetAddress_Dev GetLocalAddress() const;
+  NetAddress_Dev GetRemoteAddress() const;
+  int32_t Read(char* buffer,
+               int32_t bytes_to_read,
+               const CompletionCallback& callback);
+  int32_t Write(const char* buffer,
+                int32_t bytes_to_write,
+                const CompletionCallback& callback);
+  void Close();
+  int32_t SetOption(PP_TCPSocket_Option_Dev name,
+                    const Var& value,
+                    const CompletionCallback& callback);
+};
+
+}  // namespace pp
+
+#endif  // PPAPI_CPP_DEV_TCP_SOCKET_DEV_H_
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index 5f45879..194925e 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -23,6 +23,7 @@
 #include "ppapi/c/dev/ppb_printing_dev.h"
 #include "ppapi/c/dev/ppb_resource_array_dev.h"
 #include "ppapi/c/dev/ppb_scrollbar_dev.h"
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
 #include "ppapi/c/dev/ppb_testing_dev.h"
 #include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/dev/ppb_trace_event_dev.h"
@@ -198,6 +199,7 @@
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Printing_Dev_0_7;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_ResourceArray_Dev_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Scrollbar_Dev_0_5;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Testing_Dev_0_7;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Testing_Dev_0_8;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Testing_Dev_0_9;
@@ -1717,6 +1719,55 @@
 
 /* Not generating wrapper methods for PPB_Scrollbar_Dev_0_5 */
 
+/* Begin wrapper methods for PPB_TCPSocket_Dev_0_1 */
+
+static PP_Resource Pnacl_M29_PPB_TCPSocket_Dev_Create(PP_Instance instance) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->Create(instance);
+}
+
+static PP_Bool Pnacl_M29_PPB_TCPSocket_Dev_IsTCPSocket(PP_Resource resource) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->IsTCPSocket(resource);
+}
+
+static int32_t Pnacl_M29_PPB_TCPSocket_Dev_Connect(PP_Resource tcp_socket, PP_Resource addr, struct PP_CompletionCallback* callback) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->Connect(tcp_socket, addr, *callback);
+}
+
+static PP_Resource Pnacl_M29_PPB_TCPSocket_Dev_GetLocalAddress(PP_Resource tcp_socket) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->GetLocalAddress(tcp_socket);
+}
+
+static PP_Resource Pnacl_M29_PPB_TCPSocket_Dev_GetRemoteAddress(PP_Resource tcp_socket) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->GetRemoteAddress(tcp_socket);
+}
+
+static int32_t Pnacl_M29_PPB_TCPSocket_Dev_Read(PP_Resource tcp_socket, char* buffer, int32_t bytes_to_read, struct PP_CompletionCallback* callback) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->Read(tcp_socket, buffer, bytes_to_read, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_TCPSocket_Dev_Write(PP_Resource tcp_socket, const char* buffer, int32_t bytes_to_write, struct PP_CompletionCallback* callback) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->Write(tcp_socket, buffer, bytes_to_write, *callback);
+}
+
+static void Pnacl_M29_PPB_TCPSocket_Dev_Close(PP_Resource tcp_socket) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  iface->Close(tcp_socket);
+}
+
+static int32_t Pnacl_M29_PPB_TCPSocket_Dev_SetOption(PP_Resource tcp_socket, PP_TCPSocket_Option_Dev name, struct PP_Var* value, struct PP_CompletionCallback* callback) {
+  const struct PPB_TCPSocket_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1.real_iface;
+  return iface->SetOption(tcp_socket, name, *value, *callback);
+}
+
+/* End wrapper methods for PPB_TCPSocket_Dev_0_1 */
+
 /* Not generating wrapper methods for PPB_Testing_Dev_0_7 */
 
 /* Not generating wrapper methods for PPB_Testing_Dev_0_8 */
@@ -4183,6 +4234,18 @@
 
 /* Not generating wrapper interface for PPB_Scrollbar_Dev_0_5 */
 
+struct PPB_TCPSocket_Dev_0_1 Pnacl_Wrappers_PPB_TCPSocket_Dev_0_1 = {
+    .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M29_PPB_TCPSocket_Dev_Create,
+    .IsTCPSocket = (PP_Bool (*)(PP_Resource resource))&Pnacl_M29_PPB_TCPSocket_Dev_IsTCPSocket,
+    .Connect = (int32_t (*)(PP_Resource tcp_socket, PP_Resource addr, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_TCPSocket_Dev_Connect,
+    .GetLocalAddress = (PP_Resource (*)(PP_Resource tcp_socket))&Pnacl_M29_PPB_TCPSocket_Dev_GetLocalAddress,
+    .GetRemoteAddress = (PP_Resource (*)(PP_Resource tcp_socket))&Pnacl_M29_PPB_TCPSocket_Dev_GetRemoteAddress,
+    .Read = (int32_t (*)(PP_Resource tcp_socket, char* buffer, int32_t bytes_to_read, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_TCPSocket_Dev_Read,
+    .Write = (int32_t (*)(PP_Resource tcp_socket, const char* buffer, int32_t bytes_to_write, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_TCPSocket_Dev_Write,
+    .Close = (void (*)(PP_Resource tcp_socket))&Pnacl_M29_PPB_TCPSocket_Dev_Close,
+    .SetOption = (int32_t (*)(PP_Resource tcp_socket, PP_TCPSocket_Option_Dev name, struct PP_Var value, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_TCPSocket_Dev_SetOption
+};
+
 /* Not generating wrapper interface for PPB_Testing_Dev_0_7 */
 
 /* Not generating wrapper interface for PPB_Testing_Dev_0_8 */
@@ -5160,6 +5223,12 @@
   .real_iface = NULL
 };
 
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1 = {
+  .iface_macro = PPB_TCPSOCKET_DEV_INTERFACE_0_1,
+  .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_TCPSocket_Dev_0_1,
+  .real_iface = NULL
+};
+
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Testing_Dev_0_7 = {
   .iface_macro = PPB_TESTING_DEV_INTERFACE_0_7,
   .wrapped_iface = NULL /* Still need slot for real_iface */,
@@ -5710,6 +5779,7 @@
   &Pnacl_WrapperInfo_PPB_Printing_Dev_0_7,
   &Pnacl_WrapperInfo_PPB_ResourceArray_Dev_0_1,
   &Pnacl_WrapperInfo_PPB_Scrollbar_Dev_0_5,
+  &Pnacl_WrapperInfo_PPB_TCPSocket_Dev_0_1,
   &Pnacl_WrapperInfo_PPB_Testing_Dev_0_7,
   &Pnacl_WrapperInfo_PPB_Testing_Dev_0_8,
   &Pnacl_WrapperInfo_PPB_Testing_Dev_0_9,
diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi
index 16bfe48..b71178c5 100644
--- a/ppapi/ppapi_proxy.gypi
+++ b/ppapi/ppapi_proxy.gypi
@@ -123,6 +123,8 @@
           'proxy/ppb_network_monitor_private_proxy.h',
           'proxy/ppb_tcp_server_socket_private_proxy.cc',
           'proxy/ppb_tcp_server_socket_private_proxy.h',
+          'proxy/ppb_tcp_socket_proxy.cc',
+          'proxy/ppb_tcp_socket_proxy.h',
           'proxy/ppb_tcp_socket_private_proxy.cc',
           'proxy/ppb_tcp_socket_private_proxy.h',
           'proxy/ppb_testing_proxy.cc',
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index 34cff29e..a834433 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -94,6 +94,8 @@
           'shared_impl/scoped_pp_resource.h',
           'shared_impl/scoped_pp_var.cc',
           'shared_impl/scoped_pp_var.h',
+          'shared_impl/tcp_socket_shared.cc',
+          'shared_impl/tcp_socket_shared.h',
           'shared_impl/thread_aware_callback.cc',
           'shared_impl/thread_aware_callback.h',
           'shared_impl/time_conversion.cc',
@@ -219,6 +221,8 @@
           'thunk/ppb_talk_private_thunk.cc',
           'thunk/ppb_tcp_server_socket_private_api.h',
           'thunk/ppb_tcp_server_socket_private_thunk.cc',
+          'thunk/ppb_tcp_socket_api.h',
+          'thunk/ppb_tcp_socket_dev_thunk.cc',
           'thunk/ppb_tcp_socket_private_api.h',
           'thunk/ppb_tcp_socket_private_thunk.cc',
           'thunk/ppb_text_input_thunk.cc',
diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi
index df92b53..4c6d666 100644
--- a/ppapi/ppapi_sources.gypi
+++ b/ppapi/ppapi_sources.gypi
@@ -73,6 +73,7 @@
       'c/dev/ppb_printing_dev.h',
       'c/dev/ppb_resource_array_dev.h',
       'c/dev/ppb_scrollbar_dev.h',
+      'c/dev/ppb_tcp_socket_dev.h',
       'c/dev/ppb_testing_dev.h',
       'c/dev/ppb_text_input_dev.h',
       'c/dev/ppb_truetype_font_dev.h',
@@ -240,6 +241,8 @@
       'cpp/dev/scrollbar_dev.h',
       'cpp/dev/selection_dev.cc',
       'cpp/dev/selection_dev.h',
+      'cpp/dev/tcp_socket_dev.cc',
+      'cpp/dev/tcp_socket_dev.h',
       'cpp/dev/text_input_dev.cc',
       'cpp/dev/text_input_dev.h',
       'cpp/dev/truetype_font_dev.cc',
@@ -441,6 +444,8 @@
       'tests/test_scrollbar.h',
       'tests/test_tcp_server_socket_private.cc',
       'tests/test_tcp_server_socket_private.h',
+      'tests/test_tcp_socket.cc',
+      'tests/test_tcp_socket.h',
       'tests/test_tcp_socket_private.cc',
       'tests/test_tcp_socket_private.h',
       'tests/test_truetype_font.cc',
diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc
index 864de88..0a62aa1c 100644
--- a/ppapi/proxy/interface_list.cc
+++ b/ppapi/proxy/interface_list.cc
@@ -22,6 +22,7 @@
 #include "ppapi/c/dev/ppb_opengles2ext_dev.h"
 #include "ppapi/c/dev/ppb_printing_dev.h"
 #include "ppapi/c/dev/ppb_resource_array_dev.h"
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
 #include "ppapi/c/dev/ppb_testing_dev.h"
 #include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/dev/ppb_trace_event_dev.h"
@@ -105,6 +106,7 @@
 #include "ppapi/proxy/ppb_network_monitor_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_server_socket_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h"
+#include "ppapi/proxy/ppb_tcp_socket_proxy.h"
 #include "ppapi/proxy/ppb_testing_proxy.h"
 #include "ppapi/proxy/ppb_var_deprecated_proxy.h"
 #include "ppapi/proxy/ppb_video_decoder_proxy.h"
diff --git a/ppapi/proxy/ppb_tcp_socket_private_proxy.h b/ppapi/proxy/ppb_tcp_socket_private_proxy.h
index ffceca7..6f0f0f4 100644
--- a/ppapi/proxy/ppb_tcp_socket_private_proxy.h
+++ b/ppapi/proxy/ppb_tcp_socket_private_proxy.h
@@ -22,7 +22,7 @@
 
 class PPB_TCPSocket_Private_Proxy : public InterfaceProxy {
  public:
-  PPB_TCPSocket_Private_Proxy(Dispatcher* dispatcher);
+  explicit PPB_TCPSocket_Private_Proxy(Dispatcher* dispatcher);
   virtual ~PPB_TCPSocket_Private_Proxy();
 
   static PP_Resource CreateProxyResource(PP_Instance instance);
diff --git a/ppapi/proxy/ppb_tcp_socket_proxy.cc b/ppapi/proxy/ppb_tcp_socket_proxy.cc
new file mode 100644
index 0000000..1b6bd8a
--- /dev/null
+++ b/ppapi/proxy/ppb_tcp_socket_proxy.cc
@@ -0,0 +1,303 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/proxy/ppb_tcp_socket_proxy.h"
+
+#include <map>
+
+#include "base/logging.h"
+#include "ppapi/proxy/plugin_dispatcher.h"
+#include "ppapi/proxy/plugin_globals.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/tcp_socket_shared.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_net_address_api.h"
+#include "ppapi/thunk/ppb_tcp_socket_api.h"
+#include "ppapi/thunk/thunk.h"
+
+namespace ppapi {
+namespace proxy {
+
+namespace {
+
+typedef thunk::EnterResourceNoLock<thunk::PPB_NetAddress_API>
+    EnterNetAddressNoLock;
+
+typedef std::map<uint32, TCPSocketShared*> IDToSocketMap;
+IDToSocketMap* g_id_to_socket = NULL;
+
+class TCPSocket : public thunk::PPB_TCPSocket_API,
+                  public Resource,
+                  public TCPSocketShared {
+ public:
+  TCPSocket(const HostResource& resource, uint32 socket_id);
+  virtual ~TCPSocket();
+
+  // Resource overrides.
+  virtual thunk::PPB_TCPSocket_API* AsPPB_TCPSocket_API() OVERRIDE;
+
+  // thunk::PPB_TCPSocket_API implementation.
+  virtual int32_t Connect(PP_Resource addr,
+                          scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual PP_Resource GetLocalAddress() OVERRIDE;
+  virtual PP_Resource GetRemoteAddress() OVERRIDE;
+  virtual int32_t Read(char* buffer,
+                       int32_t bytes_to_read,
+                       scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual int32_t Write(const char* buffer,
+                        int32_t bytes_to_write,
+                        scoped_refptr<TrackedCallback> callback) OVERRIDE;
+  virtual void Close() OVERRIDE;
+  virtual int32_t SetOption(PP_TCPSocket_Option_Dev name,
+                            const PP_Var& value,
+                            scoped_refptr<TrackedCallback> callback) OVERRIDE;
+
+  // TCPSocketShared implementation.
+  virtual void SendConnect(const std::string& host, uint16_t port) OVERRIDE;
+  virtual void SendConnectWithNetAddress(
+      const PP_NetAddress_Private& addr) OVERRIDE;
+  virtual void SendSSLHandshake(
+      const std::string& server_name,
+      uint16_t server_port,
+      const std::vector<std::vector<char> >& trusted_certs,
+      const std::vector<std::vector<char> >& untrusted_certs) OVERRIDE;
+  virtual void SendRead(int32_t bytes_to_read) OVERRIDE;
+  virtual void SendWrite(const std::string& buffer) OVERRIDE;
+  virtual void SendDisconnect() OVERRIDE;
+  virtual void SendSetBoolOption(PP_TCPSocketOption_Private name,
+                                 bool value) OVERRIDE;
+  virtual Resource* GetOwnerResource() OVERRIDE;
+
+ private:
+  void SendToBrowser(IPC::Message* msg);
+
+  DISALLOW_COPY_AND_ASSIGN(TCPSocket);
+};
+
+TCPSocket::TCPSocket(const HostResource& resource, uint32 socket_id)
+    : Resource(OBJECT_IS_PROXY, resource),
+      TCPSocketShared(OBJECT_IS_PROXY, socket_id) {
+  if (!g_id_to_socket)
+    g_id_to_socket = new IDToSocketMap();
+  DCHECK(g_id_to_socket->find(socket_id) == g_id_to_socket->end());
+  (*g_id_to_socket)[socket_id] = this;
+}
+
+TCPSocket::~TCPSocket() {
+  DisconnectImpl();
+}
+
+thunk::PPB_TCPSocket_API* TCPSocket::AsPPB_TCPSocket_API() {
+  return this;
+}
+
+int32_t TCPSocket::Connect(PP_Resource addr,
+                           scoped_refptr<TrackedCallback> callback) {
+  EnterNetAddressNoLock enter(addr, true);
+  if (enter.failed())
+    return PP_ERROR_BADARGUMENT;
+
+  return ConnectWithNetAddressImpl(&enter.object()->GetNetAddressPrivate(),
+                                   callback);
+}
+
+PP_Resource TCPSocket::GetLocalAddress() {
+  PP_NetAddress_Private addr_private;
+  if (!GetLocalAddressImpl(&addr_private))
+    return 0;
+
+  thunk::EnterResourceCreationNoLock enter(pp_instance());
+  if (enter.failed())
+    return 0;
+  return enter.functions()->CreateNetAddressFromNetAddressPrivate(
+      pp_instance(), addr_private);
+}
+
+PP_Resource TCPSocket::GetRemoteAddress() {
+  PP_NetAddress_Private addr_private;
+  if (!GetRemoteAddressImpl(&addr_private))
+    return 0;
+
+  thunk::EnterResourceCreationNoLock enter(pp_instance());
+  if (enter.failed())
+    return 0;
+  return enter.functions()->CreateNetAddressFromNetAddressPrivate(
+      pp_instance(), addr_private);
+}
+
+int32_t TCPSocket::Read(char* buffer,
+                        int32_t bytes_to_read,
+                        scoped_refptr<TrackedCallback> callback) {
+  return ReadImpl(buffer, bytes_to_read, callback);
+}
+
+int32_t TCPSocket::Write(const char* buffer,
+                         int32_t bytes_to_write,
+                         scoped_refptr<TrackedCallback> callback) {
+  return WriteImpl(buffer, bytes_to_write, callback);
+}
+
+void TCPSocket::Close() {
+  DisconnectImpl();
+}
+
+int32_t TCPSocket::SetOption(PP_TCPSocket_Option_Dev name,
+                             const PP_Var& value,
+                             scoped_refptr<TrackedCallback> callback) {
+  // TODO(yzshen): Add support for other options.
+  if (name == PP_TCPSOCKET_OPTION_NO_DELAY)
+    return SetOptionImpl(PP_TCPSOCKETOPTION_NO_DELAY, value, callback);
+
+  return PP_ERROR_NOTSUPPORTED;
+}
+
+void TCPSocket::SendConnect(const std::string& host, uint16_t port) {
+  NOTREACHED();
+}
+
+void TCPSocket::SendConnectWithNetAddress(const PP_NetAddress_Private& addr) {
+  SendToBrowser(new PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress(
+      API_ID_PPB_TCPSOCKET, socket_id_, addr));
+}
+
+void TCPSocket::SendSSLHandshake(
+    const std::string& server_name,
+    uint16_t server_port,
+    const std::vector<std::vector<char> >& trusted_certs,
+    const std::vector<std::vector<char> >& untrusted_certs) {
+  NOTREACHED();
+}
+
+void TCPSocket::SendRead(int32_t bytes_to_read) {
+  SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Read(socket_id_, bytes_to_read));
+}
+
+void TCPSocket::SendWrite(const std::string& buffer) {
+  SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Write(socket_id_, buffer));
+}
+
+void TCPSocket::SendDisconnect() {
+  // After removed from the mapping, this object won't receive any notifications
+  // from the proxy.
+  DCHECK(g_id_to_socket->find(socket_id_) != g_id_to_socket->end());
+  g_id_to_socket->erase(socket_id_);
+  SendToBrowser(new PpapiHostMsg_PPBTCPSocket_Disconnect(socket_id_));
+}
+
+void TCPSocket::SendSetBoolOption(PP_TCPSocketOption_Private name, bool value) {
+  SendToBrowser(
+      new PpapiHostMsg_PPBTCPSocket_SetBoolOption(socket_id_, name, value));
+}
+
+Resource* TCPSocket::GetOwnerResource() {
+  return this;
+}
+
+void TCPSocket::SendToBrowser(IPC::Message* msg) {
+  PluginGlobals::Get()->GetBrowserSender()->Send(msg);
+}
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+
+PPB_TCPSocket_Proxy::PPB_TCPSocket_Proxy(Dispatcher* dispatcher)
+    : InterfaceProxy(dispatcher) {
+}
+
+PPB_TCPSocket_Proxy::~PPB_TCPSocket_Proxy() {
+}
+
+// static
+PP_Resource PPB_TCPSocket_Proxy::CreateProxyResource(PP_Instance instance) {
+  PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
+  if (!dispatcher)
+    return 0;
+
+  uint32 socket_id = 0;
+  PluginGlobals::Get()->GetBrowserSender()->Send(
+      new PpapiHostMsg_PPBTCPSocket_Create(
+          API_ID_PPB_TCPSOCKET, dispatcher->plugin_dispatcher_id(),
+          &socket_id));
+  if (socket_id == 0)
+    return 0;
+  return (new TCPSocket(HostResource::MakeInstanceOnly(instance),
+                        socket_id))->GetReference();
+}
+
+bool PPB_TCPSocket_Proxy::OnMessageReceived(const IPC::Message& msg) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(PPB_TCPSocket_Proxy, msg)
+    IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ConnectACK,
+                        OnMsgConnectACK)
+    IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ReadACK, OnMsgReadACK)
+    IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_WriteACK, OnMsgWriteACK)
+    IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_SetBoolOptionACK,
+                        OnMsgSetBoolOptionACK)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void PPB_TCPSocket_Proxy::OnMsgConnectACK(
+    uint32 /* plugin_dispatcher_id */,
+    uint32 socket_id,
+    bool succeeded,
+    const PP_NetAddress_Private& local_addr,
+    const PP_NetAddress_Private& remote_addr) {
+  if (!g_id_to_socket) {
+    NOTREACHED();
+    return;
+  }
+  IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id);
+  if (iter == g_id_to_socket->end())
+    return;
+  iter->second->OnConnectCompleted(succeeded, local_addr, remote_addr);
+}
+
+void PPB_TCPSocket_Proxy::OnMsgReadACK(uint32 /* plugin_dispatcher_id */,
+                                       uint32 socket_id,
+                                       bool succeeded,
+                                       const std::string& data) {
+  if (!g_id_to_socket) {
+    NOTREACHED();
+    return;
+  }
+  IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id);
+  if (iter == g_id_to_socket->end())
+    return;
+  iter->second->OnReadCompleted(succeeded, data);
+}
+
+void PPB_TCPSocket_Proxy::OnMsgWriteACK(uint32 /* plugin_dispatcher_id */,
+                                        uint32 socket_id,
+                                        bool succeeded,
+                                        int32_t bytes_written) {
+  if (!g_id_to_socket) {
+    NOTREACHED();
+    return;
+  }
+  IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id);
+  if (iter == g_id_to_socket->end())
+    return;
+  iter->second->OnWriteCompleted(succeeded, bytes_written);
+}
+
+void PPB_TCPSocket_Proxy::OnMsgSetBoolOptionACK(
+    uint32 /* plugin_dispatcher_id */,
+    uint32 socket_id,
+    bool succeeded) {
+  if (!g_id_to_socket) {
+    NOTREACHED();
+    return;
+  }
+  IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id);
+  if (iter == g_id_to_socket->end())
+    return;
+  iter->second->OnSetOptionCompleted(succeeded);
+}
+
+}  // namespace proxy
+}  // namespace ppapi
diff --git a/ppapi/proxy/ppb_tcp_socket_proxy.h b/ppapi/proxy/ppb_tcp_socket_proxy.h
new file mode 100644
index 0000000..35314a3
--- /dev/null
+++ b/ppapi/proxy/ppb_tcp_socket_proxy.h
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_PROXY_PPB_TCP_SOCKET_PROXY_H_
+#define PPAPI_PROXY_PPB_TCP_SOCKET_PROXY_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/proxy/interface_proxy.h"
+#include "ppapi/proxy/ppapi_proxy_export.h"
+
+struct PP_NetAddress_Private;
+
+namespace ppapi {
+namespace proxy {
+
+class PPB_TCPSocket_Proxy : public InterfaceProxy {
+ public:
+  explicit PPB_TCPSocket_Proxy(Dispatcher* dispatcher);
+  virtual ~PPB_TCPSocket_Proxy();
+
+  static PP_Resource CreateProxyResource(PP_Instance instance);
+
+  // InterfaceProxy implementation.
+  virtual bool OnMessageReceived(const IPC::Message& msg);
+
+  static const ApiID kApiID = API_ID_PPB_TCPSOCKET;
+
+ private:
+  // Browser->plugin message handlers.
+  void OnMsgConnectACK(uint32 plugin_dispatcher_id,
+                       uint32 socket_id,
+                       bool succeeded,
+                       const PP_NetAddress_Private& local_addr,
+                       const PP_NetAddress_Private& remote_addr);
+  void OnMsgReadACK(uint32 plugin_dispatcher_id,
+                    uint32 socket_id,
+                    bool succeeded,
+                    const std::string& data);
+  void OnMsgWriteACK(uint32 plugin_dispatcher_id,
+                     uint32 socket_id,
+                     bool succeeded,
+                     int32_t bytes_written);
+  void OnMsgSetBoolOptionACK(uint32 plugin_dispatcher_id,
+                             uint32 socket_id,
+                             bool succeeded);
+
+  DISALLOW_COPY_AND_ASSIGN(PPB_TCPSocket_Proxy);
+};
+
+}  // namespace proxy
+}  // namespace ppapi
+
+#endif  // PPAPI_PROXY_PPB_TCP_SOCKET_PROXY_H_
diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc
index 3448ce78..a9300cce 100644
--- a/ppapi/proxy/resource_creation_proxy.cc
+++ b/ppapi/proxy/resource_creation_proxy.cc
@@ -33,6 +33,7 @@
 #include "ppapi/proxy/ppb_network_monitor_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_server_socket_private_proxy.h"
 #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h"
+#include "ppapi/proxy/ppb_tcp_socket_proxy.h"
 #include "ppapi/proxy/ppb_video_decoder_proxy.h"
 #include "ppapi/proxy/ppb_x509_certificate_private_proxy.h"
 #include "ppapi/proxy/printing_resource.h"
@@ -278,6 +279,13 @@
                                  *ipv6_addr))->GetReference();
 }
 
+PP_Resource ResourceCreationProxy::CreateNetAddressFromNetAddressPrivate(
+    PP_Instance instance,
+    const PP_NetAddress_Private& private_addr) {
+  return (new NetAddressResource(GetConnection(), instance,
+                                 private_addr))->GetReference();
+}
+
 PP_Resource ResourceCreationProxy::CreateNetworkMonitor(
     PP_Instance instance,
     PPB_NetworkMonitor_Callback callback,
@@ -295,6 +303,11 @@
   return PPB_TCPServerSocket_Private_Proxy::CreateProxyResource(instance);
 }
 
+PP_Resource ResourceCreationProxy::CreateTCPSocket(
+    PP_Instance instance) {
+  return PPB_TCPSocket_Proxy::CreateProxyResource(instance);
+}
+
 PP_Resource ResourceCreationProxy::CreateTCPSocketPrivate(
     PP_Instance instance) {
   return PPB_TCPSocket_Private_Proxy::CreateProxyResource(instance);
diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h
index 3dd514d..d00a8bd 100644
--- a/ppapi/proxy/resource_creation_proxy.h
+++ b/ppapi/proxy/resource_creation_proxy.h
@@ -128,6 +128,9 @@
   virtual PP_Resource CreateNetAddressFromIPv6Address(
       PP_Instance instance,
       const PP_NetAddress_IPv6_Dev* ipv6_addr) OVERRIDE;
+  virtual PP_Resource CreateNetAddressFromNetAddressPrivate(
+      PP_Instance instance,
+      const PP_NetAddress_Private& private_addr) OVERRIDE;
   virtual PP_Resource CreateNetworkMonitor(
       PP_Instance instance,
       PPB_NetworkMonitor_Callback callback,
@@ -135,6 +138,7 @@
   virtual PP_Resource CreatePrinting(PP_Instance) OVERRIDE;
   virtual PP_Resource CreateTCPServerSocketPrivate(
       PP_Instance instance) OVERRIDE;
+  virtual PP_Resource CreateTCPSocket(PP_Instance instance) OVERRIDE;
   virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE;
   virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instance) OVERRIDE;
   virtual PP_Resource CreateWebSocket(PP_Instance instance) OVERRIDE;
diff --git a/ppapi/shared_impl/api_id.h b/ppapi/shared_impl/api_id.h
index 16955aa9..65a150e 100644
--- a/ppapi/shared_impl/api_id.h
+++ b/ppapi/shared_impl/api_id.h
@@ -40,6 +40,7 @@
   API_ID_PPB_PDF,
   API_ID_PPB_SURFACE_3D,
   API_ID_PPB_TCPSERVERSOCKET_PRIVATE,
+  API_ID_PPB_TCPSOCKET,
   API_ID_PPB_TCPSOCKET_PRIVATE,
   API_ID_PPB_TALK,
   API_ID_PPB_TESTING,
diff --git a/ppapi/shared_impl/private/tcp_socket_private_impl.cc b/ppapi/shared_impl/private/tcp_socket_private_impl.cc
index 87cc600..832603c 100644
--- a/ppapi/shared_impl/private/tcp_socket_private_impl.cc
+++ b/ppapi/shared_impl/private/tcp_socket_private_impl.cc
@@ -4,40 +4,18 @@
 
 #include "ppapi/shared_impl/private/tcp_socket_private_impl.h"
 
-#include <string.h>
-
-#include <algorithm>
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/shared_impl/ppapi_globals.h"
-#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
-#include "ppapi/shared_impl/var_tracker.h"
-#include "ppapi/shared_impl/var.h"
-#include "ppapi/thunk/enter.h"
-#include "ppapi/thunk/ppb_x509_certificate_private_api.h"
-
 namespace ppapi {
 
-const int32_t TCPSocketPrivateImpl::kMaxReadSize = 1024 * 1024;
-const int32_t TCPSocketPrivateImpl::kMaxWriteSize = 1024 * 1024;
-
 TCPSocketPrivateImpl::TCPSocketPrivateImpl(PP_Instance instance,
                                            uint32 socket_id)
     : Resource(OBJECT_IS_IMPL, instance),
-      resource_type_(OBJECT_IS_IMPL) {
-  Init(socket_id);
+      TCPSocketShared(OBJECT_IS_IMPL, socket_id) {
 }
 
 TCPSocketPrivateImpl::TCPSocketPrivateImpl(const HostResource& resource,
                                            uint32 socket_id)
     : Resource(OBJECT_IS_PROXY, resource),
-      resource_type_(OBJECT_IS_PROXY) {
-  Init(socket_id);
+      TCPSocketShared(OBJECT_IS_PROXY, socket_id) {
 }
 
 TCPSocketPrivateImpl::~TCPSocketPrivateImpl() {
@@ -51,303 +29,67 @@
 int32_t TCPSocketPrivateImpl::Connect(const char* host,
                                       uint16_t port,
                                       scoped_refptr<TrackedCallback> callback) {
-  if (!host)
-    return PP_ERROR_BADARGUMENT;
-  if (connection_state_ != BEFORE_CONNECT)
-    return PP_ERROR_FAILED;
-  if (TrackedCallback::IsPending(connect_callback_))
-    return PP_ERROR_INPROGRESS;  // Can only have one pending request.
-
-  connect_callback_ = callback;
-  // Send the request, the browser will call us back via ConnectACK.
-  SendConnect(host, port);
-  return PP_OK_COMPLETIONPENDING;
+  return ConnectImpl(host, port, callback);
 }
 
 int32_t TCPSocketPrivateImpl::ConnectWithNetAddress(
     const PP_NetAddress_Private* addr,
     scoped_refptr<TrackedCallback> callback) {
-  if (!addr)
-    return PP_ERROR_BADARGUMENT;
-  if (connection_state_ != BEFORE_CONNECT)
-    return PP_ERROR_FAILED;
-  if (TrackedCallback::IsPending(connect_callback_))
-    return PP_ERROR_INPROGRESS;  // Can only have one pending request.
-
-  connect_callback_ = callback;
-  // Send the request, the browser will call us back via ConnectACK.
-  SendConnectWithNetAddress(*addr);
-  return PP_OK_COMPLETIONPENDING;
+  return ConnectWithNetAddressImpl(addr, callback);
 }
 
 PP_Bool TCPSocketPrivateImpl::GetLocalAddress(
     PP_NetAddress_Private* local_addr) {
-  if (!IsConnected() || !local_addr)
-    return PP_FALSE;
-
-  *local_addr = local_addr_;
-  return PP_TRUE;
+  return GetLocalAddressImpl(local_addr);
 }
 
 PP_Bool TCPSocketPrivateImpl::GetRemoteAddress(
     PP_NetAddress_Private* remote_addr) {
-  if (!IsConnected() || !remote_addr)
-    return PP_FALSE;
-
-  *remote_addr = remote_addr_;
-  return PP_TRUE;
+  return GetRemoteAddressImpl(remote_addr);
 }
 
 int32_t TCPSocketPrivateImpl::SSLHandshake(
     const char* server_name,
     uint16_t server_port,
     scoped_refptr<TrackedCallback> callback) {
-  if (!server_name)
-    return PP_ERROR_BADARGUMENT;
-
-  if (connection_state_ != CONNECTED)
-    return PP_ERROR_FAILED;
-  if (TrackedCallback::IsPending(ssl_handshake_callback_) ||
-      TrackedCallback::IsPending(read_callback_) ||
-      TrackedCallback::IsPending(write_callback_))
-    return PP_ERROR_INPROGRESS;
-
-  ssl_handshake_callback_ = callback;
-
-  // Send the request, the browser will call us back via SSLHandshakeACK.
-  SendSSLHandshake(server_name, server_port, trusted_certificates_,
-      untrusted_certificates_);
-  return PP_OK_COMPLETIONPENDING;
+  return SSLHandshakeImpl(server_name, server_port, callback);
 }
 
 PP_Resource TCPSocketPrivateImpl::GetServerCertificate() {
-  if (!server_certificate_.get())
-    return 0;
-  return server_certificate_->GetReference();
+  return GetServerCertificateImpl();
 }
 
 PP_Bool TCPSocketPrivateImpl::AddChainBuildingCertificate(
     PP_Resource certificate,
     PP_Bool trusted) {
-  // TODO(raymes): The plumbing for this functionality is implemented but the
-  // certificates aren't yet used for the connection, so just return false for
-  // now.
-  return PP_FALSE;
-
-  thunk::EnterResourceNoLock<thunk::PPB_X509Certificate_Private_API>
-  enter_cert(certificate, true);
-  if (enter_cert.failed())
-    return PP_FALSE;
-
-  PP_Var der_var = enter_cert.object()->GetField(
-      PP_X509CERTIFICATE_PRIVATE_RAW);
-  ArrayBufferVar* der_array_buffer = ArrayBufferVar::FromPPVar(der_var);
-  PP_Bool success = PP_FALSE;
-  if (der_array_buffer) {
-    const char* der_bytes = static_cast<const char*>(der_array_buffer->Map());
-    uint32_t der_length = der_array_buffer->ByteLength();
-    std::vector<char> der(der_bytes, der_bytes + der_length);
-    if (PP_ToBool(trusted))
-      trusted_certificates_.push_back(der);
-    else
-      untrusted_certificates_.push_back(der);
-    success = PP_TRUE;
-  }
-  PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var);
-  return success;
+  return AddChainBuildingCertificateImpl(certificate, trusted);
 }
 
 int32_t TCPSocketPrivateImpl::Read(char* buffer,
                                    int32_t bytes_to_read,
                                    scoped_refptr<TrackedCallback> callback) {
-  if (!buffer || bytes_to_read <= 0)
-    return PP_ERROR_BADARGUMENT;
-
-  if (!IsConnected())
-    return PP_ERROR_FAILED;
-  if (TrackedCallback::IsPending(read_callback_) ||
-      TrackedCallback::IsPending(ssl_handshake_callback_))
-    return PP_ERROR_INPROGRESS;
-  read_buffer_ = buffer;
-  bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize);
-  read_callback_ = callback;
-
-  // Send the request, the browser will call us back via ReadACK.
-  SendRead(bytes_to_read_);
-  return PP_OK_COMPLETIONPENDING;
+  return ReadImpl(buffer, bytes_to_read, callback);
 }
 
 int32_t TCPSocketPrivateImpl::Write(const char* buffer,
                                     int32_t bytes_to_write,
                                     scoped_refptr<TrackedCallback> callback) {
-  if (!buffer || bytes_to_write <= 0)
-    return PP_ERROR_BADARGUMENT;
-
-  if (!IsConnected())
-    return PP_ERROR_FAILED;
-  if (TrackedCallback::IsPending(write_callback_) ||
-      TrackedCallback::IsPending(ssl_handshake_callback_))
-    return PP_ERROR_INPROGRESS;
-
-  if (bytes_to_write > kMaxWriteSize)
-    bytes_to_write = kMaxWriteSize;
-
-  write_callback_ = callback;
-
-  // Send the request, the browser will call us back via WriteACK.
-  SendWrite(std::string(buffer, bytes_to_write));
-  return PP_OK_COMPLETIONPENDING;
+  return WriteImpl(buffer, bytes_to_write, callback);
 }
 
 void TCPSocketPrivateImpl::Disconnect() {
-  if (connection_state_ == DISCONNECTED)
-    return;
-
-  connection_state_ = DISCONNECTED;
-
-  SendDisconnect();
-  socket_id_ = 0;
-
-  PostAbortIfNecessary(&connect_callback_);
-  PostAbortIfNecessary(&ssl_handshake_callback_);
-  PostAbortIfNecessary(&read_callback_);
-  PostAbortIfNecessary(&write_callback_);
-  PostAbortIfNecessary(&set_option_callback_);
-  read_buffer_ = NULL;
-  bytes_to_read_ = -1;
-  server_certificate_ = NULL;
+  DisconnectImpl();
 }
 
 int32_t TCPSocketPrivateImpl::SetOption(
     PP_TCPSocketOption_Private name,
     const PP_Var& value,
     scoped_refptr<TrackedCallback> callback) {
-  if (!IsConnected())
-    return PP_ERROR_FAILED;
-  if (TrackedCallback::IsPending(set_option_callback_))
-    return PP_ERROR_INPROGRESS;
-
-  set_option_callback_ = callback;
-
-  switch (name) {
-    case PP_TCPSOCKETOPTION_NO_DELAY:
-      if (value.type != PP_VARTYPE_BOOL)
-        return PP_ERROR_BADARGUMENT;
-      SendSetBoolOption(name, PP_ToBool(value.value.as_bool));
-      return PP_OK_COMPLETIONPENDING;
-    default:
-      return PP_ERROR_BADARGUMENT;
-  }
+  return SetOptionImpl(name, value, callback);
 }
 
-void TCPSocketPrivateImpl::OnConnectCompleted(
-    bool succeeded,
-    const PP_NetAddress_Private& local_addr,
-    const PP_NetAddress_Private& remote_addr) {
-  if (connection_state_ != BEFORE_CONNECT ||
-      !TrackedCallback::IsPending(connect_callback_)) {
-    NOTREACHED();
-    return;
-  }
-
-  if (succeeded) {
-    local_addr_ = local_addr;
-    remote_addr_ = remote_addr;
-    connection_state_ = CONNECTED;
-  }
-  connect_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
-}
-
-void TCPSocketPrivateImpl::OnSSLHandshakeCompleted(
-    bool succeeded,
-    const PPB_X509Certificate_Fields& certificate_fields) {
-  if (connection_state_ != CONNECTED ||
-      !TrackedCallback::IsPending(ssl_handshake_callback_)) {
-    NOTREACHED();
-    return;
-  }
-
-  if (succeeded) {
-    connection_state_ = SSL_CONNECTED;
-    server_certificate_ = new PPB_X509Certificate_Private_Shared(
-        resource_type_,
-        pp_instance(),
-        certificate_fields);
-    ssl_handshake_callback_->Run(PP_OK);
-  } else {
-    // The resource might be released in the callback so we need to hold
-    // a reference so we can Disconnect() first.
-    AddRef();
-    ssl_handshake_callback_->Run(PP_ERROR_FAILED);
-    Disconnect();
-    Release();
-  }
-}
-
-void TCPSocketPrivateImpl::OnReadCompleted(bool succeeded,
-                                           const std::string& data) {
-  if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_) {
-    NOTREACHED();
-    return;
-  }
-
-  if (succeeded) {
-    CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
-    if (!data.empty())
-      memcpy(read_buffer_, data.c_str(), data.size());
-  }
-  read_buffer_ = NULL;
-  bytes_to_read_ = -1;
-
-  read_callback_->Run(
-      succeeded ? static_cast<int32_t>(data.size()) :
-                  static_cast<int32_t>(PP_ERROR_FAILED));
-}
-
-void TCPSocketPrivateImpl::OnWriteCompleted(bool succeeded,
-                                            int32_t bytes_written) {
-  if (!TrackedCallback::IsPending(write_callback_) ||
-      (succeeded && bytes_written < 0)) {
-    NOTREACHED();
-    return;
-  }
-
-  write_callback_->Run(
-      succeeded ? bytes_written : static_cast<int32_t>(PP_ERROR_FAILED));
-}
-
-void TCPSocketPrivateImpl::OnSetOptionCompleted(bool succeeded) {
-  if (!TrackedCallback::IsPending(set_option_callback_)) {
-    NOTREACHED();
-    return;
-  }
-
-  set_option_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
-}
-
-void TCPSocketPrivateImpl::Init(uint32 socket_id) {
-  DCHECK(socket_id != 0);
-  socket_id_ = socket_id;
-  connection_state_ = BEFORE_CONNECT;
-  read_buffer_ = NULL;
-  bytes_to_read_ = -1;
-
-  local_addr_.size = 0;
-  memset(local_addr_.data, 0,
-         arraysize(local_addr_.data) * sizeof(*local_addr_.data));
-  remote_addr_.size = 0;
-  memset(remote_addr_.data, 0,
-         arraysize(remote_addr_.data) * sizeof(*remote_addr_.data));
-}
-
-bool TCPSocketPrivateImpl::IsConnected() const {
-  return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED;
-}
-
-void TCPSocketPrivateImpl::PostAbortIfNecessary(
-    scoped_refptr<TrackedCallback>* callback) {
-  if (TrackedCallback::IsPending(*callback))
-    (*callback)->PostAbort();
+Resource* TCPSocketPrivateImpl::GetOwnerResource() {
+  return this;
 }
 
 }  // namespace ppapi
diff --git a/ppapi/shared_impl/private/tcp_socket_private_impl.h b/ppapi/shared_impl/private/tcp_socket_private_impl.h
index 95057e7..62fba8e 100644
--- a/ppapi/shared_impl/private/tcp_socket_private_impl.h
+++ b/ppapi/shared_impl/private/tcp_socket_private_impl.h
@@ -5,26 +5,22 @@
 #ifndef PPAPI_SHARED_IMPL_PRIVATE_TCP_SOCKET_PRIVATE_IMPL_H_
 #define PPAPI_SHARED_IMPL_PRIVATE_TCP_SOCKET_PRIVATE_IMPL_H_
 
-#include <string>
-#include <vector>
-
+#include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "ppapi/shared_impl/resource.h"
-#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/shared_impl/tcp_socket_shared.h"
 #include "ppapi/thunk/ppb_tcp_socket_private_api.h"
 
 namespace ppapi {
 
-class PPB_X509Certificate_Fields;
-class PPB_X509Certificate_Private_Shared;
-
 // This class provides the shared implementation of a
 // PPB_TCPSocket_Private.  The functions that actually send messages
 // to browser are implemented differently for the proxied and
 // non-proxied derived classes.
 class PPAPI_SHARED_EXPORT TCPSocketPrivateImpl
     : public thunk::PPB_TCPSocket_Private_API,
-      public Resource {
+      public Resource,
+      public TCPSocketShared {
  public:
   // C-tor used in Impl case.
   TCPSocketPrivateImpl(PP_Instance instance, uint32 socket_id);
@@ -33,13 +29,6 @@
 
   virtual ~TCPSocketPrivateImpl();
 
-  // The maximum number of bytes that each PpapiHostMsg_PPBTCPSocket_Read
-  // message is allowed to request.
-  static const int32_t kMaxReadSize;
-  // The maximum number of bytes that each PpapiHostMsg_PPBTCPSocket_Write
-  // message is allowed to carry.
-  static const int32_t kMaxWriteSize;
-
   // Resource overrides.
   virtual PPB_TCPSocket_Private_API* AsPPB_TCPSocket_Private_API() OVERRIDE;
 
@@ -70,72 +59,10 @@
                             const PP_Var& value,
                             scoped_refptr<TrackedCallback> callback) OVERRIDE;
 
-  // Notifications on operations completion.
-  void OnConnectCompleted(bool succeeded,
-                          const PP_NetAddress_Private& local_addr,
-                          const PP_NetAddress_Private& remote_addr);
-  void OnSSLHandshakeCompleted(
-      bool succeeded,
-      const PPB_X509Certificate_Fields& certificate_fields);
-  void OnReadCompleted(bool succeeded, const std::string& data);
-  void OnWriteCompleted(bool succeeded, int32_t bytes_written);
-  void OnSetOptionCompleted(bool succeeded);
+  // TCPSocketShared implementation.
+  virtual Resource* GetOwnerResource() OVERRIDE;
 
-  // Send functions that need to be implemented differently for the
-  // proxied and non-proxied derived classes.
-  virtual void SendConnect(const std::string& host, uint16_t port) = 0;
-  virtual void SendConnectWithNetAddress(const PP_NetAddress_Private& addr) = 0;
-  virtual void SendSSLHandshake(
-      const std::string& server_name,
-      uint16_t server_port,
-      const std::vector<std::vector<char> >& trusted_certs,
-      const std::vector<std::vector<char> >& untrusted_certs) = 0;
-  virtual void SendRead(int32_t bytes_to_read) = 0;
-  virtual void SendWrite(const std::string& buffer) = 0;
-  virtual void SendDisconnect() = 0;
-  virtual void SendSetBoolOption(PP_TCPSocketOption_Private name,
-                                 bool value) = 0;
-
- protected:
-  enum ConnectionState {
-    // Before a connection is successfully established (including a connect
-    // request is pending or a previous connect request failed).
-    BEFORE_CONNECT,
-    // A connection has been successfully established (including a request of
-    // initiating SSL is pending).
-    CONNECTED,
-    // An SSL connection has been successfully established.
-    SSL_CONNECTED,
-    // The connection has been ended.
-    DISCONNECTED
-  };
-
-  void Init(uint32 socket_id);
-  bool IsConnected() const;
-  void PostAbortIfNecessary(scoped_refptr<TrackedCallback>* callback);
-
-  ResourceObjectType resource_type_;
-
-  uint32 socket_id_;
-  ConnectionState connection_state_;
-
-  scoped_refptr<TrackedCallback> connect_callback_;
-  scoped_refptr<TrackedCallback> ssl_handshake_callback_;
-  scoped_refptr<TrackedCallback> read_callback_;
-  scoped_refptr<TrackedCallback> write_callback_;
-  scoped_refptr<TrackedCallback> set_option_callback_;
-
-  char* read_buffer_;
-  int32_t bytes_to_read_;
-
-  PP_NetAddress_Private local_addr_;
-  PP_NetAddress_Private remote_addr_;
-
-  scoped_refptr<PPB_X509Certificate_Private_Shared> server_certificate_;
-
-  std::vector<std::vector<char> > trusted_certificates_;
-  std::vector<std::vector<char> > untrusted_certificates_;
-
+ private:
   DISALLOW_COPY_AND_ASSIGN(TCPSocketPrivateImpl);
 };
 
diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h
index f327388a..05b3d514 100644
--- a/ppapi/shared_impl/resource.h
+++ b/ppapi/shared_impl/resource.h
@@ -63,6 +63,7 @@
   F(PPB_TrueTypeFont_API) \
   F(PPB_TrueTypeFont_Singleton_API) \
   F(PPB_TCPServerSocket_Private_API) \
+  F(PPB_TCPSocket_API) \
   F(PPB_TCPSocket_Private_API) \
   F(PPB_UDPSocket_Private_API) \
   F(PPB_URLLoader_API) \
diff --git a/ppapi/shared_impl/tcp_socket_shared.cc b/ppapi/shared_impl/tcp_socket_shared.cc
new file mode 100644
index 0000000..8799c49
--- /dev/null
+++ b/ppapi/shared_impl/tcp_socket_shared.cc
@@ -0,0 +1,339 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/shared_impl/tcp_socket_shared.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_x509_certificate_private_api.h"
+
+namespace ppapi {
+
+const int32_t TCPSocketShared::kMaxReadSize = 1024 * 1024;
+const int32_t TCPSocketShared::kMaxWriteSize = 1024 * 1024;
+
+TCPSocketShared::TCPSocketShared(ResourceObjectType resource_type,
+                                 uint32 socket_id)
+    : resource_type_(resource_type) {
+  Init(socket_id);
+}
+
+TCPSocketShared::~TCPSocketShared() {
+}
+
+void TCPSocketShared::OnConnectCompleted(
+    bool succeeded,
+    const PP_NetAddress_Private& local_addr,
+    const PP_NetAddress_Private& remote_addr) {
+  if (connection_state_ != BEFORE_CONNECT ||
+      !TrackedCallback::IsPending(connect_callback_)) {
+    NOTREACHED();
+    return;
+  }
+
+  if (succeeded) {
+    local_addr_ = local_addr;
+    remote_addr_ = remote_addr;
+    connection_state_ = CONNECTED;
+  }
+  connect_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
+}
+
+void TCPSocketShared::OnSSLHandshakeCompleted(
+    bool succeeded,
+    const PPB_X509Certificate_Fields& certificate_fields) {
+  if (connection_state_ != CONNECTED ||
+      !TrackedCallback::IsPending(ssl_handshake_callback_)) {
+    NOTREACHED();
+    return;
+  }
+
+  if (succeeded) {
+    connection_state_ = SSL_CONNECTED;
+    server_certificate_ = new PPB_X509Certificate_Private_Shared(
+        resource_type_,
+        GetOwnerResource()->pp_instance(),
+        certificate_fields);
+    ssl_handshake_callback_->Run(PP_OK);
+  } else {
+    // The resource might be released in the callback so we need to hold
+    // a reference so we can Disconnect() first.
+    GetOwnerResource()->AddRef();
+    ssl_handshake_callback_->Run(PP_ERROR_FAILED);
+    DisconnectImpl();
+    GetOwnerResource()->Release();
+  }
+}
+
+void TCPSocketShared::OnReadCompleted(bool succeeded,
+                                      const std::string& data) {
+  if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_) {
+    NOTREACHED();
+    return;
+  }
+
+  if (succeeded) {
+    CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
+    if (!data.empty())
+      memcpy(read_buffer_, data.c_str(), data.size());
+  }
+  read_buffer_ = NULL;
+  bytes_to_read_ = -1;
+
+  read_callback_->Run(
+      succeeded ? static_cast<int32_t>(data.size()) :
+                  static_cast<int32_t>(PP_ERROR_FAILED));
+}
+
+void TCPSocketShared::OnWriteCompleted(bool succeeded,
+                                       int32_t bytes_written) {
+  if (!TrackedCallback::IsPending(write_callback_) ||
+      (succeeded && bytes_written < 0)) {
+    NOTREACHED();
+    return;
+  }
+
+  write_callback_->Run(
+      succeeded ? bytes_written : static_cast<int32_t>(PP_ERROR_FAILED));
+}
+
+void TCPSocketShared::OnSetOptionCompleted(bool succeeded) {
+  if (!TrackedCallback::IsPending(set_option_callback_)) {
+    NOTREACHED();
+    return;
+  }
+
+  set_option_callback_->Run(succeeded ? PP_OK : PP_ERROR_FAILED);
+}
+
+int32_t TCPSocketShared::ConnectImpl(const char* host,
+                                     uint16_t port,
+                                     scoped_refptr<TrackedCallback> callback) {
+  if (!host)
+    return PP_ERROR_BADARGUMENT;
+  if (connection_state_ != BEFORE_CONNECT)
+    return PP_ERROR_FAILED;
+  if (TrackedCallback::IsPending(connect_callback_))
+    return PP_ERROR_INPROGRESS;  // Can only have one pending request.
+
+  connect_callback_ = callback;
+  // Send the request, the browser will call us back via ConnectACK.
+  SendConnect(host, port);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t TCPSocketShared::ConnectWithNetAddressImpl(
+    const PP_NetAddress_Private* addr,
+    scoped_refptr<TrackedCallback> callback) {
+  if (!addr)
+    return PP_ERROR_BADARGUMENT;
+  if (connection_state_ != BEFORE_CONNECT)
+    return PP_ERROR_FAILED;
+  if (TrackedCallback::IsPending(connect_callback_))
+    return PP_ERROR_INPROGRESS;  // Can only have one pending request.
+
+  connect_callback_ = callback;
+  // Send the request, the browser will call us back via ConnectACK.
+  SendConnectWithNetAddress(*addr);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+PP_Bool TCPSocketShared::GetLocalAddressImpl(
+    PP_NetAddress_Private* local_addr) {
+  if (!IsConnected() || !local_addr)
+    return PP_FALSE;
+
+  *local_addr = local_addr_;
+  return PP_TRUE;
+}
+
+PP_Bool TCPSocketShared::GetRemoteAddressImpl(
+    PP_NetAddress_Private* remote_addr) {
+  if (!IsConnected() || !remote_addr)
+    return PP_FALSE;
+
+  *remote_addr = remote_addr_;
+  return PP_TRUE;
+}
+
+int32_t TCPSocketShared::SSLHandshakeImpl(
+    const char* server_name,
+    uint16_t server_port,
+    scoped_refptr<TrackedCallback> callback) {
+  if (!server_name)
+    return PP_ERROR_BADARGUMENT;
+
+  if (connection_state_ != CONNECTED)
+    return PP_ERROR_FAILED;
+  if (TrackedCallback::IsPending(ssl_handshake_callback_) ||
+      TrackedCallback::IsPending(read_callback_) ||
+      TrackedCallback::IsPending(write_callback_))
+    return PP_ERROR_INPROGRESS;
+
+  ssl_handshake_callback_ = callback;
+
+  // Send the request, the browser will call us back via SSLHandshakeACK.
+  SendSSLHandshake(server_name, server_port, trusted_certificates_,
+      untrusted_certificates_);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+PP_Resource TCPSocketShared::GetServerCertificateImpl() {
+  if (!server_certificate_.get())
+    return 0;
+  return server_certificate_->GetReference();
+}
+
+PP_Bool TCPSocketShared::AddChainBuildingCertificateImpl(
+    PP_Resource certificate,
+    PP_Bool trusted) {
+  // TODO(raymes): The plumbing for this functionality is implemented but the
+  // certificates aren't yet used for the connection, so just return false for
+  // now.
+  return PP_FALSE;
+
+  thunk::EnterResourceNoLock<thunk::PPB_X509Certificate_Private_API>
+  enter_cert(certificate, true);
+  if (enter_cert.failed())
+    return PP_FALSE;
+
+  PP_Var der_var = enter_cert.object()->GetField(
+      PP_X509CERTIFICATE_PRIVATE_RAW);
+  ArrayBufferVar* der_array_buffer = ArrayBufferVar::FromPPVar(der_var);
+  PP_Bool success = PP_FALSE;
+  if (der_array_buffer) {
+    const char* der_bytes = static_cast<const char*>(der_array_buffer->Map());
+    uint32_t der_length = der_array_buffer->ByteLength();
+    std::vector<char> der(der_bytes, der_bytes + der_length);
+    if (PP_ToBool(trusted))
+      trusted_certificates_.push_back(der);
+    else
+      untrusted_certificates_.push_back(der);
+    success = PP_TRUE;
+  }
+  PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(der_var);
+  return success;
+}
+
+int32_t TCPSocketShared::ReadImpl(char* buffer,
+                                  int32_t bytes_to_read,
+                                  scoped_refptr<TrackedCallback> callback) {
+  if (!buffer || bytes_to_read <= 0)
+    return PP_ERROR_BADARGUMENT;
+
+  if (!IsConnected())
+    return PP_ERROR_FAILED;
+  if (TrackedCallback::IsPending(read_callback_) ||
+      TrackedCallback::IsPending(ssl_handshake_callback_))
+    return PP_ERROR_INPROGRESS;
+  read_buffer_ = buffer;
+  bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize);
+  read_callback_ = callback;
+
+  // Send the request, the browser will call us back via ReadACK.
+  SendRead(bytes_to_read_);
+  return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t TCPSocketShared::WriteImpl(const char* buffer,
+                                   int32_t bytes_to_write,
+                                   scoped_refptr<TrackedCallback> callback) {
+  if (!buffer || bytes_to_write <= 0)
+    return PP_ERROR_BADARGUMENT;
+
+  if (!IsConnected())
+    return PP_ERROR_FAILED;
+  if (TrackedCallback::IsPending(write_callback_) ||
+      TrackedCallback::IsPending(ssl_handshake_callback_))
+    return PP_ERROR_INPROGRESS;
+
+  if (bytes_to_write > kMaxWriteSize)
+    bytes_to_write = kMaxWriteSize;
+
+  write_callback_ = callback;
+
+  // Send the request, the browser will call us back via WriteACK.
+  SendWrite(std::string(buffer, bytes_to_write));
+  return PP_OK_COMPLETIONPENDING;
+}
+
+void TCPSocketShared::DisconnectImpl() {
+  if (connection_state_ == DISCONNECTED)
+    return;
+
+  connection_state_ = DISCONNECTED;
+
+  SendDisconnect();
+  socket_id_ = 0;
+
+  PostAbortIfNecessary(&connect_callback_);
+  PostAbortIfNecessary(&ssl_handshake_callback_);
+  PostAbortIfNecessary(&read_callback_);
+  PostAbortIfNecessary(&write_callback_);
+  PostAbortIfNecessary(&set_option_callback_);
+  read_buffer_ = NULL;
+  bytes_to_read_ = -1;
+  server_certificate_ = NULL;
+}
+
+int32_t TCPSocketShared::SetOptionImpl(
+    PP_TCPSocketOption_Private name,
+    const PP_Var& value,
+    scoped_refptr<TrackedCallback> callback) {
+  if (!IsConnected())
+    return PP_ERROR_FAILED;
+  if (TrackedCallback::IsPending(set_option_callback_))
+    return PP_ERROR_INPROGRESS;
+
+  set_option_callback_ = callback;
+
+  switch (name) {
+    case PP_TCPSOCKETOPTION_NO_DELAY:
+      if (value.type != PP_VARTYPE_BOOL)
+        return PP_ERROR_BADARGUMENT;
+      SendSetBoolOption(name, PP_ToBool(value.value.as_bool));
+      return PP_OK_COMPLETIONPENDING;
+    default:
+      return PP_ERROR_BADARGUMENT;
+  }
+}
+
+void TCPSocketShared::Init(uint32 socket_id) {
+  DCHECK(socket_id != 0);
+  socket_id_ = socket_id;
+  connection_state_ = BEFORE_CONNECT;
+  read_buffer_ = NULL;
+  bytes_to_read_ = -1;
+
+  local_addr_.size = 0;
+  memset(local_addr_.data, 0,
+         arraysize(local_addr_.data) * sizeof(*local_addr_.data));
+  remote_addr_.size = 0;
+  memset(remote_addr_.data, 0,
+         arraysize(remote_addr_.data) * sizeof(*remote_addr_.data));
+}
+
+bool TCPSocketShared::IsConnected() const {
+  return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED;
+}
+
+void TCPSocketShared::PostAbortIfNecessary(
+    scoped_refptr<TrackedCallback>* callback) {
+  if (TrackedCallback::IsPending(*callback))
+    (*callback)->PostAbort();
+}
+
+}  // namespace ppapi
diff --git a/ppapi/shared_impl/tcp_socket_shared.h b/ppapi/shared_impl/tcp_socket_shared.h
new file mode 100644
index 0000000..bd5e56b
--- /dev/null
+++ b/ppapi/shared_impl/tcp_socket_shared.h
@@ -0,0 +1,133 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_SHARED_IMPL_TCP_SOCKET_SHARED_H_
+#define PPAPI_SHARED_IMPL_TCP_SOCKET_SHARED_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "ppapi/c/private/ppb_tcp_socket_private.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+
+namespace ppapi {
+
+class PPB_X509Certificate_Fields;
+class PPB_X509Certificate_Private_Shared;
+
+// This class provides the shared implementation for both PPB_TCPSocket and
+// PPB_TCPSocket_Private.
+class PPAPI_SHARED_EXPORT TCPSocketShared {
+ public:
+  // The maximum number of bytes that each PpapiHostMsg_PPBTCPSocket_Read
+  // message is allowed to request.
+  static const int32_t kMaxReadSize;
+  // The maximum number of bytes that each PpapiHostMsg_PPBTCPSocket_Write
+  // message is allowed to carry.
+  static const int32_t kMaxWriteSize;
+
+  // Notifications on operations completion.
+  void OnConnectCompleted(bool succeeded,
+                          const PP_NetAddress_Private& local_addr,
+                          const PP_NetAddress_Private& remote_addr);
+  void OnSSLHandshakeCompleted(
+      bool succeeded,
+      const PPB_X509Certificate_Fields& certificate_fields);
+  void OnReadCompleted(bool succeeded, const std::string& data);
+  void OnWriteCompleted(bool succeeded, int32_t bytes_written);
+  void OnSetOptionCompleted(bool succeeded);
+
+  // Send functions that need to be implemented differently for the
+  // proxied and non-proxied derived classes.
+  virtual void SendConnect(const std::string& host, uint16_t port) = 0;
+  virtual void SendConnectWithNetAddress(const PP_NetAddress_Private& addr) = 0;
+  virtual void SendSSLHandshake(
+      const std::string& server_name,
+      uint16_t server_port,
+      const std::vector<std::vector<char> >& trusted_certs,
+      const std::vector<std::vector<char> >& untrusted_certs) = 0;
+  virtual void SendRead(int32_t bytes_to_read) = 0;
+  virtual void SendWrite(const std::string& buffer) = 0;
+  virtual void SendDisconnect() = 0;
+  virtual void SendSetBoolOption(PP_TCPSocketOption_Private name,
+                                 bool value) = 0;
+
+  virtual Resource* GetOwnerResource() = 0;
+
+ protected:
+  enum ConnectionState {
+    // Before a connection is successfully established (including a connect
+    // request is pending or a previous connect request failed).
+    BEFORE_CONNECT,
+    // A connection has been successfully established (including a request of
+    // initiating SSL is pending).
+    CONNECTED,
+    // An SSL connection has been successfully established.
+    SSL_CONNECTED,
+    // The connection has been ended.
+    DISCONNECTED
+  };
+
+  TCPSocketShared(ResourceObjectType resource_type, uint32 socket_id);
+  virtual ~TCPSocketShared();
+
+  int32_t ConnectImpl(const char* host,
+                      uint16_t port,
+                      scoped_refptr<TrackedCallback> callback);
+  int32_t ConnectWithNetAddressImpl(const PP_NetAddress_Private* addr,
+                                    scoped_refptr<TrackedCallback> callback);
+  PP_Bool GetLocalAddressImpl(PP_NetAddress_Private* local_addr);
+  PP_Bool GetRemoteAddressImpl(PP_NetAddress_Private* remote_addr);
+  int32_t SSLHandshakeImpl(const char* server_name,
+                           uint16_t server_port,
+                           scoped_refptr<TrackedCallback> callback);
+  PP_Resource GetServerCertificateImpl();
+  PP_Bool AddChainBuildingCertificateImpl(PP_Resource certificate,
+                                          PP_Bool trusted);
+  int32_t ReadImpl(char* buffer,
+                   int32_t bytes_to_read,
+                   scoped_refptr<TrackedCallback> callback);
+  int32_t WriteImpl(const char* buffer,
+                    int32_t bytes_to_write,
+                    scoped_refptr<TrackedCallback> callback);
+  void DisconnectImpl();
+  int32_t SetOptionImpl(PP_TCPSocketOption_Private name,
+                        const PP_Var& value,
+                        scoped_refptr<TrackedCallback> callback);
+
+  void Init(uint32 socket_id);
+  bool IsConnected() const;
+  void PostAbortIfNecessary(scoped_refptr<TrackedCallback>* callback);
+
+  ResourceObjectType resource_type_;
+
+  uint32 socket_id_;
+  ConnectionState connection_state_;
+
+  scoped_refptr<TrackedCallback> connect_callback_;
+  scoped_refptr<TrackedCallback> ssl_handshake_callback_;
+  scoped_refptr<TrackedCallback> read_callback_;
+  scoped_refptr<TrackedCallback> write_callback_;
+  scoped_refptr<TrackedCallback> set_option_callback_;
+
+  char* read_buffer_;
+  int32_t bytes_to_read_;
+
+  PP_NetAddress_Private local_addr_;
+  PP_NetAddress_Private remote_addr_;
+
+  scoped_refptr<PPB_X509Certificate_Private_Shared> server_certificate_;
+
+  std::vector<std::vector<char> > trusted_certificates_;
+  std::vector<std::vector<char> > untrusted_certificates_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TCPSocketShared);
+};
+
+}  // namespace ppapi
+
+#endif  // PPAPI_SHARED_IMPL_TCP_SOCKET_SHARED_H_
diff --git a/ppapi/tests/all_c_includes.h b/ppapi/tests/all_c_includes.h
index d550c21..4a8ae13e 100644
--- a/ppapi/tests/all_c_includes.h
+++ b/ppapi/tests/all_c_includes.h
@@ -26,6 +26,7 @@
 #include "ppapi/c/dev/ppb_printing_dev.h"
 #include "ppapi/c/dev/ppb_resource_array_dev.h"
 #include "ppapi/c/dev/ppb_scrollbar_dev.h"
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
 #include "ppapi/c/dev/ppb_testing_dev.h"
 #include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/dev/ppb_trace_event_dev.h"
diff --git a/ppapi/tests/all_cpp_includes.h b/ppapi/tests/all_cpp_includes.h
index 45fddf22..37a4100 100644
--- a/ppapi/tests/all_cpp_includes.h
+++ b/ppapi/tests/all_cpp_includes.h
@@ -26,6 +26,7 @@
 #include "ppapi/cpp/dev/scriptable_object_deprecated.h"
 #include "ppapi/cpp/dev/scrollbar_dev.h"
 #include "ppapi/cpp/dev/selection_dev.h"
+#include "ppapi/cpp/dev/tcp_socket_dev.h"
 #include "ppapi/cpp/dev/text_input_dev.h"
 #include "ppapi/cpp/dev/url_util_dev.h"
 #include "ppapi/cpp/dev/var_array_dev.h"
diff --git a/ppapi/tests/test_tcp_socket.cc b/ppapi/tests/test_tcp_socket.cc
new file mode 100644
index 0000000..7a14fe7
--- /dev/null
+++ b/ppapi/tests/test_tcp_socket.cc
@@ -0,0 +1,160 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/tests/test_tcp_socket.h"
+
+#include "ppapi/cpp/dev/tcp_socket_dev.h"
+#include "ppapi/tests/test_utils.h"
+#include "ppapi/tests/testing_instance.h"
+
+namespace {
+
+// Validates the first line of an HTTP response.
+bool ValidateHttpResponse(const std::string& s) {
+  // Just check that it begins with "HTTP/" and ends with a "\r\n".
+  return s.size() >= 5 &&
+         s.substr(0, 5) == "HTTP/" &&
+         s.substr(s.size() - 2) == "\r\n";
+}
+
+}  // namespace
+
+REGISTER_TEST_CASE(TCPSocket);
+
+TestTCPSocket::TestTCPSocket(TestingInstance* instance) : TestCase(instance) {
+}
+
+bool TestTCPSocket::Init() {
+  if (!pp::TCPSocket_Dev::IsAvailable())
+    return false;
+
+  // We need something to connect to, so we connect to the HTTP server whence we
+  // came. Grab the host and port.
+  if (!EnsureRunningOverHTTP())
+    return false;
+
+  std::string host;
+  uint16_t port = 0;
+  if (!GetLocalHostPort(instance_->pp_instance(), &host, &port))
+    return false;
+
+  if (!ResolveHost(instance_->pp_instance(), host, port, &addr_))
+    return false;
+
+  return true;
+}
+
+void TestTCPSocket::RunTests(const std::string& filter) {
+  RUN_CALLBACK_TEST(TestTCPSocket, Connect, filter);
+  RUN_CALLBACK_TEST(TestTCPSocket, ReadWrite, filter);
+  RUN_CALLBACK_TEST(TestTCPSocket, SetOption, filter);
+}
+
+std::string TestTCPSocket::TestConnect() {
+  pp::TCPSocket_Dev socket(instance_);
+  TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+
+  cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+  CHECK_CALLBACK_BEHAVIOR(cb);
+  ASSERT_EQ(PP_OK, cb.result());
+
+  pp::NetAddress_Dev local_addr, remote_addr;
+  local_addr = socket.GetLocalAddress();
+  remote_addr = socket.GetRemoteAddress();
+
+  ASSERT_NE(0, local_addr.pp_resource());
+  ASSERT_NE(0, remote_addr.pp_resource());
+  ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
+
+  socket.Close();
+
+  PASS();
+}
+
+std::string TestTCPSocket::TestReadWrite() {
+  pp::TCPSocket_Dev socket(instance_);
+  TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+
+  cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+  CHECK_CALLBACK_BEHAVIOR(cb);
+  ASSERT_EQ(PP_OK, cb.result());
+
+  ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n"));
+
+  // Read up to the first \n and check that it looks like valid HTTP response.
+  std::string s;
+  ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s));
+  ASSERT_TRUE(ValidateHttpResponse(s));
+
+  PASS();
+}
+
+std::string TestTCPSocket::TestSetOption() {
+  pp::TCPSocket_Dev socket(instance_);
+  TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+
+  cb.WaitForResult(
+      socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, true, cb.GetCallback()));
+  CHECK_CALLBACK_BEHAVIOR(cb);
+  ASSERT_EQ(PP_ERROR_FAILED, cb.result());
+
+  cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+  CHECK_CALLBACK_BEHAVIOR(cb);
+  ASSERT_EQ(PP_OK, cb.result());
+
+  cb.WaitForResult(
+      socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, true, cb.GetCallback()));
+  CHECK_CALLBACK_BEHAVIOR(cb);
+  ASSERT_EQ(PP_OK, cb.result());
+
+  PASS();
+}
+
+int32_t TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket_Dev* socket,
+                                               std::string* s) {
+  char buffer[1000];
+
+  s->clear();
+  // Make sure we don't just hang if |Read()| spews.
+  while (s->size() < 10000) {
+    TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+    int32_t rv = socket->Read(buffer, sizeof(buffer), cb.GetCallback());
+    if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING)
+      return PP_ERROR_FAILED;
+    cb.WaitForResult(rv);
+    if (cb.result() < 0)
+      return cb.result();
+    if (cb.result() == 0)
+      return PP_ERROR_FAILED;  // Didn't get a \n-terminated line.
+    s->reserve(s->size() + cb.result());
+    for (int32_t i = 0; i < cb.result(); i++) {
+      s->push_back(buffer[i]);
+      if (buffer[i] == '\n')
+        return PP_OK;
+    }
+  }
+  return PP_ERROR_FAILED;
+}
+
+int32_t TestTCPSocket::WriteStringToSocket(pp::TCPSocket_Dev* socket,
+                                           const std::string& s) {
+  const char* buffer = s.data();
+  size_t written = 0;
+  while (written < s.size()) {
+    TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+    int32_t rv = socket->Write(buffer + written, s.size() - written,
+                               cb.GetCallback());
+    if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING)
+      return PP_ERROR_FAILED;
+    cb.WaitForResult(rv);
+    if (cb.result() < 0)
+      return cb.result();
+    if (cb.result() == 0)
+      return PP_ERROR_FAILED;
+    written += cb.result();
+  }
+  if (written != s.size())
+    return PP_ERROR_FAILED;
+  return PP_OK;
+}
diff --git a/ppapi/tests/test_tcp_socket.h b/ppapi/tests/test_tcp_socket.h
new file mode 100644
index 0000000..0ff7e338e
--- /dev/null
+++ b/ppapi/tests/test_tcp_socket.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PAPPI_TESTS_TEST_TCP_SOCKET_H_
+#define PAPPI_TESTS_TEST_TCP_SOCKET_H_
+
+#include <string>
+
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/cpp/dev/net_address_dev.h"
+#include "ppapi/tests/test_case.h"
+
+namespace pp {
+class TCPSocket_Dev;
+}
+
+class TestTCPSocket: public TestCase {
+ public:
+  explicit TestTCPSocket(TestingInstance* instance);
+
+  // TestCase implementation.
+  virtual bool Init();
+  virtual void RunTests(const std::string& filter);
+
+ private:
+  std::string TestConnect();
+  std::string TestReadWrite();
+  std::string TestSetOption();
+
+  int32_t ReadFirstLineFromSocket(pp::TCPSocket_Dev* socket, std::string* s);
+  int32_t WriteStringToSocket(pp::TCPSocket_Dev* socket, const std::string& s);
+
+  pp::NetAddress_Dev addr_;
+};
+
+#endif  // PAPPI_TESTS_TEST_TCP_SOCKET_H_
diff --git a/ppapi/tests/test_utils.cc b/ppapi/tests/test_utils.cc
index 86a9bc19..509d6ff8b 100644
--- a/ppapi/tests/test_utils.cc
+++ b/ppapi/tests/test_utils.cc
@@ -6,6 +6,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #if defined(_MSC_VER)
 #include <windows.h>
 #else
@@ -13,7 +14,11 @@
 #endif
 
 #include "ppapi/c/pp_errors.h"
+#include "ppapi/cpp/dev/net_address_dev.h"
+#include "ppapi/cpp/instance_handle.h"
 #include "ppapi/cpp/module.h"
+#include "ppapi/cpp/private/host_resolver_private.h"
+#include "ppapi/cpp/private/net_address_private.h"
 #include "ppapi/cpp/var.h"
 
 namespace {
@@ -98,6 +103,82 @@
     return (x << 8) | (x >> 8);
 }
 
+bool EqualNetAddress(const pp::NetAddress_Dev& addr1,
+                     const pp::NetAddress_Dev& addr2) {
+  if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED ||
+      addr2.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED) {
+    return false;
+  }
+
+  if (addr1.GetFamily() == PP_NETADDRESS_FAMILY_IPV4) {
+    PP_NetAddress_IPv4_Dev ipv4_addr1, ipv4_addr2;
+    if (!addr1.DescribeAsIPv4Address(&ipv4_addr1) ||
+        !addr2.DescribeAsIPv4Address(&ipv4_addr2)) {
+      return false;
+    }
+
+    return ipv4_addr1.port == ipv4_addr2.port &&
+           !memcmp(ipv4_addr1.addr, ipv4_addr2.addr, sizeof(ipv4_addr1.addr));
+  } else {
+    PP_NetAddress_IPv6_Dev ipv6_addr1, ipv6_addr2;
+    if (!addr1.DescribeAsIPv6Address(&ipv6_addr1) ||
+        !addr2.DescribeAsIPv6Address(&ipv6_addr2)) {
+      return false;
+    }
+
+    return ipv6_addr1.port == ipv6_addr2.port &&
+           !memcmp(ipv6_addr1.addr, ipv6_addr2.addr, sizeof(ipv6_addr1.addr));
+  }
+}
+
+bool ResolveHost(PP_Instance instance,
+                 const std::string& host,
+                 uint16_t port,
+                 pp::NetAddress_Dev* addr) {
+  // TODO(yzshen): Change to use the public host resolver once it is supported.
+  pp::InstanceHandle instance_handle(instance);
+  pp::HostResolverPrivate host_resolver(instance_handle);
+  PP_HostResolver_Private_Hint hint = { PP_NETADDRESSFAMILY_UNSPECIFIED, 0 };
+
+  TestCompletionCallback callback(instance);
+  callback.WaitForResult(
+      host_resolver.Resolve(host, port, hint, callback.GetCallback()));
+
+  PP_NetAddress_Private addr_private;
+  if (callback.result() != PP_OK || host_resolver.GetSize() == 0 ||
+      !host_resolver.GetNetAddress(0, &addr_private)) {
+    return false;
+  }
+
+  switch (pp::NetAddressPrivate::GetFamily(addr_private)) {
+    case PP_NETADDRESSFAMILY_IPV4: {
+      PP_NetAddress_IPv4_Dev ipv4_addr;
+      ipv4_addr.port = ConvertToNetEndian16(
+          pp::NetAddressPrivate::GetPort(addr_private));
+      if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv4_addr.addr,
+                                             sizeof(ipv4_addr.addr))) {
+        return false;
+      }
+      *addr = pp::NetAddress_Dev(instance_handle, ipv4_addr);
+      return true;
+    }
+    case PP_NETADDRESSFAMILY_IPV6: {
+      PP_NetAddress_IPv6_Dev ipv6_addr;
+      ipv6_addr.port = ConvertToNetEndian16(
+          pp::NetAddressPrivate::GetPort(addr_private));
+      if (!pp::NetAddressPrivate::GetAddress(addr_private, ipv6_addr.addr,
+                                             sizeof(ipv6_addr.addr))) {
+        return false;
+      }
+      *addr = pp::NetAddress_Dev(instance_handle, ipv6_addr);
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
 void NestedEvent::Wait() {
   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
   // Don't allow nesting more than once; it doesn't work with the code as-is,
diff --git a/ppapi/tests/test_utils.h b/ppapi/tests/test_utils.h
index 0410018..04aa452 100644
--- a/ppapi/tests/test_utils.h
+++ b/ppapi/tests/test_utils.h
@@ -14,6 +14,10 @@
 #include "ppapi/cpp/message_loop.h"
 #include "ppapi/utility/completion_callback_factory.h"
 
+namespace pp {
+class NetAddress_Dev;
+}
+
 // Timeout to wait for some action to complete.
 extern const int kActionTimeoutMs;
 
@@ -24,6 +28,13 @@
 
 uint16_t ConvertFromNetEndian16(uint16_t x);
 uint16_t ConvertToNetEndian16(uint16_t x);
+bool EqualNetAddress(const pp::NetAddress_Dev& addr1,
+                     const pp::NetAddress_Dev& addr2);
+// Only returns the first address if there are more than one available.
+bool ResolveHost(PP_Instance instance,
+                 const std::string& host,
+                 uint16_t port,
+                 pp::NetAddress_Dev* addr);
 
 // NestedEvent allows you to run a nested MessageLoop and wait for a particular
 // event to complete. For example, you can use it to wait for a callback on a
diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h
index 1628e873..e953811 100644
--- a/ppapi/thunk/interfaces_ppb_public_dev.h
+++ b/ppapi/thunk/interfaces_ppb_public_dev.h
@@ -7,6 +7,8 @@
 
 #include "ppapi/thunk/interfaces_preamble.h"
 
+PROXIED_API(PPB_TCPSocket)
+
 // Map the old dev console interface to the stable one (which is the same) to
 // keep Flash, etc. working.
 PROXIED_IFACE(PPB_Instance, "PPB_Console(Dev);0.1", PPB_Console_1_0)
@@ -34,6 +36,8 @@
               PPB_Printing_Dev_0_7)
 PROXIED_IFACE(NoAPIName, PPB_RESOURCEARRAY_DEV_INTERFACE_0_1,
               PPB_ResourceArray_Dev_0_1)
+PROXIED_IFACE(PPB_TCPSocket, PPB_TCPSOCKET_DEV_INTERFACE_0_1,
+              PPB_TCPSocket_Dev_0_1)
 PROXIED_IFACE(PPB_Instance, PPB_TEXTINPUT_DEV_INTERFACE_0_2,
               PPB_TextInput_Dev_0_2)
 PROXIED_IFACE(NoAPIName, PPB_TRUETYPEFONT_DEV_INTERFACE_0_1,
diff --git a/ppapi/thunk/ppb_tcp_socket_api.h b/ppapi/thunk/ppb_tcp_socket_api.h
new file mode 100644
index 0000000..1b94a83
--- /dev/null
+++ b/ppapi/thunk/ppb_tcp_socket_api.h
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_THUNK_PPB_TCP_SOCKET_API_H_
+#define PPAPI_THUNK_PPB_TCP_SOCKET_API_H_
+
+#include "base/memory/ref_counted.h"
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
+#include "ppapi/thunk/ppapi_thunk_export.h"
+
+namespace ppapi {
+
+class TrackedCallback;
+
+namespace thunk {
+
+class PPAPI_THUNK_EXPORT PPB_TCPSocket_API {
+ public:
+  virtual ~PPB_TCPSocket_API() {}
+
+  virtual int32_t Connect(PP_Resource addr,
+                          scoped_refptr<TrackedCallback> callback) = 0;
+  virtual PP_Resource GetLocalAddress() = 0;
+  virtual PP_Resource GetRemoteAddress() = 0;
+  virtual int32_t Read(char* buffer,
+                       int32_t bytes_to_read,
+                       scoped_refptr<TrackedCallback> callback) = 0;
+  virtual int32_t Write(const char* buffer,
+                        int32_t bytes_to_write,
+                        scoped_refptr<TrackedCallback> callback) = 0;
+  virtual void Close() = 0;
+  virtual int32_t SetOption(PP_TCPSocket_Option_Dev name,
+                            const PP_Var& value,
+                            scoped_refptr<TrackedCallback> callback) = 0;
+};
+
+}  // namespace thunk
+}  // namespace ppapi
+
+#endif  // PPAPI_THUNK_PPB_TCP_SOCKET_API_H_
diff --git a/ppapi/thunk/ppb_tcp_socket_dev_thunk.cc b/ppapi/thunk/ppb_tcp_socket_dev_thunk.cc
new file mode 100644
index 0000000..43a1968
--- /dev/null
+++ b/ppapi/thunk/ppb_tcp_socket_dev_thunk.cc
@@ -0,0 +1,128 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// From dev/ppb_tcp_socket_dev.idl modified Wed Jun 05 23:11:18 2013.
+
+#include "ppapi/c/dev/ppb_tcp_socket_dev.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_instance_api.h"
+#include "ppapi/thunk/ppb_tcp_socket_api.h"
+#include "ppapi/thunk/resource_creation_api.h"
+#include "ppapi/thunk/thunk.h"
+
+namespace ppapi {
+namespace thunk {
+
+namespace {
+
+PP_Resource Create(PP_Instance instance) {
+  VLOG(4) << "PPB_TCPSocket_Dev::Create()";
+  EnterResourceCreation enter(instance);
+  if (enter.failed())
+    return 0;
+  return enter.functions()->CreateTCPSocket(instance);
+}
+
+PP_Bool IsTCPSocket(PP_Resource resource) {
+  VLOG(4) << "PPB_TCPSocket_Dev::IsTCPSocket()";
+  EnterResource<PPB_TCPSocket_API> enter(resource, false);
+  return PP_FromBool(enter.succeeded());
+}
+
+int32_t Connect(PP_Resource tcp_socket,
+                PP_Resource addr,
+                struct PP_CompletionCallback callback) {
+  VLOG(4) << "PPB_TCPSocket_Dev::Connect()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+  if (enter.failed())
+    return enter.retval();
+  return enter.SetResult(enter.object()->Connect(addr, enter.callback()));
+}
+
+PP_Resource GetLocalAddress(PP_Resource tcp_socket) {
+  VLOG(4) << "PPB_TCPSocket_Dev::GetLocalAddress()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, true);
+  if (enter.failed())
+    return 0;
+  return enter.object()->GetLocalAddress();
+}
+
+PP_Resource GetRemoteAddress(PP_Resource tcp_socket) {
+  VLOG(4) << "PPB_TCPSocket_Dev::GetRemoteAddress()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, true);
+  if (enter.failed())
+    return 0;
+  return enter.object()->GetRemoteAddress();
+}
+
+int32_t Read(PP_Resource tcp_socket,
+             char* buffer,
+             int32_t bytes_to_read,
+             struct PP_CompletionCallback callback) {
+  VLOG(4) << "PPB_TCPSocket_Dev::Read()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+  if (enter.failed())
+    return enter.retval();
+  return enter.SetResult(enter.object()->Read(buffer,
+                                              bytes_to_read,
+                                              enter.callback()));
+}
+
+int32_t Write(PP_Resource tcp_socket,
+              const char* buffer,
+              int32_t bytes_to_write,
+              struct PP_CompletionCallback callback) {
+  VLOG(4) << "PPB_TCPSocket_Dev::Write()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+  if (enter.failed())
+    return enter.retval();
+  return enter.SetResult(enter.object()->Write(buffer,
+                                               bytes_to_write,
+                                               enter.callback()));
+}
+
+void Close(PP_Resource tcp_socket) {
+  VLOG(4) << "PPB_TCPSocket_Dev::Close()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, true);
+  if (enter.failed())
+    return;
+  enter.object()->Close();
+}
+
+int32_t SetOption(PP_Resource tcp_socket,
+                  PP_TCPSocket_Option_Dev name,
+                  struct PP_Var value,
+                  struct PP_CompletionCallback callback) {
+  VLOG(4) << "PPB_TCPSocket_Dev::SetOption()";
+  EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+  if (enter.failed())
+    return enter.retval();
+  return enter.SetResult(enter.object()->SetOption(name,
+                                                   value,
+                                                   enter.callback()));
+}
+
+const PPB_TCPSocket_Dev_0_1 g_ppb_tcpsocket_dev_thunk_0_1 = {
+  &Create,
+  &IsTCPSocket,
+  &Connect,
+  &GetLocalAddress,
+  &GetRemoteAddress,
+  &Read,
+  &Write,
+  &Close,
+  &SetOption
+};
+
+}  // namespace
+
+const PPB_TCPSocket_Dev_0_1* GetPPB_TCPSocket_Dev_0_1_Thunk() {
+  return &g_ppb_tcpsocket_dev_thunk_0_1;
+}
+
+}  // namespace thunk
+}  // namespace ppapi
diff --git a/ppapi/thunk/resource_creation_api.h b/ppapi/thunk/resource_creation_api.h
index 38b6d12..a760030 100644
--- a/ppapi/thunk/resource_creation_api.h
+++ b/ppapi/thunk/resource_creation_api.h
@@ -28,6 +28,7 @@
 struct PP_BrowserFont_Trusted_Description;
 struct PP_NetAddress_IPv4_Dev;
 struct PP_NetAddress_IPv6_Dev;
+struct PP_NetAddress_Private;
 struct PP_Size;
 
 namespace ppapi {
@@ -141,12 +142,16 @@
   virtual PP_Resource CreateNetAddressFromIPv6Address(
       PP_Instance instance,
       const PP_NetAddress_IPv6_Dev* ipv6_addr) = 0;
+  virtual PP_Resource CreateNetAddressFromNetAddressPrivate(
+      PP_Instance instance,
+      const PP_NetAddress_Private& private_addr) = 0;
   virtual PP_Resource CreateNetworkMonitor(
       PP_Instance instance,
       PPB_NetworkMonitor_Callback callback,
       void* user_data) = 0;
   virtual PP_Resource CreatePrinting(PP_Instance instance) = 0;
   virtual PP_Resource CreateTCPServerSocketPrivate(PP_Instance instance) = 0;
+  virtual PP_Resource CreateTCPSocket(PP_Instance instace) = 0;
   virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instace) = 0;
   virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instace) = 0;
   virtual PP_Resource CreateWebSocket(PP_Instance instance) = 0;