mirror of
https://github.com/clearlinux/graphene.git
synced 2026-09-06 22:01:29 +00:00
[Pal/{Linux,Linux-SGX}] Refactor db_pipes.c code
Cleanup of the pipes' implementation in both PALs, including better comments and small fixups (proper `pipe_delete()`, proper error handling, proper nonblocking option).
This commit is contained in:
committed by
Michał Kowalczyk
parent
58c53ad747
commit
350b498fb0
@@ -21,8 +21,6 @@
|
||||
* "pipe:" or "pipe.srv:".
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "pal.h"
|
||||
#include "pal_debug.h"
|
||||
@@ -33,53 +31,87 @@
|
||||
#include "pal_linux_defs.h"
|
||||
#include "pal_linux_error.h"
|
||||
#include "pal_security.h"
|
||||
|
||||
typedef __kernel_pid_t pid_t;
|
||||
#include <asm/fcntl.h>
|
||||
#include <asm/poll.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/un.h>
|
||||
|
||||
static int pipe_path(int pipeid, char* path, int len) {
|
||||
/* use abstrace UNIX sockets for pipes */
|
||||
memset(path, 0, len);
|
||||
return snprintf(path + 1, len - 1, "%s%08x", pal_sec.pipe_prefix, pipeid);
|
||||
}
|
||||
|
||||
static int pipe_addr(int pipeid, struct sockaddr_un* addr) {
|
||||
/* use abstract UNIX sockets for pipes, with name format "@/graphene/12345678" */
|
||||
addr->sun_family = AF_UNIX;
|
||||
return pipe_path(pipeid, (char*)addr->sun_path, sizeof(addr->sun_path));
|
||||
}
|
||||
memset(addr->sun_path, 0, sizeof(addr->sun_path));
|
||||
|
||||
static inline int pipe_type(int options) {
|
||||
int type = SOCK_STREAM;
|
||||
if (options & PAL_OPTION_NONBLOCK)
|
||||
type |= SOCK_NONBLOCK;
|
||||
return type;
|
||||
/* for abstract sockets, first char is NUL */
|
||||
char* str = (char*)addr->sun_path + 1;
|
||||
size_t size = sizeof(addr->sun_path) - 1;
|
||||
|
||||
/* pipe_prefix already contains a slash at the end, so not needed in the format string */
|
||||
int ret = snprintf(str, size, "%s%08x", pal_sec.pipe_prefix, pipeid);
|
||||
return ret >= 0 && (size_t)ret < size ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Create a listening abstract UNIX socket as preparation for connecting two ends of a pipe.
|
||||
*
|
||||
* An abstract UNIX socket with name "@/graphene/<pipeid>" is opened for listening. A corresponding
|
||||
* PAL handle with type `pipesrv` is created. This PAL handle typically serves only as an
|
||||
* intermediate step to connect two ends of the pipe (`pipecli` and `pipe`). As soon as the other
|
||||
* end of the pipe connects to this listening socket, a new accepted socket and the corresponding
|
||||
* PAL handle are created, and this `pipesrv` handle can be closed.
|
||||
*
|
||||
* \param[out] handle PAL handle of type `pipesrv` with abstract UNIX socket opened for listening.
|
||||
* \param[in] pipeid Integer uniquely identifying the pipe.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_listen(PAL_HANDLE* handle, PAL_NUM pipeid, int options) {
|
||||
struct sockaddr_un addr;
|
||||
int ret;
|
||||
|
||||
if ((ret = pipe_addr(pipeid, &addr)) < 0)
|
||||
return ret;
|
||||
struct sockaddr_un addr;
|
||||
ret = pipe_addr(pipeid, &addr);
|
||||
if (IS_ERR(ret))
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
unsigned int addrlen = sizeof(struct sockaddr_un);
|
||||
struct sockopt sock_options;
|
||||
ret = ocall_listen(AF_UNIX, pipe_type(options), 0, /*ipv6_v6only=*/0,
|
||||
unsigned int addrlen = sizeof(struct sockaddr_un);
|
||||
int nonblock = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0;
|
||||
|
||||
ret = ocall_listen(AF_UNIX, SOCK_STREAM | nonblock, 0, /*ipv6_v6only=*/0,
|
||||
(struct sockaddr*)&addr, &addrlen, &sock_options);
|
||||
if (IS_ERR(ret))
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe));
|
||||
if (!hdl) {
|
||||
ocall_close(ret);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(hdl, pipesrv);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0);
|
||||
hdl->pipe.fd = ret;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = options & PAL_OPTION_NONBLOCK ? PAL_TRUE : PAL_FALSE;
|
||||
*handle = hdl;
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0); /* cannot write to a listening socket */
|
||||
hdl->pipe.fd = ret;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = options & PAL_OPTION_NONBLOCK ? PAL_TRUE : PAL_FALSE;
|
||||
|
||||
*handle = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Accept the other end of the pipe and create PAL handle for our end of the pipe.
|
||||
*
|
||||
* Caller creates a `pipesrv` PAL handle with the underlying abstract UNIX socket opened for
|
||||
* listening, and then calls this function to wait for the other end of the pipe to connect.
|
||||
* When the connection request arrives, a new `pipecli` PAL handle is created with the
|
||||
* corresponding underlying socket and is returned in `client`. This `pipecli` PAL handle denotes
|
||||
* our end of the pipe. Typically, `pipesrv` handle is not needed after this and can be closed.
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipesrv` with abstract UNIX socket opened for listening.
|
||||
* \param[out] client PAL handle of type `pipecli` connected to the other end of the pipe (`pipe`).
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_waitforclient(PAL_HANDLE handle, PAL_HANDLE* client) {
|
||||
if (!IS_HANDLE_TYPE(handle, pipesrv))
|
||||
return -PAL_ERROR_NOTSERVER;
|
||||
@@ -93,64 +125,131 @@ static int pipe_waitforclient(PAL_HANDLE handle, PAL_HANDLE* client) {
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
|
||||
PAL_HANDLE clnt = malloc(HANDLE_SIZE(pipe));
|
||||
if (!clnt) {
|
||||
ocall_close(ret);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(clnt, pipecli);
|
||||
HANDLE_HDR(clnt)->flags |= RFD(0) | WFD(0);
|
||||
clnt->pipe.fd = ret;
|
||||
clnt->pipe.nonblocking = PAL_FALSE;
|
||||
clnt->pipe.pipeid = handle->pipe.pipeid;
|
||||
*client = clnt;
|
||||
clnt->pipe.fd = ret;
|
||||
clnt->pipe.nonblocking = PAL_FALSE; /* FIXME: must set nonblocking based on `handle` value */
|
||||
clnt->pipe.pipeid = handle->pipe.pipeid;
|
||||
|
||||
*client = clnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Connect to the other end of the pipe and create PAL handle for our end of the pipe.
|
||||
*
|
||||
* This function connects to the other end of the pipe, represented as an abstract UNIX socket
|
||||
* "@/graphene/<pipeid>" opened for listening. When the connection succeeds, a new `pipe` PAL handle
|
||||
* is created with the corresponding underlying socket and is returned in `handle`. The other end of
|
||||
* the pipe is typically of type `pipecli`.
|
||||
*
|
||||
* \param[out] handle PAL handle of type `pipe` with abstract UNIX socket connected to another end.
|
||||
* \param[in] pipeid Integer uniquely identifying the pipe.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_connect(PAL_HANDLE* handle, PAL_NUM pipeid, int options) {
|
||||
struct sockaddr_un addr;
|
||||
int ret;
|
||||
|
||||
if ((ret = pipe_addr(pipeid, &addr)) < 0)
|
||||
return ret;
|
||||
struct sockaddr_un addr;
|
||||
ret = pipe_addr(pipeid, &addr);
|
||||
if (IS_ERR(ret))
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
struct sockopt sock_options;
|
||||
ret = ocall_connect(AF_UNIX, pipe_type(options), 0, /*ipv6_v6only=*/0, (void*)&addr,
|
||||
sizeof(struct sockaddr_un), NULL, NULL, &sock_options);
|
||||
unsigned int addrlen = sizeof(struct sockaddr_un);
|
||||
int nonblock = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0;
|
||||
|
||||
ret = ocall_connect(AF_UNIX, SOCK_STREAM | nonblock, 0, /*ipv6_v6only=*/0,
|
||||
(const struct sockaddr*)&addr,
|
||||
addrlen, NULL, NULL, &sock_options);
|
||||
if (IS_ERR(ret))
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe));
|
||||
if (!hdl) {
|
||||
ocall_close(ret);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(hdl, pipe);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(0);
|
||||
hdl->pipe.fd = ret;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
*handle = hdl;
|
||||
hdl->pipe.fd = ret;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
|
||||
*handle = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Create PAL handle with read and write ends of a pipe.
|
||||
*
|
||||
* This function creates a PAL handle of type `pipeprv` (anonymous pipe). In contrast to other types
|
||||
* of pipes, `pipeprv` encapsulates both ends of the pipe, backed by a host-level socketpair. This
|
||||
* type of pipe is typically reserved for internal PAL uses, not for LibOS emulation.
|
||||
*
|
||||
* \param[out] handle PAL handle of type `pipeprv` backed by a host-level socketpair.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_private(PAL_HANDLE* handle, int options) {
|
||||
int ret, fds[2];
|
||||
int type = SOCK_STREAM;
|
||||
if (options & PAL_OPTION_NONBLOCK)
|
||||
type |= SOCK_NONBLOCK;
|
||||
int fds[2];
|
||||
|
||||
ret = ocall_socketpair(AF_UNIX, type, 0, fds);
|
||||
int nonblock = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0;
|
||||
|
||||
int ret = ocall_socketpair(AF_UNIX, SOCK_STREAM | nonblock, 0, fds);
|
||||
if (IS_ERR(ret))
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipeprv));
|
||||
if (!hdl) {
|
||||
ocall_close(fds[0]);
|
||||
ocall_close(fds[1]);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(hdl, pipeprv);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(1);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(1); /* first FD for reads, second FD for writes */
|
||||
hdl->pipeprv.fds[0] = fds[0];
|
||||
hdl->pipeprv.fds[1] = fds[1];
|
||||
hdl->pipeprv.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
*handle = hdl;
|
||||
|
||||
*handle = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 'open' operation of pipe stream. For each pipe stream, it is
|
||||
identified by a decimal number in URI. There could be two
|
||||
types: pipe and pipe.srv. They behave pretty much the same,
|
||||
except they are two ends of the pipe. */
|
||||
/*!
|
||||
* \brief Create PAL handle of type `pipeprv`, `pipesrv`, or `pipe` depending on `type` and `uri`.
|
||||
*
|
||||
* Depending on the combination of `type` and `uri`, the following PAL handles are created:
|
||||
*
|
||||
* - `type` is URI_TYPE_PIPE and `url` is empty: create `pipeprv` handle (with two connected
|
||||
* ends of an anonymous pipe).
|
||||
*
|
||||
* - `type` is URI_TYPE_PIPE_SRV: create `pipesrv` handle (intermediate listening socket) with
|
||||
* name in the form of "@/graphene/<pipeid>" where pipeid is
|
||||
* derived from `uri` via strtol(). Caller is expected to call
|
||||
* pipe_waitforclient() afterwards.
|
||||
*
|
||||
* - `type` is URI_TYPE_PIPE: create `pipe` handle (connecting socket) with name in the form of
|
||||
* "@/graphene/<pipeid>" where pipeid is derived from `uri` via
|
||||
* strtol().
|
||||
*
|
||||
* \param[out] handle Created PAL handle of type `pipeprv`, `pipesrv`, or `pipe`.
|
||||
* \param[in] type Can be URI_TYPE_PIPE or URI_TYPE_PIPE_SRV.
|
||||
* \param[in] uri Content is either NUL (for anonymous pipe) or an integer denoting pipeid.
|
||||
* \param[in] access Not used.
|
||||
* \param[in] share Not used.
|
||||
* \param[in] create Not used.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share,
|
||||
int create, int options) {
|
||||
if (!WITHIN_MASK(access, PAL_ACCESS_MASK) || !WITHIN_MASK(share, PAL_SHARE_MASK) ||
|
||||
@@ -175,7 +274,15 @@ static int pipe_open(PAL_HANDLE* handle, const char* type, const char* uri, int
|
||||
return -PAL_ERROR_INVAL;
|
||||
}
|
||||
|
||||
/* 'read' operation of pipe stream. offset does not apply here. */
|
||||
/*!
|
||||
* \brief Read from pipe (from read end in case of `pipeprv`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipecli`, or `pipe`.
|
||||
* \param[in] offset Not used.
|
||||
* \param[in] len Size of user-supplied buffer.
|
||||
* \param[out] buffer User-supplied buffer to read data to.
|
||||
* \return Number of bytes read on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int64_t pipe_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void* buffer) {
|
||||
if (offset)
|
||||
return -PAL_ERROR_INVAL;
|
||||
@@ -184,12 +291,9 @@ static int64_t pipe_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void*
|
||||
!IS_HANDLE_TYPE(handle, pipe))
|
||||
return -PAL_ERROR_NOTCONNECTION;
|
||||
|
||||
if (len != (uint32_t)len)
|
||||
return -PAL_ERROR_INVAL;
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[0] : handle->pipe.fd;
|
||||
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[0] : handle->pipe.fd;
|
||||
ssize_t bytes = ocall_recv(fd, buffer, len, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (IS_ERR(bytes))
|
||||
return unix_to_pal_error(ERRNO(bytes));
|
||||
|
||||
@@ -199,7 +303,15 @@ static int64_t pipe_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void*
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* 'write' operation of pipe stream. offset does not apply here. */
|
||||
/*!
|
||||
* \brief Write to pipe (to write end in case of `pipeprv`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipecli`, or `pipe`.
|
||||
* \param[in] offset Not used.
|
||||
* \param[in] len Size of user-supplied buffer.
|
||||
* \param[in] buffer User-supplied buffer to write data from.
|
||||
* \return Number of bytes written on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int64_t pipe_write(PAL_HANDLE handle, uint64_t offset, uint64_t len, const void* buffer) {
|
||||
if (offset)
|
||||
return -PAL_ERROR_INVAL;
|
||||
@@ -208,9 +320,6 @@ static int64_t pipe_write(PAL_HANDLE handle, uint64_t offset, uint64_t len, cons
|
||||
!IS_HANDLE_TYPE(handle, pipe))
|
||||
return -PAL_ERROR_NOTCONNECTION;
|
||||
|
||||
if (len != (uint32_t)len)
|
||||
return -PAL_ERROR_INVAL;
|
||||
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[1] : handle->pipe.fd;
|
||||
|
||||
ssize_t bytes = ocall_send(fd, buffer, len, NULL, 0, NULL, 0);
|
||||
@@ -220,7 +329,12 @@ static int64_t pipe_write(PAL_HANDLE handle, uint64_t offset, uint64_t len, cons
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* 'close' operation of pipe stream. */
|
||||
/*!
|
||||
* \brief Close pipe (both ends in case of `pipeprv`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_close(PAL_HANDLE handle) {
|
||||
if (IS_HANDLE_TYPE(handle, pipeprv)) {
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON) {
|
||||
@@ -231,10 +345,7 @@ static int pipe_close(PAL_HANDLE handle) {
|
||||
ocall_close(handle->pipeprv.fds[1]);
|
||||
handle->pipeprv.fds[1] = PAL_IDX_POISON;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handle->pipe.fd != PAL_IDX_POISON) {
|
||||
} else if (handle->pipe.fd != PAL_IDX_POISON) {
|
||||
ocall_close(handle->pipe.fd);
|
||||
handle->pipe.fd = PAL_IDX_POISON;
|
||||
}
|
||||
@@ -242,40 +353,14 @@ static int pipe_close(PAL_HANDLE handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 'delete' operation of pipe stream. */
|
||||
/*!
|
||||
* \brief Shut down pipe (one or both ends in case of `pipeprv` depending on `access`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[in] access May be 0, PAL_DELETE_RD, PAL_DELETE_WR.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_delete(PAL_HANDLE handle, int access) {
|
||||
if (IS_HANDLE_TYPE(handle, pipeprv)) {
|
||||
switch (access) {
|
||||
case 0:
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON) {
|
||||
ocall_close(handle->pipeprv.fds[0]);
|
||||
handle->pipeprv.fds[0] = PAL_IDX_POISON;
|
||||
}
|
||||
if (handle->pipeprv.fds[1] != PAL_IDX_POISON) {
|
||||
ocall_close(handle->pipeprv.fds[1]);
|
||||
handle->pipeprv.fds[1] = PAL_IDX_POISON;
|
||||
}
|
||||
break;
|
||||
case PAL_DELETE_RD:
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON) {
|
||||
ocall_close(handle->pipeprv.fds[0]);
|
||||
handle->pipeprv.fds[0] = PAL_IDX_POISON;
|
||||
}
|
||||
break;
|
||||
case PAL_DELETE_WR:
|
||||
if (handle->pipeprv.fds[1] != PAL_IDX_POISON) {
|
||||
ocall_close(handle->pipeprv.fds[1]);
|
||||
handle->pipeprv.fds[1] = PAL_IDX_POISON;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -PAL_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->pipe.fd == PAL_IDX_POISON)
|
||||
return 0;
|
||||
|
||||
int shutdown;
|
||||
switch (access) {
|
||||
case 0:
|
||||
@@ -291,10 +376,34 @@ static int pipe_delete(PAL_HANDLE handle, int access) {
|
||||
return -PAL_ERROR_INVAL;
|
||||
}
|
||||
|
||||
ocall_shutdown(handle->pipe.fd, shutdown);
|
||||
if (IS_HANDLE_TYPE(handle, pipeprv)) {
|
||||
/* pipeprv has two underlying FDs, shut down the requested one(s) */
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON &&
|
||||
(shutdown == SHUT_RD || shutdown == SHUT_RDWR)) {
|
||||
ocall_shutdown(handle->pipeprv.fds[0], SHUT_RD);
|
||||
}
|
||||
|
||||
if (handle->pipeprv.fds[1] != PAL_IDX_POISON &&
|
||||
(shutdown == SHUT_WR || shutdown == SHUT_RDWR)) {
|
||||
ocall_shutdown(handle->pipeprv.fds[1], SHUT_WR);
|
||||
}
|
||||
} else {
|
||||
/* other types of pipes have a single underlying FD, shut it down */
|
||||
if (handle->pipe.fd != PAL_IDX_POISON) {
|
||||
ocall_shutdown(handle->pipe.fd, shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Retrieve attributes of PAL handle.
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[out] attr User-supplied buffer to store handle's current attributes.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
int ret;
|
||||
|
||||
@@ -347,6 +456,15 @@ static int pipe_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set attributes of PAL handle.
|
||||
*
|
||||
* Currently only `nonblocking` attribute can be set.
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[in] attr User-supplied buffer with new handle's attributes.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_attrsetbyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
if (handle->generic.fds[0] == PAL_IDX_POISON)
|
||||
return -PAL_ERROR_BADHANDLE;
|
||||
@@ -366,8 +484,18 @@ static int pipe_attrsetbyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Retrieve full URI of PAL handle.
|
||||
*
|
||||
* Full URI is composed of the type and pipeid: "<type>:<pipeid>".
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[out] buffer User-supplied buffer to write URI to.
|
||||
* \param[in] count Size of the user-supplied buffer.
|
||||
* \return Number of bytes written on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_getname(PAL_HANDLE handle, char* buffer, size_t count) {
|
||||
int old_count = count;
|
||||
size_t old_count = count;
|
||||
int ret;
|
||||
|
||||
const char* prefix = NULL;
|
||||
|
||||
+275
-164
@@ -21,8 +21,6 @@
|
||||
* "pipe:" or "pipe.srv:".
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "pal.h"
|
||||
#include "pal_debug.h"
|
||||
@@ -32,71 +30,105 @@
|
||||
#include "pal_linux.h"
|
||||
#include "pal_linux_defs.h"
|
||||
#include "pal_security.h"
|
||||
|
||||
typedef __kernel_pid_t pid_t;
|
||||
#include <asm/errno.h>
|
||||
#include <asm/fcntl.h>
|
||||
#include <asm/poll.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/un.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
static int pipe_path(int pipeid, char* path, int len) {
|
||||
/* use abstract UNIX sockets for pipes */
|
||||
memset(path, 0, len);
|
||||
|
||||
if (pal_sec.pipe_prefix_id)
|
||||
return snprintf(path + 1, len - 1, GRAPHENE_UNIX_PREFIX_FMT "/%08x", pal_sec.pipe_prefix_id,
|
||||
pipeid);
|
||||
else
|
||||
return snprintf(path + 1, len - 1, "/graphene/%08x", pipeid);
|
||||
}
|
||||
|
||||
static int pipe_addr(int pipeid, struct sockaddr_un* addr) {
|
||||
/* use abstract UNIX sockets for pipes, with name format "@/graphene/12345678" */
|
||||
addr->sun_family = AF_UNIX;
|
||||
return pipe_path(pipeid, (char*)addr->sun_path, sizeof(addr->sun_path));
|
||||
memset(addr->sun_path, 0, sizeof(addr->sun_path));
|
||||
|
||||
/* for abstract sockets, first char is NUL */
|
||||
char* str = (char*)addr->sun_path + 1;
|
||||
size_t size = sizeof(addr->sun_path) - 1;
|
||||
|
||||
/* FIXME: Below naming scheme is slightly different from Linux-SGX, not important though */
|
||||
int ret;
|
||||
if (pal_sec.pipe_prefix_id) {
|
||||
ret = snprintf(str, size, GRAPHENE_UNIX_PREFIX_FMT "/%08x",
|
||||
pal_sec.pipe_prefix_id, pipeid);
|
||||
} else {
|
||||
ret = snprintf(str, size, "/graphene/%08x", pipeid);
|
||||
}
|
||||
return ret >= 0 && (size_t)ret < size ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Create a listening abstract UNIX socket as preparation for connecting two ends of a pipe.
|
||||
*
|
||||
* An abstract UNIX socket with name "@/graphene/<pipeid>" is opened for listening. A corresponding
|
||||
* PAL handle with type `pipesrv` is created. This PAL handle typically serves only as an
|
||||
* intermediate step to connect two ends of the pipe (`pipecli` and `pipe`). As soon as the other
|
||||
* end of the pipe connects to this listening socket, a new accepted socket and the corresponding
|
||||
* PAL handle are created, and this `pipesrv` handle can be closed.
|
||||
*
|
||||
* \param[out] handle PAL handle of type `pipesrv` with abstract UNIX socket opened for listening.
|
||||
* \param[in] pipeid Integer uniquely identifying the pipe.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_listen(PAL_HANDLE* handle, PAL_NUM pipeid, int options) {
|
||||
int ret, fd;
|
||||
|
||||
fd = INLINE_SYSCALL(socket, 3, AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | options, 0);
|
||||
if (IS_ERR(fd))
|
||||
return -PAL_ERROR_DENIED;
|
||||
int ret;
|
||||
|
||||
struct sockaddr_un addr;
|
||||
|
||||
if ((ret = pipe_addr(pipeid, &addr)) < 0)
|
||||
return ret;
|
||||
|
||||
ret = INLINE_SYSCALL(bind, 3, fd, &addr, sizeof(addr.sun_path) - 1);
|
||||
|
||||
if (IS_ERR(ret)) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
|
||||
switch (ERRNO(ret)) {
|
||||
case EINVAL:
|
||||
return -PAL_ERROR_INVAL;
|
||||
case EADDRINUSE:
|
||||
return -PAL_ERROR_STREAMEXIST;
|
||||
default:
|
||||
return -PAL_ERROR_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
ret = INLINE_SYSCALL(listen, 2, fd, 1);
|
||||
ret = pipe_addr(pipeid, &addr);
|
||||
if (IS_ERR(ret))
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
int nonblock = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0;
|
||||
|
||||
int fd = INLINE_SYSCALL(socket, 3, AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | nonblock, 0);
|
||||
if (IS_ERR(fd))
|
||||
return unix_to_pal_error(ERRNO(fd));
|
||||
|
||||
ret = INLINE_SYSCALL(bind, 3, fd, &addr, sizeof(addr.sun_path) - 1);
|
||||
if (IS_ERR(ret)) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
}
|
||||
|
||||
ret = INLINE_SYSCALL(listen, 2, fd, 1);
|
||||
if (IS_ERR(ret)) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
}
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe));
|
||||
if (!hdl) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(hdl, pipesrv);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0);
|
||||
hdl->pipe.fd = fd;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = options & PAL_OPTION_NONBLOCK ? PAL_TRUE : PAL_FALSE;
|
||||
*handle = hdl;
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0); /* cannot write to a listening socket */
|
||||
hdl->pipe.fd = fd;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = options & PAL_OPTION_NONBLOCK ? PAL_TRUE : PAL_FALSE;
|
||||
|
||||
*handle = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Accept the other end of the pipe and create PAL handle for our end of the pipe.
|
||||
*
|
||||
* Caller creates a `pipesrv` PAL handle with the underlying abstract UNIX socket opened for
|
||||
* listening, and then calls this function to wait for the other end of the pipe to connect.
|
||||
* When the connection request arrives, a new `pipecli` PAL handle is created with the
|
||||
* corresponding underlying socket and is returned in `client`. This `pipecli` PAL handle denotes
|
||||
* our end of the pipe. Typically, `pipesrv` handle is not needed after this and can be closed.
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipesrv` with abstract UNIX socket opened for listening.
|
||||
* \param[out] client PAL handle of type `pipecli` connected to the other end of the pipe (`pipe`).
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_waitforclient(PAL_HANDLE handle, PAL_HANDLE* client) {
|
||||
if (!IS_HANDLE_TYPE(handle, pipesrv))
|
||||
return -PAL_ERROR_NOTSERVER;
|
||||
@@ -105,87 +137,137 @@ static int pipe_waitforclient(PAL_HANDLE handle, PAL_HANDLE* client) {
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
int newfd = INLINE_SYSCALL(accept4, 4, handle->pipe.fd, NULL, NULL, O_CLOEXEC);
|
||||
|
||||
if (IS_ERR(newfd))
|
||||
switch (ERRNO(newfd)) {
|
||||
case EWOULDBLOCK:
|
||||
return -PAL_ERROR_TRYAGAIN;
|
||||
case ECONNABORTED:
|
||||
return -PAL_ERROR_CONNFAILED;
|
||||
default:
|
||||
return -PAL_ERROR_DENIED;
|
||||
}
|
||||
return unix_to_pal_error(ERRNO(newfd));
|
||||
|
||||
PAL_HANDLE clnt = malloc(HANDLE_SIZE(pipe));
|
||||
SET_HANDLE_TYPE(clnt, pipecli);
|
||||
HANDLE_HDR(clnt)->flags |= RFD(0) | WFD(0);
|
||||
clnt->pipe.fd = newfd;
|
||||
clnt->pipe.pipeid = handle->pipe.pipeid;
|
||||
clnt->pipe.nonblocking = PAL_FALSE;
|
||||
*client = clnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pipe_connect(PAL_HANDLE* handle, PAL_NUM pipeid, int options) {
|
||||
int ret, fd;
|
||||
|
||||
fd = INLINE_SYSCALL(socket, 3, AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | options, 0);
|
||||
|
||||
if (IS_ERR(fd))
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
struct sockaddr_un addr;
|
||||
|
||||
if ((ret = pipe_addr(pipeid, &addr)) < 0)
|
||||
return ret;
|
||||
|
||||
ret = INLINE_SYSCALL(connect, 3, fd, &addr, sizeof(addr.sun_path) - 1);
|
||||
|
||||
if (IS_ERR(ret)) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
switch (ERRNO(ret)) {
|
||||
case ECONNREFUSED:
|
||||
return -PAL_ERROR_STREAMNOTEXIST;
|
||||
case EINTR:
|
||||
return -PAL_ERROR_TRYAGAIN;
|
||||
default:
|
||||
return -PAL_ERROR_DENIED;
|
||||
}
|
||||
if (!clnt) {
|
||||
INLINE_SYSCALL(close, 1, newfd);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe));
|
||||
SET_HANDLE_TYPE(hdl, pipe);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(0);
|
||||
hdl->pipe.fd = fd;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
*handle = hdl;
|
||||
SET_HANDLE_TYPE(clnt, pipecli);
|
||||
HANDLE_HDR(clnt)->flags |= RFD(0) | WFD(0);
|
||||
clnt->pipe.fd = newfd;
|
||||
clnt->pipe.nonblocking = PAL_FALSE; /* FIXME: must set nonblocking based on `handle` value */
|
||||
clnt->pipe.pipeid = handle->pipe.pipeid;
|
||||
|
||||
*client = clnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pipe_private(PAL_HANDLE* handle, int options) {
|
||||
int ret, fds[2];
|
||||
/*!
|
||||
* \brief Connect to the other end of the pipe and create PAL handle for our end of the pipe.
|
||||
*
|
||||
* This function connects to the other end of the pipe, represented as an abstract UNIX socket
|
||||
* "@/graphene/<pipeid>" opened for listening. When the connection succeeds, a new `pipe` PAL handle
|
||||
* is created with the corresponding underlying socket and is returned in `handle`. The other end of
|
||||
* the pipe is typically of type `pipecli`.
|
||||
*
|
||||
* \param[out] handle PAL handle of type `pipe` with abstract UNIX socket connected to another end.
|
||||
* \param[in] pipeid Integer uniquely identifying the pipe.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_connect(PAL_HANDLE* handle, PAL_NUM pipeid, int options) {
|
||||
int ret;
|
||||
|
||||
ret = INLINE_SYSCALL(socketpair, 4, AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | options, 0, fds);
|
||||
struct sockaddr_un addr;
|
||||
ret = pipe_addr(pipeid, &addr);
|
||||
if (IS_ERR(ret))
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipeprv));
|
||||
SET_HANDLE_TYPE(hdl, pipeprv);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(1);
|
||||
hdl->pipeprv.fds[0] = fds[0];
|
||||
hdl->pipeprv.fds[1] = fds[1];
|
||||
hdl->pipeprv.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
*handle = hdl;
|
||||
int nonblock = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0;
|
||||
|
||||
int fd = INLINE_SYSCALL(socket, 3, AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | nonblock, 0);
|
||||
if (IS_ERR(fd))
|
||||
return -PAL_ERROR_DENIED;
|
||||
|
||||
ret = INLINE_SYSCALL(connect, 3, fd, &addr, sizeof(addr.sun_path) - 1);
|
||||
if (IS_ERR(ret)) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
}
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipe));
|
||||
if (!hdl) {
|
||||
INLINE_SYSCALL(close, 1, fd);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(hdl, pipe);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(0);
|
||||
hdl->pipe.fd = fd;
|
||||
hdl->pipe.pipeid = pipeid;
|
||||
hdl->pipe.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
|
||||
*handle = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 'open' operation of pipe stream. For each pipe stream, it is
|
||||
identified by a decimal number in URI. There could be two
|
||||
types: pipe and pipe.srv. They behave pretty much the same,
|
||||
except they are two ends of the pipe. */
|
||||
/*!
|
||||
* \brief Create PAL handle with read and write ends of a pipe.
|
||||
*
|
||||
* This function creates a PAL handle of type `pipeprv` (anonymous pipe). In contrast to other types
|
||||
* of pipes, `pipeprv` encapsulates both ends of the pipe, backed by a host-level socketpair. This
|
||||
* type of pipe is typically reserved for internal PAL uses, not for LibOS emulation.
|
||||
*
|
||||
* \param[out] handle PAL handle of type `pipeprv` backed by a host-level socketpair.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_private(PAL_HANDLE* handle, int options) {
|
||||
int fds[2];
|
||||
|
||||
int nonblock = options & PAL_OPTION_NONBLOCK ? SOCK_NONBLOCK : 0;
|
||||
|
||||
int ret = INLINE_SYSCALL(socketpair, 4, AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | nonblock, 0, fds);
|
||||
if (IS_ERR(ret))
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
|
||||
PAL_HANDLE hdl = malloc(HANDLE_SIZE(pipeprv));
|
||||
if (!hdl) {
|
||||
INLINE_SYSCALL(close, 1, fds[0]);
|
||||
INLINE_SYSCALL(close, 1, fds[1]);
|
||||
return -PAL_ERROR_NOMEM;
|
||||
}
|
||||
|
||||
SET_HANDLE_TYPE(hdl, pipeprv);
|
||||
HANDLE_HDR(hdl)->flags |= RFD(0) | WFD(1); /* first FD for reads, second FD for writes */
|
||||
hdl->pipeprv.fds[0] = fds[0];
|
||||
hdl->pipeprv.fds[1] = fds[1];
|
||||
hdl->pipeprv.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
||||
|
||||
*handle = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Create PAL handle of type `pipeprv`, `pipesrv`, or `pipe` depending on `type` and `uri`.
|
||||
*
|
||||
* Depending on the combination of `type` and `uri`, the following PAL handles are created:
|
||||
*
|
||||
* - `type` is URI_TYPE_PIPE and `url` is empty: create `pipeprv` handle (with two connected
|
||||
* ends of an anonymous pipe).
|
||||
*
|
||||
* - `type` is URI_TYPE_PIPE_SRV: create `pipesrv` handle (intermediate listening socket) with
|
||||
* name in the form of "@/graphene/<pipeid>" where pipeid is
|
||||
* derived from `uri` via strtol(). Caller is expected to call
|
||||
* pipe_waitforclient() afterwards.
|
||||
*
|
||||
* - `type` is URI_TYPE_PIPE: create `pipe` handle (connecting socket) with name in the form of
|
||||
* "@/graphene/<pipeid>" where pipeid is derived from `uri` via
|
||||
* strtol().
|
||||
*
|
||||
* \param[out] handle Created PAL handle of type `pipeprv`, `pipesrv`, or `pipe`.
|
||||
* \param[in] type Can be URI_TYPE_PIPE or URI_TYPE_PIPE_SRV.
|
||||
* \param[in] uri Content is either NUL (for anonymous pipe) or an integer denoting pipeid.
|
||||
* \param[in] access Not used.
|
||||
* \param[in] share Not used.
|
||||
* \param[in] create Not used.
|
||||
* \param[in] options May contain PAL_OPTION_NONBLOCK.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_open(PAL_HANDLE* handle, const char* type, const char* uri, int access, int share,
|
||||
int create, int options) {
|
||||
if (!WITHIN_MASK(access, PAL_ACCESS_MASK) || !WITHIN_MASK(share, PAL_SHARE_MASK) ||
|
||||
@@ -210,7 +292,15 @@ static int pipe_open(PAL_HANDLE* handle, const char* type, const char* uri, int
|
||||
return -PAL_ERROR_INVAL;
|
||||
}
|
||||
|
||||
/* 'read' operation of pipe stream. offset does not apply here. */
|
||||
/*!
|
||||
* \brief Read from pipe (from read end in case of `pipeprv`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipecli`, or `pipe`.
|
||||
* \param[in] offset Not used.
|
||||
* \param[in] len Size of user-supplied buffer.
|
||||
* \param[out] buffer User-supplied buffer to read data to.
|
||||
* \return Number of bytes read on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int64_t pipe_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void* buffer) {
|
||||
if (offset)
|
||||
return -PAL_ERROR_INVAL;
|
||||
@@ -219,13 +309,11 @@ static int64_t pipe_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void*
|
||||
!IS_HANDLE_TYPE(handle, pipe))
|
||||
return -PAL_ERROR_NOTCONNECTION;
|
||||
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[0] : handle->pipe.fd;
|
||||
int64_t bytes = 0;
|
||||
|
||||
bytes = INLINE_SYSCALL(read, 3, fd, buffer, len);
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[0] : handle->pipe.fd;
|
||||
|
||||
ssize_t bytes = INLINE_SYSCALL(read, 3, fd, buffer, len);
|
||||
if (IS_ERR(bytes))
|
||||
bytes = unix_to_pal_error(ERRNO(bytes));
|
||||
return unix_to_pal_error(ERRNO(bytes));
|
||||
|
||||
if (!bytes)
|
||||
return -PAL_ERROR_ENDOFSTREAM;
|
||||
@@ -233,7 +321,15 @@ static int64_t pipe_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void*
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* 'write' operation of pipe stream. offset does not apply here. */
|
||||
/*!
|
||||
* \brief Write to pipe (to write end in case of `pipeprv`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipecli`, or `pipe`.
|
||||
* \param[in] offset Not used.
|
||||
* \param[in] len Size of user-supplied buffer.
|
||||
* \param[in] buffer User-supplied buffer to write data from.
|
||||
* \return Number of bytes written on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int64_t pipe_write(PAL_HANDLE handle, uint64_t offset, size_t len, const void* buffer) {
|
||||
if (offset)
|
||||
return -PAL_ERROR_INVAL;
|
||||
@@ -242,17 +338,21 @@ static int64_t pipe_write(PAL_HANDLE handle, uint64_t offset, size_t len, const
|
||||
!IS_HANDLE_TYPE(handle, pipe))
|
||||
return -PAL_ERROR_NOTCONNECTION;
|
||||
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[1] : handle->pipe.fd;
|
||||
int64_t bytes = 0;
|
||||
int fd = IS_HANDLE_TYPE(handle, pipeprv) ? handle->pipeprv.fds[1] : handle->pipe.fd;
|
||||
|
||||
bytes = INLINE_SYSCALL(write, 3, fd, buffer, len);
|
||||
ssize_t bytes = INLINE_SYSCALL(write, 3, fd, buffer, len);
|
||||
if (IS_ERR(bytes))
|
||||
bytes = unix_to_pal_error(ERRNO(bytes));
|
||||
return unix_to_pal_error(ERRNO(bytes));
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* 'close' operation of pipe stream. */
|
||||
/*!
|
||||
* \brief Close pipe (both ends in case of `pipeprv`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_close(PAL_HANDLE handle) {
|
||||
if (IS_HANDLE_TYPE(handle, pipeprv)) {
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON) {
|
||||
@@ -263,10 +363,7 @@ static int pipe_close(PAL_HANDLE handle) {
|
||||
INLINE_SYSCALL(close, 1, handle->pipeprv.fds[1]);
|
||||
handle->pipeprv.fds[1] = PAL_IDX_POISON;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handle->pipe.fd != PAL_IDX_POISON) {
|
||||
} else if (handle->pipe.fd != PAL_IDX_POISON) {
|
||||
INLINE_SYSCALL(close, 1, handle->pipe.fd);
|
||||
handle->pipe.fd = PAL_IDX_POISON;
|
||||
}
|
||||
@@ -274,40 +371,14 @@ static int pipe_close(PAL_HANDLE handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 'delete' operation of pipe stream. */
|
||||
/*!
|
||||
* \brief Shut down pipe (one or both ends in case of `pipeprv` depending on `access`).
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[in] access May be 0, PAL_DELETE_RD, PAL_DELETE_WR.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_delete(PAL_HANDLE handle, int access) {
|
||||
if (IS_HANDLE_TYPE(handle, pipeprv)) {
|
||||
switch (access) {
|
||||
case 0:
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON) {
|
||||
INLINE_SYSCALL(close, 1, handle->pipeprv.fds[0]);
|
||||
handle->pipeprv.fds[0] = PAL_IDX_POISON;
|
||||
}
|
||||
if (handle->pipeprv.fds[1] != PAL_IDX_POISON) {
|
||||
INLINE_SYSCALL(close, 1, handle->pipeprv.fds[1]);
|
||||
handle->pipeprv.fds[1] = PAL_IDX_POISON;
|
||||
}
|
||||
break;
|
||||
case PAL_DELETE_RD:
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON) {
|
||||
INLINE_SYSCALL(close, 1, handle->pipeprv.fds[0]);
|
||||
handle->pipeprv.fds[0] = PAL_IDX_POISON;
|
||||
}
|
||||
break;
|
||||
case PAL_DELETE_WR:
|
||||
if (handle->pipeprv.fds[1] != PAL_IDX_POISON) {
|
||||
INLINE_SYSCALL(close, 1, handle->pipeprv.fds[1]);
|
||||
handle->pipeprv.fds[1] = PAL_IDX_POISON;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -PAL_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->pipe.fd == PAL_IDX_POISON)
|
||||
return 0;
|
||||
|
||||
int shutdown;
|
||||
switch (access) {
|
||||
case 0:
|
||||
@@ -323,14 +394,36 @@ static int pipe_delete(PAL_HANDLE handle, int access) {
|
||||
return -PAL_ERROR_INVAL;
|
||||
}
|
||||
|
||||
INLINE_SYSCALL(shutdown, 2, handle->pipe.fd, shutdown);
|
||||
if (IS_HANDLE_TYPE(handle, pipeprv)) {
|
||||
/* pipeprv has two underlying FDs, shut down the requested one(s) */
|
||||
if (handle->pipeprv.fds[0] != PAL_IDX_POISON &&
|
||||
(shutdown == SHUT_RD || shutdown == SHUT_RDWR)) {
|
||||
INLINE_SYSCALL(shutdown, 2, handle->pipeprv.fds[0], SHUT_RD);
|
||||
}
|
||||
|
||||
if (handle->pipeprv.fds[1] != PAL_IDX_POISON &&
|
||||
(shutdown == SHUT_WR || shutdown == SHUT_RDWR)) {
|
||||
INLINE_SYSCALL(shutdown, 2, handle->pipeprv.fds[1], SHUT_WR);
|
||||
}
|
||||
} else {
|
||||
/* other types of pipes have a single underlying FD, shut it down */
|
||||
if (handle->pipe.fd != PAL_IDX_POISON) {
|
||||
INLINE_SYSCALL(shutdown, 2, handle->pipe.fd, shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Retrieve attributes of PAL handle.
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[out] attr User-supplied buffer to store handle's current attributes.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
if (handle->pipe.fd == PAL_IDX_POISON)
|
||||
return -PAL_ERROR_BADHANDLE;
|
||||
@@ -343,6 +436,7 @@ static int pipe_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
/* get number of bytes available for reading (doesn't make sense for "listening" pipes) */
|
||||
attr->pending_size = 0;
|
||||
if (!IS_HANDLE_TYPE(handle, pipesrv)) {
|
||||
int val;
|
||||
ret = INLINE_SYSCALL(ioctl, 3, handle->pipe.fd, FIONREAD, &val);
|
||||
if (IS_ERR(ret))
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
@@ -383,19 +477,26 @@ static int pipe_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set attributes of PAL handle.
|
||||
*
|
||||
* Currently only `nonblocking` attribute can be set.
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[in] attr User-supplied buffer with new handle's attributes.
|
||||
* \return 0 on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_attrsetbyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
if (handle->generic.fds[0] == PAL_IDX_POISON)
|
||||
return -PAL_ERROR_BADHANDLE;
|
||||
|
||||
int ret;
|
||||
PAL_BOL* nonblocking = (HANDLE_HDR(handle)->type == pal_type_pipeprv)
|
||||
? &handle->pipeprv.nonblocking
|
||||
: &handle->pipe.nonblocking;
|
||||
|
||||
if (attr->nonblocking != *nonblocking) {
|
||||
ret = INLINE_SYSCALL(fcntl, 3, handle->generic.fds[0], F_SETFL,
|
||||
attr->nonblocking ? O_NONBLOCK : 0);
|
||||
|
||||
int ret = INLINE_SYSCALL(fcntl, 3, handle->generic.fds[0], F_SETFL,
|
||||
attr->nonblocking ? O_NONBLOCK : 0);
|
||||
if (IS_ERR(ret))
|
||||
return unix_to_pal_error(ERRNO(ret));
|
||||
|
||||
@@ -405,6 +506,16 @@ static int pipe_attrsetbyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Retrieve full URI of PAL handle.
|
||||
*
|
||||
* Full URI is composed of the type and pipeid: "<type>:<pipeid>".
|
||||
*
|
||||
* \param[in] handle PAL handle of type `pipeprv`, `pipesrv`, `pipecli`, or `pipe`.
|
||||
* \param[out] buffer User-supplied buffer to write URI to.
|
||||
* \param[in] count Size of the user-supplied buffer.
|
||||
* \return Number of bytes written on success, negative PAL error code otherwise.
|
||||
*/
|
||||
static int pipe_getname(PAL_HANDLE handle, char* buffer, size_t count) {
|
||||
size_t old_count = count;
|
||||
int ret;
|
||||
|
||||
Reference in New Issue
Block a user