Squashed 'third_party/ntcore_2016/' content from commit d8de5e4

Change-Id: Id4839f41b6a620d8bae58dcf1710016671cc4992
git-subtree-dir: third_party/ntcore_2016
git-subtree-split: d8de5e4f19e612e7102172c0dbf152ce82d3d63a
diff --git a/src/tcpsockets/NetworkAcceptor.h b/src/tcpsockets/NetworkAcceptor.h
new file mode 100644
index 0000000..4702b7f
--- /dev/null
+++ b/src/tcpsockets/NetworkAcceptor.h
@@ -0,0 +1,26 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#ifndef TCPSOCKETS_NETWORKACCEPTOR_H_
+#define TCPSOCKETS_NETWORKACCEPTOR_H_
+
+#include "NetworkStream.h"
+
+class NetworkAcceptor {
+ public:
+  NetworkAcceptor() = default;
+  virtual ~NetworkAcceptor() = default;
+
+  virtual int start() = 0;
+  virtual void shutdown() = 0;
+  virtual std::unique_ptr<NetworkStream> accept() = 0;
+
+  NetworkAcceptor(const NetworkAcceptor&) = delete;
+  NetworkAcceptor& operator=(const NetworkAcceptor&) = delete;
+};
+
+#endif  // TCPSOCKETS_NETWORKACCEPTOR_H_
diff --git a/src/tcpsockets/NetworkStream.h b/src/tcpsockets/NetworkStream.h
new file mode 100644
index 0000000..63aedb4
--- /dev/null
+++ b/src/tcpsockets/NetworkStream.h
@@ -0,0 +1,39 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#ifndef TCPSOCKETS_NETWORKSTREAM_H_
+#define TCPSOCKETS_NETWORKSTREAM_H_
+
+#include <cstddef>
+
+#include "llvm/StringRef.h"
+
+class NetworkStream {
+ public:
+  NetworkStream() = default;
+  virtual ~NetworkStream() = default;
+
+  enum Error {
+    kConnectionClosed = 0,
+    kConnectionReset = -1,
+    kConnectionTimedOut = -2
+  };
+
+  virtual std::size_t send(const char* buffer, std::size_t len, Error* err) = 0;
+  virtual std::size_t receive(char* buffer, std::size_t len, Error* err,
+                              int timeout = 0) = 0;
+  virtual void close() = 0;
+
+  virtual llvm::StringRef getPeerIP() const = 0;
+  virtual int getPeerPort() const = 0;
+  virtual void setNoDelay() = 0;
+
+  NetworkStream(const NetworkStream&) = delete;
+  NetworkStream& operator=(const NetworkStream&) = delete;
+};
+
+#endif  // TCPSOCKETS_NETWORKSTREAM_H_
diff --git a/src/tcpsockets/SocketError.cpp b/src/tcpsockets/SocketError.cpp
new file mode 100644
index 0000000..9619edd
--- /dev/null
+++ b/src/tcpsockets/SocketError.cpp
@@ -0,0 +1,31 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "SocketError.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <string.h>
+#endif
+
+namespace tcpsockets {
+
+std::string SocketStrerror(int code) {
+#ifdef _WIN32
+  LPSTR errstr = nullptr;
+  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                0, code, 0, (LPSTR)&errstr, 0, 0);
+  std::string rv(errstr);
+  LocalFree(errstr);
+  return rv;
+#else
+  return strerror(code);
+#endif
+}
+
+}  // namespace tcpsockets
diff --git a/src/tcpsockets/SocketError.h b/src/tcpsockets/SocketError.h
new file mode 100644
index 0000000..267e8da
--- /dev/null
+++ b/src/tcpsockets/SocketError.h
@@ -0,0 +1,37 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#ifndef TCPSOCKETS_SOCKETERROR_H_
+#define TCPSOCKETS_SOCKETERROR_H_
+
+#include <string>
+
+#ifdef _WIN32
+#include <WinSock2.h>
+#else
+#include <errno.h>
+#endif
+
+namespace tcpsockets {
+
+static inline int SocketErrno() {
+#ifdef _WIN32
+  return WSAGetLastError();
+#else
+  return errno;
+#endif
+}
+
+std::string SocketStrerror(int code);
+
+static inline std::string SocketStrerror() {
+  return SocketStrerror(SocketErrno());
+}
+
+}  // namespace tcpsockets
+
+#endif  // TCPSOCKETS_SOCKETERROR_H_
diff --git a/src/tcpsockets/TCPAcceptor.cpp b/src/tcpsockets/TCPAcceptor.cpp
new file mode 100644
index 0000000..3b7e16e
--- /dev/null
+++ b/src/tcpsockets/TCPAcceptor.cpp
@@ -0,0 +1,182 @@
+/*
+   TCPAcceptor.cpp
+
+   TCPAcceptor class definition. TCPAcceptor provides methods to passively
+   establish TCP/IP connections with clients.
+
+   ------------------------------------------
+
+   Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+#include "TCPAcceptor.h"
+
+#include <cstdio>
+#include <cstring>
+#ifdef _WIN32
+#include <WinSock2.h>
+#pragma comment(lib, "Ws2_32.lib")
+#else
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+#include "llvm/SmallString.h"
+#include "../Log.h"
+#include "SocketError.h"
+
+using namespace tcpsockets;
+
+TCPAcceptor::TCPAcceptor(int port, const char* address)
+    : m_lsd(0),
+      m_port(port),
+      m_address(address),
+      m_listening(false) {
+  m_shutdown = false;
+#ifdef _WIN32
+  WSAData wsaData;
+  WORD wVersionRequested = MAKEWORD(2, 2);
+  WSAStartup(wVersionRequested, &wsaData);
+#endif
+}
+
+TCPAcceptor::~TCPAcceptor() {
+  if (m_lsd > 0) {
+    shutdown();
+#ifdef _WIN32
+    closesocket(m_lsd);
+#else
+    close(m_lsd);
+#endif
+  }
+#ifdef _WIN32
+  WSACleanup();
+#endif
+}
+
+int TCPAcceptor::start() {
+  if (m_listening) return 0;
+
+  m_lsd = socket(PF_INET, SOCK_STREAM, 0);
+  struct sockaddr_in address;
+
+  std::memset(&address, 0, sizeof(address));
+  address.sin_family = PF_INET;
+  if (m_address.size() > 0) {
+#ifdef _WIN32
+    llvm::SmallString<128> addr_copy(m_address);
+    addr_copy.push_back('\0');
+    int size = sizeof(address);
+    WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size);
+#else
+    inet_pton(PF_INET, m_address.c_str(), &(address.sin_addr));
+#endif
+  } else {
+    address.sin_addr.s_addr = INADDR_ANY;
+  }
+  address.sin_port = htons(m_port);
+
+  int optval = 1;
+  setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof optval);
+
+  int result = bind(m_lsd, (struct sockaddr*)&address, sizeof(address));
+  if (result != 0) {
+    ERROR("bind() failed: " << SocketStrerror());
+    return result;
+  }
+
+  result = listen(m_lsd, 5);
+  if (result != 0) {
+    ERROR("listen() failed: " << SocketStrerror());
+    return result;
+  }
+  m_listening = true;
+  return result;
+}
+
+void TCPAcceptor::shutdown() {
+  m_shutdown = true;
+#ifdef _WIN32
+  ::shutdown(m_lsd, SD_BOTH);
+
+  // this is ugly, but the easiest way to do this
+  // force wakeup of accept() with a non-blocking connect to ourselves
+  struct sockaddr_in address;
+
+  std::memset(&address, 0, sizeof(address));
+  address.sin_family = PF_INET;
+  llvm::SmallString<128> addr_copy;
+  if (m_address.size() > 0)
+    addr_copy = m_address;
+  else
+    addr_copy = "127.0.0.1";
+  addr_copy.push_back('\0');
+  int size = sizeof(address);
+  if (WSAStringToAddress(addr_copy.data(), PF_INET, nullptr,
+                         (struct sockaddr*)&address, &size) != 0)
+    return;
+  address.sin_port = htons(m_port);
+
+  fd_set sdset;
+  struct timeval tv;
+  int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);
+
+  // Set socket to non-blocking
+  u_long mode = 1;
+  ioctlsocket(sd, FIONBIO, &mode);
+
+  // Try to connect
+  ::connect(sd, (struct sockaddr*)&address, sizeof(address));
+
+  // Close
+  ::closesocket(sd);
+
+#else
+  ::shutdown(m_lsd, SHUT_RDWR);
+  int nullfd = ::open("/dev/null", O_RDONLY);
+  if (nullfd >= 0) {
+    ::dup2(nullfd, m_lsd);
+    ::close(nullfd);
+  }
+#endif
+}
+
+std::unique_ptr<NetworkStream> TCPAcceptor::accept() {
+  if (!m_listening || m_shutdown) return nullptr;
+
+  struct sockaddr_in address;
+#ifdef _WIN32
+  int len = sizeof(address);
+#else
+  socklen_t len = sizeof(address);
+#endif
+  std::memset(&address, 0, sizeof(address));
+  int sd = ::accept(m_lsd, (struct sockaddr*)&address, &len);
+  if (sd < 0) {
+    if (!m_shutdown) ERROR("accept() failed: " << SocketStrerror());
+    return nullptr;
+  }
+  if (m_shutdown) {
+#ifdef _WIN32
+    closesocket(sd);
+#else
+    close(sd);
+#endif
+    return nullptr;
+  }
+  return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
+}
diff --git a/src/tcpsockets/TCPAcceptor.h b/src/tcpsockets/TCPAcceptor.h
new file mode 100644
index 0000000..d6a6ccc
--- /dev/null
+++ b/src/tcpsockets/TCPAcceptor.h
@@ -0,0 +1,50 @@
+/*
+   TCPAcceptor.h
+
+   TCPAcceptor class interface. TCPAcceptor provides methods to passively
+   establish TCP/IP connections with clients.
+
+   ------------------------------------------
+
+   Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+#ifndef TCPSOCKETS_TCPACCEPTOR_H_
+#define TCPSOCKETS_TCPACCEPTOR_H_
+
+#include <atomic>
+#include <memory>
+#include <string>
+
+#include "NetworkAcceptor.h"
+#include "TCPStream.h"
+
+class TCPAcceptor : public NetworkAcceptor {
+  int m_lsd;
+  int m_port;
+  std::string m_address;
+  bool m_listening;
+  std::atomic_bool m_shutdown;
+
+ public:
+  TCPAcceptor(int port, const char* address);
+  ~TCPAcceptor();
+
+  int start() override;
+  void shutdown() override;
+  std::unique_ptr<NetworkStream> accept() override;
+};
+
+#endif
diff --git a/src/tcpsockets/TCPConnector.cpp b/src/tcpsockets/TCPConnector.cpp
new file mode 100644
index 0000000..665500d
--- /dev/null
+++ b/src/tcpsockets/TCPConnector.cpp
@@ -0,0 +1,167 @@
+/*
+   TCPConnector.h
+
+   TCPConnector class definition. TCPConnector provides methods to actively
+   establish TCP/IP connections with a server.
+
+   ------------------------------------------
+
+   Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License
+*/
+
+#include "TCPConnector.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <cstdio>
+#include <cstring>
+#ifdef _WIN32
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+#else
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#endif
+
+#include "TCPStream.h"
+
+#include "llvm/SmallString.h"
+#include "../Log.h"
+#include "SocketError.h"
+
+using namespace tcpsockets;
+
+static int ResolveHostName(const char* hostname, struct in_addr* addr) {
+  struct addrinfo hints;
+  struct addrinfo* res;
+
+  hints.ai_flags = 0;
+  hints.ai_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = 0;
+  hints.ai_addrlen = 0;
+  hints.ai_addr = nullptr;
+  hints.ai_canonname = nullptr;
+  hints.ai_next = nullptr;
+  int result = getaddrinfo(hostname, nullptr, &hints, &res);
+  if (result == 0) {
+    std::memcpy(addr, &((struct sockaddr_in*)res->ai_addr)->sin_addr,
+                sizeof(struct in_addr));
+    freeaddrinfo(res);
+  }
+  return result;
+}
+
+std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
+                                                     int port, int timeout) {
+#ifdef _WIN32
+  struct WSAHelper {
+    WSAHelper() {
+      WSAData wsaData;
+      WORD wVersionRequested = MAKEWORD(2, 2);
+      WSAStartup(wVersionRequested, &wsaData);
+    }
+    ~WSAHelper() { WSACleanup(); }
+  };
+  static WSAHelper helper;
+#endif
+  struct sockaddr_in address;
+
+  std::memset(&address, 0, sizeof(address));
+  address.sin_family = AF_INET;
+  if (ResolveHostName(server, &(address.sin_addr)) != 0) {
+#ifdef _WIN32
+    llvm::SmallString<128> addr_copy(server);
+    addr_copy.push_back('\0');
+    int size = sizeof(address);
+    if (WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size) != 0) {
+      ERROR("could not resolve " << server << " address");
+      return nullptr;
+    }
+#else
+    inet_pton(PF_INET, server, &(address.sin_addr));
+#endif
+  }
+  address.sin_port = htons(port);
+
+  if (timeout == 0) {
+    int sd = socket(AF_INET, SOCK_STREAM, 0);
+    if (::connect(sd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+      ERROR("connect() to " << server << " port " << port << " failed: " << SocketStrerror());
+      return nullptr;
+    }
+    return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
+  }
+
+  fd_set sdset;
+  struct timeval tv;
+  socklen_t len;
+  int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);
+
+  // Set socket to non-blocking
+#ifdef _WIN32
+  u_long mode = 1;
+  ioctlsocket(sd, FIONBIO, &mode);
+#else
+  long arg;
+  arg = fcntl(sd, F_GETFL, nullptr);
+  arg |= O_NONBLOCK;
+  fcntl(sd, F_SETFL, arg);
+#endif
+
+  // Connect with time limit
+  if ((result = ::connect(sd, (struct sockaddr*)&address, sizeof(address))) <
+      0) {
+    int my_errno = SocketErrno();
+#ifdef _WIN32
+    if (my_errno == WSAEWOULDBLOCK || my_errno == WSAEINPROGRESS) {
+#else
+    if (my_errno == EWOULDBLOCK || my_errno == EINPROGRESS) {
+#endif
+      tv.tv_sec = timeout;
+      tv.tv_usec = 0;
+      FD_ZERO(&sdset);
+      FD_SET(sd, &sdset);
+      if (select(sd + 1, nullptr, &sdset, nullptr, &tv) > 0) {
+        len = sizeof(int);
+        getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len);
+        if (valopt) {
+          ERROR("select() to " << server << " port " << port << " error " << valopt << " - " << SocketStrerror(valopt));
+        }
+        // connection established
+        else
+          result = 0;
+      } else
+        INFO("connect() to " << server << " port " << port << " timed out");
+    } else
+      ERROR("connect() to " << server << " port " << port << " error " << SocketErrno() << " - " << SocketStrerror());
+  }
+
+  // Return socket to blocking mode
+#ifdef _WIN32
+  mode = 0;
+  ioctlsocket(sd, FIONBIO, &mode);
+#else
+  arg = fcntl(sd, F_GETFL, nullptr);
+  arg &= (~O_NONBLOCK);
+  fcntl(sd, F_SETFL, arg);
+#endif
+
+  // Create stream object if connected
+  if (result == -1) return nullptr;
+  return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
+}
diff --git a/src/tcpsockets/TCPConnector.h b/src/tcpsockets/TCPConnector.h
new file mode 100644
index 0000000..ebac859
--- /dev/null
+++ b/src/tcpsockets/TCPConnector.h
@@ -0,0 +1,37 @@
+/*
+   TCPConnector.h
+
+   TCPConnector class interface. TCPConnector provides methods to actively
+   establish TCP/IP connections with a server.
+
+   ------------------------------------------
+
+   Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License
+*/
+
+#ifndef TCPSOCKETS_TCPCONNECTOR_H_
+#define TCPSOCKETS_TCPCONNECTOR_H_
+
+#include <memory>
+
+#include "NetworkStream.h"
+
+class TCPConnector {
+ public:
+  static std::unique_ptr<NetworkStream> connect(const char* server, int port,
+                                                int timeout = 0);
+};
+
+#endif
diff --git a/src/tcpsockets/TCPStream.cpp b/src/tcpsockets/TCPStream.cpp
new file mode 100644
index 0000000..3149be6
--- /dev/null
+++ b/src/tcpsockets/TCPStream.cpp
@@ -0,0 +1,157 @@
+/*
+   TCPStream.h
+
+   TCPStream class definition. TCPStream provides methods to trasnfer
+   data between peers over a TCP/IP connection.
+
+   ------------------------------------------
+
+   Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+#include "TCPStream.h"
+
+#ifdef _WIN32
+#include <WinSock2.h>
+#else
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+#endif
+
+TCPStream::TCPStream(int sd, struct sockaddr_in* address) : m_sd(sd) {
+  char ip[50];
+#ifdef _WIN32
+  unsigned long size = sizeof(ip) - 1;
+  WSAAddressToString((struct sockaddr*)address, sizeof sockaddr_in, nullptr, ip, &size);
+#else
+  inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip,
+            sizeof(ip) - 1);
+#endif
+  m_peerIP = ip;
+  m_peerPort = ntohs(address->sin_port);
+}
+
+TCPStream::~TCPStream() { close(); }
+
+std::size_t TCPStream::send(const char* buffer, std::size_t len, Error* err) {
+  if (m_sd < 0) {
+    *err = kConnectionClosed;
+    return 0;
+  }
+#ifdef _WIN32
+  WSABUF wsaBuf;
+  wsaBuf.buf = const_cast<char*>(buffer);
+  wsaBuf.len = (ULONG)len;
+  DWORD rv;
+  bool result = true;
+  while (WSASend(m_sd, &wsaBuf, 1, &rv, 0, nullptr, nullptr) == SOCKET_ERROR) {
+    if (WSAGetLastError() != WSAEWOULDBLOCK) {
+      result = false;
+      break;
+    }
+    Sleep(1);
+  }
+  if (!result) {
+    char Buffer[128];
+#ifdef _MSC_VER
+    sprintf_s(Buffer, "Send() failed: WSA error=%d\n", WSAGetLastError());
+#else
+    std::snprintf(Buffer, 128, "Send() failed: WSA error=%d\n", WSAGetLastError());
+#endif
+    OutputDebugStringA(Buffer);
+    *err = kConnectionReset;
+    return 0;
+  }
+#else
+  ssize_t rv = write(m_sd, buffer, len);
+  if (rv < 0) {
+    *err = kConnectionReset;
+    return 0;
+  }
+#endif
+  return static_cast<std::size_t>(rv);
+}
+
+std::size_t TCPStream::receive(char* buffer, std::size_t len, Error* err,
+                               int timeout) {
+  if (m_sd < 0) {
+    *err = kConnectionClosed;
+    return 0;
+  }
+#ifdef _WIN32
+  int rv;
+#else
+  ssize_t rv;
+#endif
+  if (timeout <= 0) {
+#ifdef _WIN32
+    rv = recv(m_sd, buffer, len, 0);
+#else
+    rv = read(m_sd, buffer, len);
+#endif
+  }
+  else if (WaitForReadEvent(timeout)) {
+#ifdef _WIN32
+    rv = recv(m_sd, buffer, len, 0);
+#else
+    rv = read(m_sd, buffer, len);
+#endif
+  } else {
+    *err = kConnectionTimedOut;
+    return 0;
+  }
+  if (rv < 0) {
+    *err = kConnectionReset;
+    return 0;
+  }
+  return static_cast<std::size_t>(rv);
+}
+
+void TCPStream::close() {
+  if (m_sd >= 0) {
+#ifdef _WIN32
+    ::shutdown(m_sd, SD_BOTH);
+    closesocket(m_sd);
+#else
+    ::shutdown(m_sd, SHUT_RDWR);
+    ::close(m_sd);
+#endif
+  }
+  m_sd = -1;
+}
+
+llvm::StringRef TCPStream::getPeerIP() const { return m_peerIP; }
+
+int TCPStream::getPeerPort() const { return m_peerPort; }
+
+void TCPStream::setNoDelay() {
+  int optval = 1;
+  setsockopt(m_sd, IPPROTO_TCP, TCP_NODELAY, (char*)&optval, sizeof optval);
+}
+
+bool TCPStream::WaitForReadEvent(int timeout) {
+  fd_set sdset;
+  struct timeval tv;
+
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+  FD_ZERO(&sdset);
+  FD_SET(m_sd, &sdset);
+  if (select(m_sd + 1, &sdset, NULL, NULL, &tv) > 0) {
+    return true;
+  }
+  return false;
+}
diff --git a/src/tcpsockets/TCPStream.h b/src/tcpsockets/TCPStream.h
new file mode 100644
index 0000000..21ef6fd
--- /dev/null
+++ b/src/tcpsockets/TCPStream.h
@@ -0,0 +1,67 @@
+/*
+   TCPStream.h
+
+   TCPStream class interface. TCPStream provides methods to trasnfer
+   data between peers over a TCP/IP connection.
+
+   ------------------------------------------
+
+   Copyright © 2013 [Vic Hargrave - http://vichargrave.com]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+#ifndef TCPSOCKETS_TCPSTREAM_H_
+#define TCPSOCKETS_TCPSTREAM_H_
+
+#include <cstddef>
+#include <string>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+
+#include "NetworkStream.h"
+
+class TCPStream : public NetworkStream {
+  int m_sd;
+  std::string m_peerIP;
+  int m_peerPort;
+
+ public:
+  friend class TCPAcceptor;
+  friend class TCPConnector;
+
+  ~TCPStream();
+
+  std::size_t send(const char* buffer, std::size_t len, Error* err) override;
+  std::size_t receive(char* buffer, std::size_t len, Error* err,
+                      int timeout = 0) override;
+  void close() override;
+
+  llvm::StringRef getPeerIP() const override;
+  int getPeerPort() const override;
+  void setNoDelay() override;
+
+  TCPStream(const TCPStream& stream) = delete;
+  TCPStream& operator=(const TCPStream&) = delete;
+ private:
+  bool WaitForReadEvent(int timeout);
+
+  TCPStream(int sd, struct sockaddr_in* address);
+  TCPStream() = delete;
+};
+
+#endif