blob: 7317c925f0a5ae579e675f37bb35b9c903325a39 [file] [log] [blame]
/*
* Copyright (C) 2019 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "RemoteInspectorSocket.h"
#if ENABLE(REMOTE_INSPECTOR)
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <wtf/UniStdExtras.h>
namespace Inspector {
namespace Socket {
void init()
{
}
Optional<PlatformSocketType> connect(const char* serverAddress, uint16_t serverPort)
{
struct sockaddr_in address = { };
address.sin_family = AF_INET;
inet_aton(serverAddress, &address.sin_addr);
address.sin_port = htons(serverPort);
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) {
LOG_ERROR("Failed to create socket for %s:%d, errno = %d", serverAddress, serverPort, errno);
return WTF::nullopt;
}
int error = ::connect(fd, (struct sockaddr*)&address, sizeof(address));
if (error < 0) {
LOG_ERROR("Failed to connect to %s:%u, errno = %d", serverAddress, serverPort, errno);
::close(fd);
return WTF::nullopt;
}
return fd;
}
Optional<PlatformSocketType> listen(const char* addressStr, uint16_t port)
{
struct sockaddr_in address = { };
int fdListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fdListen < 0) {
LOG_ERROR("socket() failed, errno = %d", errno);
return WTF::nullopt;
}
const int enabled = 1;
int error = setsockopt(fdListen, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled));
if (error < 0) {
LOG_ERROR("setsockopt() SO_REUSEADDR, errno = %d", errno);
return WTF::nullopt;
}
error = setsockopt(fdListen, SOL_SOCKET, SO_REUSEPORT, &enabled, sizeof(enabled));
if (error < 0) {
LOG_ERROR("setsockopt() SO_REUSEPORT, errno = %d", errno);
return WTF::nullopt;
}
// FIXME: Support AF_INET6 connections.
address.sin_family = AF_INET;
if (addressStr && *addressStr)
inet_aton(addressStr, &address.sin_addr);
else
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(port);
error = ::bind(fdListen, (struct sockaddr*)&address, sizeof(address));
if (error < 0) {
LOG_ERROR("bind() failed, errno = %d", errno);
::close(fdListen);
return WTF::nullopt;
}
error = ::listen(fdListen, 1);
if (error < 0) {
LOG_ERROR("listen() failed, errno = %d", errno);
::close(fdListen);
return WTF::nullopt;
}
return fdListen;
}
Optional<PlatformSocketType> accept(PlatformSocketType socket)
{
struct sockaddr_in address = { };
socklen_t len = sizeof(struct sockaddr_in);
int fd = ::accept(socket, (struct sockaddr*) &address, &len);
if (fd >= 0)
return fd;
LOG_ERROR("accept(inet) error (errno = %d)", errno);
return WTF::nullopt;
}
Optional<std::array<PlatformSocketType, 2>> createPair()
{
std::array<PlatformSocketType, 2> sockets;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, &sockets[0]))
return WTF::nullopt;
return sockets;
}
void setup(PlatformSocketType socket)
{
setCloseOnExec(socket);
setNonBlock(socket);
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &BufferSize, sizeof(BufferSize));
setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &BufferSize, sizeof(BufferSize));
}
bool isValid(PlatformSocketType socket)
{
return socket != INVALID_SOCKET_VALUE;
}
bool isListening(PlatformSocketType socket)
{
int out;
socklen_t outSize = sizeof(out);
if (getsockopt(socket, SOL_SOCKET, SO_ACCEPTCONN, &out, &outSize) != -1)
return out;
LOG_ERROR("getsockopt errno = %d", errno);
return false;
}
uint16_t getPort(PlatformSocketType socket)
{
ASSERT(isValid(socket));
struct sockaddr_in address = { };
socklen_t len = sizeof(address);
getsockname(socket, reinterpret_cast<struct sockaddr*>(&address), &len);
return address.sin_port;
}
Optional<size_t> read(PlatformSocketType socket, void* buffer, int bufferSize)
{
ASSERT(isValid(socket));
ssize_t readSize = ::read(socket, buffer, bufferSize);
if (readSize >= 0)
return static_cast<size_t>(readSize);
LOG_ERROR("read error (errno = %d)", errno);
return WTF::nullopt;
}
Optional<size_t> write(PlatformSocketType socket, const void* data, int size)
{
ASSERT(isValid(socket));
ssize_t writeSize = ::write(socket, data, size);
if (writeSize >= 0)
return static_cast<size_t>(writeSize);
LOG_ERROR("write error (errno = %d)", errno);
return WTF::nullopt;
}
void close(PlatformSocketType& socket)
{
if (!isValid(socket))
return;
::close(socket);
socket = INVALID_SOCKET_VALUE;
}
PollingDescriptor preparePolling(PlatformSocketType socket)
{
PollingDescriptor poll;
poll.fd = socket;
poll.events = POLLIN;
return poll;
}
bool poll(Vector<PollingDescriptor>& pollDescriptors, int timeout)
{
int ret = ::poll(pollDescriptors.data(), pollDescriptors.size(), timeout);
return ret > 0;
}
bool isReadable(const PollingDescriptor& poll)
{
return poll.revents & POLLIN;
}
bool isWritable(const PollingDescriptor& poll)
{
return poll.revents & POLLOUT;
}
void markWaitingWritable(PollingDescriptor& poll)
{
poll.events |= POLLOUT;
}
void clearWaitingWritable(PollingDescriptor& poll)
{
poll.events &= ~POLLOUT;
}
} // namespace Socket
} // namespace Inspector
#endif // ENABLE(REMOTE_INSPECTOR)