Initial work
This commit is contained in:
commit
3222551702
374 changed files with 40290 additions and 0 deletions
247
external/android-emugl/shared/emugl/common/sockets.cpp
vendored
Normal file
247
external/android-emugl/shared/emugl/common/sockets.cpp
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue