blob: f29faddf9cc0acc51fc77b19a47e12a4afc8d3b2 [file] [log] [blame]
/*
* Copyright (C) 2011 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.
*/
/* This file implements the 'unix:' goldfish pipe type which allows
* guest clients to directly connect to a Unix domain port through
* /dev/qemu_pipe.
*
* The list of allowed
*/
#include "android/emulation/android_pipe_unix.h"
// TECHNICAL
#ifndef _WIN32
#include "android/async-utils.h"
#include "android/base/memory/LazyInstance.h"
#include "android/emulation/android_pipe_host.h"
#include "android/utils/eintr_wrapper.h"
#include "android/utils/looper.h"
#include "android/utils/sockets.h"
#include "android/utils/system.h"
#include <string>
#include <vector>
// Sockets includes
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
/* Implement the net pipes */
/* Set to 1 or 2 for debug traces */
#define DEBUG 0
#if DEBUG >= 1
#define D(...) printf(__VA_ARGS__), printf("\n")
#else
#define D(...) ((void)0)
#endif
#if DEBUG >= 2
#define DD(...) printf(__VA_ARGS__), printf("\n")
#else
#define DD(...) ((void)0)
#endif
struct GlobalState {
std::vector<std::string> allowedPaths;
};
static android::base::LazyInstance<GlobalState> sGlobal = LAZY_INSTANCE_INIT;
static bool android_unix_pipe_check_path(const char* path) {
if (path) {
D("%s: Checking for [%s]", __FUNCTION__, path);
GlobalState* global = sGlobal.ptr();
for (const auto& it : global->allowedPaths) {
if (it == path) {
D(" OK\n");
return true;
}
}
D(" UNKNOWN\N");
}
return false;
}
enum State {
STATE_INIT,
STATE_CONNECTING,
STATE_CONNECTED,
STATE_CLOSING_GUEST,
STATE_CLOSING_SOCKET
};
struct SocketPipe {
void* hwpipe = nullptr;
State state = STATE_INIT;
int wakeWanted = 0;
LoopIo* io = nullptr;
AsyncConnector connector[1] = {};
};
static void socketPipe_free(SocketPipe* pipe) {
int fd;
/* Close the socket */
if (pipe->io) {
fd = loopIo_fd(pipe->io);
loopIo_free(pipe->io);
socket_close(fd);
}
/* Release the pipe object */
delete pipe;
}
static void socketPipe_resetState(SocketPipe* pipe) {
if ((pipe->wakeWanted & PIPE_WAKE_WRITE) != 0) {
loopIo_wantWrite(pipe->io);
} else {
loopIo_dontWantWrite(pipe->io);
}
if (pipe->state == STATE_CONNECTED &&
(pipe->wakeWanted & PIPE_WAKE_READ) != 0) {
loopIo_wantRead(pipe->io);
} else {
loopIo_dontWantRead(pipe->io);
}
}
/* This function is only called when the socket is disconnected.
* See socketPipe_closeFromGuest() for the case when the guest requires
* the disconnection. */
static void socketPipe_closeFromSocket(void* opaque) {
auto pipe = static_cast<SocketPipe*>(opaque);
D("%s", __FUNCTION__);
/* If the guest already ordered the pipe to be closed, delete immediately */
if (pipe->state == STATE_CLOSING_GUEST) {
socketPipe_free(pipe);
return;
}
/* Force the closure of the QEMUD channel - if a guest is blocked
* waiting for a wake signal, it will receive an error. */
if (pipe->hwpipe != NULL) {
android_pipe_host_close(pipe->hwpipe);
pipe->hwpipe = NULL;
}
pipe->state = STATE_CLOSING_SOCKET;
socketPipe_resetState(pipe);
}
/* This is the function that gets called each time there is an asynchronous
* event on the network pipe.
*/
static void socketPipe_io_func(void* opaque, int fd, unsigned events) {
auto pipe = static_cast<SocketPipe*>(opaque);
int wakeFlags = 0;
/* Run the connector if we are in the CONNECTING state */
/* TODO: Add some sort of time-out, to deal with the case */
/* when the server is wedged. */
if (pipe->state == STATE_CONNECTING) {
AsyncStatus status = asyncConnector_run(pipe->connector);
if (status == ASYNC_NEED_MORE) {
return;
} else if (status == ASYNC_ERROR) {
/* Could not connect, tell our client by closing the channel. */
socketPipe_closeFromSocket(pipe);
return;
}
pipe->state = STATE_CONNECTED;
socketPipe_resetState(pipe);
return;
}
/* Otherwise, accept incoming data */
if ((events & LOOP_IO_READ) != 0) {
if ((pipe->wakeWanted & PIPE_WAKE_READ) != 0) {
wakeFlags |= PIPE_WAKE_READ;
}
}
if ((events & LOOP_IO_WRITE) != 0) {
if ((pipe->wakeWanted & PIPE_WAKE_WRITE) != 0) {
wakeFlags |= PIPE_WAKE_WRITE;
}
}
/* Send wake signal to the guest if needed */
if (wakeFlags != 0) {
android_pipe_host_signal_wake(pipe->hwpipe, wakeFlags);
pipe->wakeWanted &= ~wakeFlags;
}
/* Reset state */
socketPipe_resetState(pipe);
}
static void* socketPipe_initFromAddress(void* hwpipe,
const SockAddress* address,
Looper* looper) {
SocketPipe* pipe = new SocketPipe();
*pipe = {};
pipe->hwpipe = hwpipe;
pipe->state = STATE_INIT;
{
AsyncStatus status;
int fd = socket_create(sock_address_get_family(address), SOCKET_STREAM);
if (fd < 0) {
D("%s: Could create socket from address family!", __FUNCTION__);
socketPipe_free(pipe);
return NULL;
}
pipe->io = loopIo_new(looper, fd, socketPipe_io_func, pipe);
status = asyncConnector_init(pipe->connector, address, pipe->io);
pipe->state = STATE_CONNECTING;
if (status == ASYNC_ERROR) {
D("%s: Could not connect to socket: %s", __FUNCTION__, errno_str);
socketPipe_free(pipe);
return NULL;
}
if (status == ASYNC_COMPLETE) {
pipe->state = STATE_CONNECTED;
socketPipe_resetState(pipe);
}
}
return pipe;
}
/* Called when the guest wants to close the channel. This is different
* from socketPipe_closeFromSocket() which is called when the socket is
* disconnected. */
static void socketPipe_closeFromGuest(void* opaque) {
auto pipe = static_cast<SocketPipe*>(opaque);
socketPipe_free(pipe);
}
static int netPipeReadySend(SocketPipe* pipe) {
if (pipe->state == STATE_CONNECTED)
return 0;
else if (pipe->state == STATE_CONNECTING)
return PIPE_ERROR_AGAIN;
else if (pipe->hwpipe == NULL)
return PIPE_ERROR_INVAL;
else
return PIPE_ERROR_IO;
}
#ifdef _WIN32
int qemu_windows_send(int fd, const void* _buf, int len1) {
int ret, len;
auto buf = (const char*)_buf;
len = len1;
while (len > 0) {
ret = send(fd, buf, len, 0);
if (ret < 0) {
errno = WSAGetLastError();
if (errno != WSAEWOULDBLOCK) {
return -1;
}
} else if (ret == 0) {
break;
} else {
buf += ret;
len -= ret;
break;
}
}
return len1 - len;
}
int qemu_windows_recv(int fd, void* _buf, int len1, bool single_read) {
int ret, len;
char* buf = (char*)_buf;
len = len1;
while (len > 0) {
ret = recv(fd, buf, len, 0);
if (ret < 0) {
errno = WSAGetLastError();
if (errno != WSAEWOULDBLOCK) {
return -1;
}
continue;
} else {
if (single_read) {
return ret;
}
buf += ret;
len -= ret;
break;
}
}
return len1 - len;
}
#endif // _WIN32
static int socketPipe_sendBuffers(void* opaque,
const AndroidPipeBuffer* buffers,
int numBuffers) {
auto pipe = static_cast<SocketPipe*>(opaque);
int count = 0;
int ret = 0;
size_t buffStart = 0;
const AndroidPipeBuffer* buff = buffers;
const AndroidPipeBuffer* buffEnd = buff + numBuffers;
ret = netPipeReadySend(pipe);
if (ret != 0)
return ret;
for (; buff < buffEnd; buff++)
count += buff->size;
buff = buffers;
while (count > 0) {
int avail = buff->size - buffStart;
// NOTE:
// Please take care to send data in a way that does not cause
// pipe corruption.
//
// For instance:
// One may want to call send() multiple times here, but the important
// thing to notice is, what happens when multiple send()'s are issued,
// especially when the last send() results in an error (e.g., EAGAIN)?
//
// If the last send() results in EAGAIN, we need to ensure that no
// data was sent. If we end up sending data successfully through
// send and then get EAGAIN on the last send() call, the pipe driver
// will believe there has really not been any data sent,
// which in turn will cause retransmission of actually-sent data,
// corrupting the pipe.
//
// Otherwise, we need to retry when getting EAGAIN,
// until the transfer completely goes through.
// Only the following two situations are correct:
//
// a) transfer completely or partially succeeds,
// returning # bytes written
// b) nothing is transferred + error code
//
// We currently employ two solutions depending on platform:
// 1. Spin on EAGAIN, with multiple send() calls.
// 2. Only allow one possible send() success, which makes it easier
// to deal with EAGAIN.
//
// We cannot use #1 on POSIX hosts at least, because if we keep
// retrying on EAGAIN, it's possible to lock up the emulator.
// This is because currently, there is a global lock
// for all render threads.
// If the wrong thread is waiting for the lock at the same time
// we are retrying on the EAGAIN signal, no progress will be made.
// So we just use #2: HANDLE_EINTR(send(...)), allowing only
// one successful send() and returning EAGAIN without the possibility
// of previous successful sends.
//
// Curiously, on Windows hosts, solution #2 will cause the emulator
// to not be able to boot up, with repeated surfaceflinger failures.
// On Windows hosts, solution #1 (spin on EAGAIN) must be used.
#ifndef _WIN32
// Solution #2: Allow only one successful send()
int len = HANDLE_EINTR(send(loopIo_fd(pipe->io),
buff->data + buffStart,
avail,
0));
#else
// Solution #1: Spin on EAGAIN (WSAEWOULDBLOCK)
int len = qemu_windows_send(loopIo_fd(pipe->io),
buff->data + buffStart,
avail);
#endif
/* the write succeeded */
if (len > 0) {
buffStart += len;
if (buffStart >= buff->size) {
buff++;
buffStart = 0;
}
count -= len;
ret += len;
continue;
}
/* we reached the end of stream? */
if (len == 0) {
if (ret == 0)
ret = PIPE_ERROR_IO;
break;
}
/* if we already wrote some stuff, simply return */
if (ret > 0) {
break;
}
/* need to return an appropriate error code */
if (errno == EAGAIN || errno == EWOULDBLOCK) {
ret = PIPE_ERROR_AGAIN;
} else {
ret = PIPE_ERROR_IO;
}
break;
}
return ret;
}
static int socketPipe_recvBuffers(void* opaque,
AndroidPipeBuffer* buffers,
int numBuffers) {
auto pipe = static_cast<SocketPipe*>(opaque);
int count = 0;
int ret = 0;
size_t buffStart = 0;
AndroidPipeBuffer* buff = buffers;
AndroidPipeBuffer* buffEnd = buff + numBuffers;
for (; buff < buffEnd; buff++)
count += buff->size;
buff = buffers;
while (count > 0) {
int avail = buff->size - buffStart;
// See comment in socketPipe_sendBuffers.
// Although we have not observed it yet,
// pipe corruption can potentially happen here too.
// We use the same solutions to be safe.
#ifndef _WIN32
int len = HANDLE_EINTR(recv(loopIo_fd(pipe->io),
buff->data + buffStart,
avail,
0));
#else
int len = qemu_windows_recv(loopIo_fd(pipe->io),
buff->data + buffStart,
avail,
true);
#endif
/* the read succeeded */
if (len > 0) {
buffStart += len;
if (buffStart >= buff->size) {
buff++;
buffStart = 0;
}
count -= len;
ret += len;
continue;
}
/* we reached the end of stream? */
if (len == 0) {
if (ret == 0)
ret = PIPE_ERROR_IO;
break;
}
/* if we already read some stuff, simply return */
if (ret > 0) {
break;
}
/* need to return an appropriate error code */
if (errno == EAGAIN || errno == EWOULDBLOCK) {
ret = PIPE_ERROR_AGAIN;
} else {
ret = PIPE_ERROR_IO;
}
break;
}
return ret;
}
static unsigned socketPipe_poll(void* opaque) {
auto pipe = static_cast<SocketPipe*>(opaque);
unsigned mask = loopIo_poll(pipe->io);
unsigned ret = 0;
if (mask & LOOP_IO_READ)
ret |= PIPE_POLL_IN;
if (mask & LOOP_IO_WRITE)
ret |= PIPE_POLL_OUT;
return ret;
}
static void socketPipe_wakeOn(void* opaque, int flags) {
auto pipe = static_cast<SocketPipe*>(opaque);
DD("%s: flags=%d", __FUNCTION__, flags);
pipe->wakeWanted |= flags;
socketPipe_resetState(pipe);
}
void* socketPipe_initUnix(void* hwpipe, void* _looper, const char* args) {
/* Build SockAddress from arguments. Acceptable formats are:
*
* <path>
*/
if (args == NULL || args[0] == '\0') {
D("%s: Missing address!", __FUNCTION__);
return NULL;
}
D("%s: Address is '%s'", __FUNCTION__, args);
if (!android_unix_pipe_check_path(args)) {
D("%s: Rejecting connection to unknown path '%s'", __FUNCTION__, args);
return NULL;
}
SockAddress address;
sock_address_init_unix(&address, args);
void* ret = socketPipe_initFromAddress(hwpipe, &address,
static_cast<Looper*>(_looper));
sock_address_done(&address);
return ret;
}
static const AndroidPipeFuncs s_unix_pipe_funcs = {
socketPipe_initUnix,
socketPipe_closeFromGuest,
socketPipe_sendBuffers,
socketPipe_recvBuffers,
socketPipe_poll,
socketPipe_wakeOn,
NULL, /* we can't save these */
NULL, /* we can't load these */
};
void android_unix_pipes_init(void) {
Looper* looper = looper_getForThread();
android_pipe_add_type("unix", looper, &s_unix_pipe_funcs);
}
void android_unix_pipes_add_allowed_path(const char* path) {
if (path && path[0]) {
D("%s: Adding [%s]", __FUNCTION__, path);
GlobalState* global = sGlobal.ptr();
global->allowedPaths.emplace_back(std::string(path));
}
}
#else // _WIN32
void android_unix_pipes_init(void) {
// nothing to do here.
}
void android_unix_pipes_add_allowed_path(const char* path) {
// nothing to do here.
}
#endif // _WIN32