diff options
Diffstat (limited to 'emulator')
6 files changed, 308 insertions, 55 deletions
diff --git a/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp index f7a2314..3ef4c6f 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp +++ b/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ #include "SocketStream.h" -#include <cutils/sockets.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -53,6 +52,7 @@ SocketStream::~SocketStream() #else ::close(m_sock); #endif + m_sock = -1; } if (m_buf != NULL) { free(m_buf); @@ -140,7 +140,7 @@ const unsigned char *SocketStream::read( void *buf, size_t *inout_len) int n; do { - n = recv(buf, *inout_len); + n = this->recv(buf, *inout_len); } while( n < 0 && errno == EINTR ); if (n > 0) { diff --git a/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp index 8a6e56e..ba355ab 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp +++ b/emulator/opengl/shared/OpenglCodecCommon/TcpStream.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ #include "TcpStream.h" -#include <cutils/sockets.h> +#include "emugl/common/sockets.h" + #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -30,77 +31,48 @@ #define LISTEN_BACKLOG 4 -TcpStream::TcpStream(size_t bufSize) : - SocketStream(bufSize) -{ -} +TcpStream::TcpStream(size_t bufSize) : SocketStream(bufSize) {} TcpStream::TcpStream(int sock, size_t bufSize) : - SocketStream(sock, bufSize) -{ + SocketStream(sock, bufSize) { // 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( sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag) ); + emugl::socketTcpDisableNagle(sock); } -int TcpStream::listen(char addrstr[MAX_ADDRSTR_LEN]) -{ - m_sock = socket_loopback_server(0, SOCK_STREAM); +int TcpStream::listen(char addrstr[MAX_ADDRSTR_LEN]) { + m_sock = emugl::socketTcpLoopbackServer(0, SOCK_STREAM); if (!valid()) return int(ERR_INVALID_SOCKET); - /* get the actual port number assigned by the system */ - struct sockaddr_in addr; - socklen_t addrLen = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - if (getsockname(m_sock, (struct sockaddr*)&addr, &addrLen) < 0) { - close(m_sock); + int port = emugl::socketGetPort(m_sock); + if (port < 0) { + ::close(m_sock); return int(ERR_INVALID_SOCKET); } - snprintf(addrstr, MAX_ADDRSTR_LEN - 1, "%hu", ntohs(addr.sin_port)); + + snprintf(addrstr, MAX_ADDRSTR_LEN - 1, "%hu", port); addrstr[MAX_ADDRSTR_LEN-1] = '\0'; return 0; } -SocketStream * TcpStream::accept() -{ - int clientSock = -1; - - while (true) { - struct sockaddr_in addr; - socklen_t len = sizeof(addr); - clientSock = ::accept(m_sock, (sockaddr *)&addr, &len); - - if (clientSock < 0 && errno == EINTR) { - continue; - } - break; - } +SocketStream * TcpStream::accept() { + int clientSock = emugl::socketAccept(m_sock); + if (clientSock < 0) + return NULL; - TcpStream *clientStream = NULL; - - if (clientSock >= 0) { - clientStream = new TcpStream(clientSock, m_bufsize); - } - return clientStream; + return new TcpStream(clientSock, m_bufsize); } -int TcpStream::connect(const char* addr) -{ +int TcpStream::connect(const char* addr) { int port = atoi(addr); - return connect("127.0.0.1",port); + m_sock = emugl::socketTcpLoopbackClient(port, SOCK_STREAM); + return valid() ? 0 : -1; } int TcpStream::connect(const char* hostname, unsigned short port) { - m_sock = socket_network_client(hostname, port, SOCK_STREAM); - if (!valid()) return -1; - return 0; + m_sock = emugl::socketTcpClient(hostname, port, SOCK_STREAM); + return valid() ? 0 : -1; } diff --git a/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp index b2eef6d..7b2f67d 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp +++ b/emulator/opengl/shared/OpenglCodecCommon/UnixStream.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ #include "UnixStream.h" -#include <cutils/sockets.h> + +#include "emugl/common/sockets.h" + #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -92,7 +94,7 @@ int UnixStream::listen(char addrstr[MAX_ADDRSTR_LEN]) return -1; } - m_sock = socket_local_server(addrstr, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + m_sock = emugl::socketLocalServer(addrstr, SOCK_STREAM); if (!valid()) return int(ERR_INVALID_SOCKET); return 0; @@ -123,7 +125,7 @@ SocketStream * UnixStream::accept() int UnixStream::connect(const char* addr) { - m_sock = socket_local_client(addr, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + m_sock = emugl::socketLocalClient(addr, SOCK_STREAM); if (!valid()) return -1; return 0; diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk index f1c20b5..6a6c169 100644 --- a/emulator/opengl/shared/emugl/common/Android.mk +++ b/emulator/opengl/shared/emugl/common/Android.mk @@ -8,6 +8,7 @@ LOCAL_PATH := $(call my-dir) commonSources := \ lazy_instance.cpp \ smart_ptr.cpp \ + sockets.cpp \ thread_store.cpp \ host_commonSources := $(commonSources) diff --git a/emulator/opengl/shared/emugl/common/sockets.cpp b/emulator/opengl/shared/emugl/common/sockets.cpp new file mode 100644 index 0000000..feb6d38 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/sockets.cpp @@ -0,0 +1,221 @@ +// 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> +#endif + +#include <stddef.h> +#include <string.h> +#include <unistd.h> + +namespace emugl { + +namespace { + +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; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); +#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) + return -errno; + + // Bind to the socket. + if (::bind(s, &addr->generic, addr->len) < 0 || + ::listen(s, 5) < 0) { + int ret = -errno; + ::close(s); + return ret; + } + + socketSetReuseAddress(s); + return s; +} + +int socketConnectInternal(const SockAddr* addr, int socketType) { + int s = ::socket(addr->getFamily(), socketType, 0); + if (s < 0) + return -errno; + + 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 diff --git a/emulator/opengl/shared/emugl/common/sockets.h b/emulator/opengl/shared/emugl/common/sockets.h new file mode 100644 index 0000000..11e7ac7 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/sockets.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef EMUGL_COMMON_SOCKETS_H +#define EMUGL_COMMON_SOCKETS_H + +// A set of helper functions used to deal with sockets in a portable way. + +namespace emugl { + +// Disable Nagle's algorithm for socket descriptor |s|. This assumes +// that |s| is a TCP socket descriptor. +void socketTcpDisableNagle(int s); + +// Return the port associated with a given IP or IPv6 socket, +// or -errno code on failure. +int socketGetPort(int s); + +// Bind to a local/Unix path, and return its socket descriptor on success, +// or -errno code on failure. +int socketLocalServer(const char* path, int socketType); + +// Connect to a Unix local path, and return a new socket descriptor +// on success, or -errno code on failure. +int socketLocalClient(const char* path, int socketType); + +// Bind to a localhost TCP socket, and return its socket descriptor on +// success, or -errno code on failure. +int socketTcpLoopbackServer(int port, int socketType); + +// Connect to a localhost TCP port, and return a new socket descriptor on +// success, or -errno code on failure. +int socketTcpLoopbackClient(int port, int socketType); + +// Connect to a TCP host, and return a new socket descriptor on +// success, or -errno code on failure. +int socketTcpClient(const char* hostname, int port, int socketType); + +// Accept a new connection. |serverSocket| must be a bound server socket +// descriptor. Returns new socket descriptor on success, or -errno code +// on failure. +int socketAccept(int serverSocket); + +} // namespace emugl + +#endif // EMUGL_COMMON_SOCKETS_H |