--- /dev/null
+// Copyright (C) 2014 The Android Open Source Project
+//
+// 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 "emugl/common/sockets.h"
+
+#include <errno.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+namespace emugl {
+
+namespace {
+
+static void socketSetDontLinger(int s) {
+#ifdef _WIN32
+ // TODO: Verify default behavior on WINDOWS
+#else
+ // Ungraceful shutdown, no reason to linger at all
+ struct linger so_linger;
+ so_linger.l_onoff = 1;
+ so_linger.l_linger = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger) < 0)
+ perror("Setting socket option SO_LINGER={on, 0} failed");
+#endif
+}
+
+static void socketSetReuseAddress(int s) {
+#ifdef _WIN32
+ // The default behaviour on Windows is equivalent to SO_REUSEADDR
+ // so we don't need to set this option. Moreover, one should never
+ // set this option with WinSock because it's badly implemented and
+ // generates a huge security issue. See:
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx
+#else
+ int val = 1;
+ if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
+ perror("Setting socket option SO_REUSEADDR failed");
+#endif
+}
+
+// Helper union to store a socket address.
+struct SockAddr {
+ socklen_t len;
+ union {
+ sockaddr generic;
+ sockaddr_in inet;
+#ifndef _WIN32
+ sockaddr_un local;
+#endif
+ };
+
+ int getFamily() const { return generic.sa_family; }
+
+ void initEmpty() {
+ ::memset(this, 0, sizeof(*this));
+ this->len = static_cast<socklen_t>(sizeof(*this));
+ }
+
+ int initFromInet(uint32_t ip_address, int port) {
+ if (port < 0 || port >= 65536)
+ return -EINVAL;
+
+ ::memset(this, 0, sizeof(*this));
+ this->inet.sin_family = AF_INET;
+ this->inet.sin_port = htons(port);
+ this->inet.sin_addr.s_addr = htonl(ip_address);
+ this->len = sizeof(this->inet);
+ return 0;
+ }
+
+ int initFromLocalhost(int port) {
+ return initFromInet(0x7f000001, port);
+ }
+
+#ifndef _WIN32
+ // Initialize the SockAddr from a Unix path. Returns 0 on success,
+ // or -errno code on failure.
+ int initFromUnixPath(const char* path) {
+ if (!path || !path[0])
+ return -EINVAL;
+
+ size_t pathLen = ::strlen(path);
+ if (pathLen >= sizeof(local.sun_path))
+ return -E2BIG;
+
+ ::memset(this, 0, sizeof(*this));
+ this->local.sun_family = AF_LOCAL;
+ ::memcpy(this->local.sun_path, path, pathLen + 1U);
+ this->len = pathLen + offsetof(sockaddr_un, sun_path);
+ return 0;
+ }
+#endif
+};
+
+int socketBindInternal(const SockAddr* addr, int socketType) {
+ int s = ::socket(addr->getFamily(), socketType, 0);
+ if (s < 0) {
+ perror("Could not create socket to bind");
+ return -errno;
+ }
+
+ socketSetDontLinger(s);
+ socketSetReuseAddress(s);
+
+ // Bind to the socket.
+ if (::bind(s, &addr->generic, addr->len) < 0 ||
+ ::listen(s, 5) < 0) {
+ int ret = -errno;
+ perror("Could not bind or listen to socket");
+ ::close(s);
+ return ret;
+ }
+
+ return s;
+}
+
+int socketConnectInternal(const SockAddr* addr, int socketType) {
+ int s = ::socket(addr->getFamily(), socketType, 0);
+ if (s < 0) {
+ perror("Could not create socket to connect");
+ return -errno;
+ }
+
+ socketSetDontLinger(s);
+ socketSetReuseAddress(s);
+
+ int ret;
+ do {
+ ret = ::connect(s, &addr->generic, addr->len);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ ret = -errno;
+ ::close(s);
+ return ret;
+ }
+
+ return s;
+}
+
+} // namespace
+
+void socketTcpDisableNagle(int s) {
+ // disable Nagle algorithm to improve bandwidth of small
+ // packets which are quite common in our implementation.
+#ifdef _WIN32
+ DWORD flag;
+#else
+ int flag;
+#endif
+ flag = 1;
+ setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
+ (const char*)&flag, sizeof(flag));
+}
+
+int socketGetPort(int s) {
+ SockAddr addr;
+ addr.initEmpty();
+ if (getsockname(s, &addr.generic, &addr.len) < 0) {
+ return -errno;
+ }
+ switch (addr.generic.sa_family) {
+ case AF_INET:
+ return ntohs(addr.inet.sin_port);
+ default:
+ ;
+ }
+ return -EINVAL;
+}
+
+#ifndef _WIN32
+int socketLocalServer(const char* path, int socketType) {
+ SockAddr addr;
+ int ret = addr.initFromUnixPath(path);
+ if (ret < 0) {
+ return ret;
+ }
+ return socketBindInternal(&addr, socketType);
+}
+
+int socketLocalClient(const char* path, int socketType) {
+ SockAddr addr;
+ int ret = addr.initFromUnixPath(path);
+ if (ret < 0) {
+ return ret;
+ }
+ return socketConnectInternal(&addr, socketType);
+}
+#endif // !_WIN32
+
+int socketTcpLoopbackServer(int port, int socketType) {
+ SockAddr addr;
+ int ret = addr.initFromLocalhost(port);
+ if (ret < 0) {
+ return ret;
+ }
+ return socketBindInternal(&addr, socketType);
+}
+
+int socketTcpLoopbackClient(int port, int socketType) {
+ SockAddr addr;
+ int ret = addr.initFromLocalhost(port);
+ if (ret < 0) {
+ return ret;
+ }
+ return socketConnectInternal(&addr, socketType);
+}
+
+int socketTcpClient(const char* hostname, int port, int socketType) {
+ // TODO(digit): Implement this.
+ return -ENOSYS;
+}
+
+int socketAccept(int serverSocket) {
+ int ret;
+ do {
+ ret = ::accept(serverSocket, NULL, NULL);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+} // namespace emugl