/* Copyright (C) 2014 Stony Brook University
This file is part of Graphene Library OS.
Graphene Library OS is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Graphene Library OS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see . */
/*
* shim_pipe.c
*
* Implementation of system call "pipe", "pipe2" and "socketpair".
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
int create_pipes(IDTYPE* pipeid, PAL_HANDLE* srv, PAL_HANDLE* cli, struct shim_qstr* qstr,
int flags) {
PAL_HANDLE hdl0 = NULL, hdl1 = NULL, hdl2 = NULL;
int ret = 0;
char uri[PIPE_URI_SIZE];
if ((ret = create_pipe(pipeid, uri, PIPE_URI_SIZE, &hdl0, qstr,
/*use_vmid_for_name=*/false)) < 0) {
debug("pipe creation failure\n");
return ret;
}
if (!(hdl2 = DkStreamOpen(uri, 0, 0, 0, flags & O_NONBLOCK))) {
ret = -PAL_ERRNO;
debug("pipe connection failure\n");
goto err;
}
if (!(hdl1 = DkStreamWaitForClient(hdl0))) {
ret = -PAL_ERRNO;
debug("pipe acception failure\n");
goto err;
}
DkStreamDelete(hdl0, 0);
DkObjectClose(hdl0);
*srv = hdl1;
*cli = hdl2;
return 0;
err:
if (hdl1)
DkObjectClose(hdl1);
if (hdl2)
DkObjectClose(hdl2);
DkStreamDelete(hdl0, 0);
DkObjectClose(hdl0);
return ret;
}
int shim_do_pipe2(int* filedes, int flags) {
if (!filedes || test_user_memory(filedes, 2 * sizeof(int), true))
return -EFAULT;
int ret = 0;
struct shim_handle* hdl1 = get_new_handle();
struct shim_handle* hdl2 = get_new_handle();
if (!hdl1 || !hdl2) {
ret = -ENOMEM;
goto out;
}
hdl1->type = TYPE_PIPE;
set_handle_fs(hdl1, &pipe_builtin_fs);
hdl1->flags = O_RDONLY;
hdl1->acc_mode = MAY_READ;
hdl2->type = TYPE_PIPE;
set_handle_fs(hdl2, &pipe_builtin_fs);
hdl2->flags = O_WRONLY;
hdl2->acc_mode = MAY_WRITE;
if ((ret = create_pipes(&hdl1->info.pipe.pipeid, &hdl1->pal_handle, &hdl2->pal_handle,
&hdl1->uri, flags)) < 0)
goto out;
qstrcopy(&hdl2->uri, &hdl2->uri);
flags = flags & O_CLOEXEC ? FD_CLOEXEC : 0;
int vfd1 = set_new_fd_handle(hdl1, flags, NULL);
int vfd2 = set_new_fd_handle(hdl2, flags, NULL);
if (vfd1 < 0 || vfd2 < 0) {
if (vfd1 >= 0) {
struct shim_handle* tmp = detach_fd_handle(vfd1, NULL, NULL);
if (tmp)
put_handle(tmp);
}
if (vfd2 >= 0) {
struct shim_handle* tmp = detach_fd_handle(vfd2, NULL, NULL);
if (tmp)
put_handle(tmp);
}
goto out;
}
filedes[0] = vfd1;
filedes[1] = vfd2;
out:
if (hdl1)
put_handle(hdl1);
if (hdl2)
put_handle(hdl2);
return ret;
}
int shim_do_pipe(int* filedes) {
return shim_do_pipe2(filedes, 0);
}
int shim_do_socketpair(int domain, int type, int protocol, int* sv) {
if (domain != AF_UNIX)
return -EAFNOSUPPORT;
if (type != SOCK_STREAM)
return -EPROTONOSUPPORT;
if (!sv || test_user_memory(sv, 2 * sizeof(int), true))
return -EFAULT;
int ret = 0;
struct shim_handle* hdl1 = get_new_handle();
struct shim_handle* hdl2 = get_new_handle();
if (!hdl1 || !hdl2) {
ret = -ENOMEM;
goto out;
}
struct shim_sock_handle* sock1 = &hdl1->info.sock;
struct shim_sock_handle* sock2 = &hdl2->info.sock;
hdl1->type = TYPE_SOCK;
set_handle_fs(hdl1, &socket_builtin_fs);
hdl1->flags = O_RDONLY;
hdl1->acc_mode = MAY_READ | MAY_WRITE;
sock1->domain = domain;
sock1->sock_type = type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
sock1->protocol = protocol;
sock1->sock_state = SOCK_ACCEPTED;
hdl2->type = TYPE_SOCK;
set_handle_fs(hdl2, &socket_builtin_fs);
hdl1->flags = O_WRONLY;
hdl2->acc_mode = MAY_READ | MAY_WRITE;
sock2->domain = domain;
sock2->sock_type = type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
sock2->protocol = protocol;
sock2->sock_state = SOCK_CONNECTED;
if ((ret = create_pipes(&sock1->addr.un.pipeid, &hdl1->pal_handle, &hdl2->pal_handle,
&hdl1->uri, type & SOCK_NONBLOCK ? O_NONBLOCK : 0)) < 0)
goto out;
sock2->addr.un.pipeid = sock1->addr.un.pipeid;
qstrcopy(&hdl2->uri, &hdl1->uri);
int flags = type & SOCK_CLOEXEC ? FD_CLOEXEC : 0;
int vfd1 = set_new_fd_handle(hdl1, flags, NULL);
int vfd2 = set_new_fd_handle(hdl2, flags, NULL);
if (vfd1 < 0 || vfd2 < 0) {
if (vfd1 >= 0) {
struct shim_handle* tmp = detach_fd_handle(vfd1, NULL, NULL);
if (tmp)
put_handle(tmp);
}
if (vfd2 >= 0) {
struct shim_handle* tmp = detach_fd_handle(vfd2, NULL, NULL);
if (tmp)
put_handle(tmp);
}
goto out;
}
sv[0] = vfd1;
sv[1] = vfd2;
out:
if (hdl1)
put_handle(hdl1);
if (hdl2)
put_handle(hdl2);
return ret;
}