options/posix: Implement recvmsg() and sendmsg()

This commit is contained in:
Alexander van der Grinten 2018-02-19 20:57:16 +01:00
parent 14d41a3b42
commit 15397facc0
4 changed files with 143 additions and 25 deletions

View file

@ -54,9 +54,12 @@ static bool disableBuffering = false;
FILE *fopen(const char *__restrict filename, const char *__restrict mode) {
int fd;
if(strcmp(mode, "r")) {
if(!strcmp(mode, "r") || !strcmp(mode, "rb")) {
if(mlibc::sys_open(filename, __MLIBC_O_RDONLY, &fd))
return nullptr;
}else if(!strcmp(mode, "re")) {
if(mlibc::sys_open(filename, __MLIBC_O_RDONLY | __MLIBC_O_CLOEXEC, &fd))
return nullptr;
}else{
frigg::panicLogger() << "Illegal fopen() mode '" << mode << "'" << frigg::endLog;
}

View file

@ -1,13 +1,14 @@
#include <cstdarg>
#include <time.h>
#include <bits/posix/ssize_t.h>
#include <bits/posix/off_t.h>
#include <bits/posix/pid_t.h>
#include <bits/posix/socklen_t.h>
#include <bits/posix/stat.h>
#include <stdarg.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <time.h>
namespace mlibc {
@ -32,6 +33,8 @@ int sys_ftruncate(int fd, size_t size);
int sys_fallocate(int fd, off_t offset, size_t size);
int sys_unlink(const char *path);
int sys_socket(int family, int type, int protocol, int *fd);
int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length);
int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length);
gid_t sys_getgid();
gid_t sys_getegid();
uid_t sys_getuid();

View file

@ -65,19 +65,11 @@ ssize_t recvfrom(int, void *__restrict, size_t, int, struct sockaddr *__restrict
__builtin_unreachable();
}
ssize_t recvmsg(int fd, struct msghdr *msgh, int flags) {
__ensure(msgh->msg_iovlen);
frigg::infoLogger() << "mlibc: recvmsg() control length: " << msgh->msg_controllen
<< frigg::endLog;
ssize_t size;
if(mlibc::sys_read(fd, msgh->msg_iov[0].iov_base, msgh->msg_iov[0].iov_len, &size))
ssize_t recvmsg(int fd, struct msghdr *hdr, int flags) {
ssize_t length;
if(mlibc::sys_msg_recv(fd, hdr, flags, &length))
return -1;
msgh->msg_controllen = 0;
return size;
return length;
}
ssize_t send(int, const void *, size_t, int) {
@ -85,17 +77,11 @@ ssize_t send(int, const void *, size_t, int) {
__builtin_unreachable();
}
ssize_t sendmsg(int fd, const struct msghdr *msgh, int flags) {
__ensure(msgh->msg_iovlen);
frigg::infoLogger() << "mlibc: sendmsg() control length: " << msgh->msg_controllen
<< frigg::endLog;
__ensure(!msgh->msg_controllen);
ssize_t size;
if(mlibc::sys_write(fd, msgh->msg_iov[0].iov_base, msgh->msg_iov[0].iov_len, &size))
ssize_t sendmsg(int fd, const struct msghdr *hdr, int flags) {
ssize_t length;
if(mlibc::sys_msg_send(fd, hdr, flags, &length))
return -1;
return size;
return length;
}
ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t) {

View file

@ -423,6 +423,132 @@ int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) {
return 0;
}
int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length) {
__ensure(hdr->msg_iovlen);
HelAction actions[4];
globalQueue.trim();
managarm::posix::CntRequest<MemoryAllocator> req(getAllocator());
req.set_request_type(managarm::posix::CntReqType::SENDMSG);
req.set_fd(sockfd);
frigg::infoLogger() << "mlibc: sendmsg() control length: " << hdr->msg_controllen
<< frigg::endLog;
for(auto cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
__ensure(cmsg->cmsg_level == SOL_SOCKET);
__ensure(cmsg->cmsg_type == SCM_RIGHTS);
__ensure(cmsg->cmsg_len >= sizeof(struct cmsghdr));
size_t size = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
__ensure(!(size % sizeof(int)));
for(size_t off = 0; off < size; off += sizeof(int)) {
int fd;
memcpy(&fd, CMSG_DATA(cmsg) + off, sizeof(int));
req.add_fds(fd);
frigg::infoLogger() << "mlibc: sending fd " << fd << frigg::endLog;
}
}
frigg::String<MemoryAllocator> ser(getAllocator());
req.SerializeToString(&ser);
actions[0].type = kHelActionOffer;
actions[0].flags = kHelItemAncillary;
actions[1].type = kHelActionSendFromBuffer;
actions[1].flags = kHelItemChain;
actions[1].buffer = ser.data();
actions[1].length = ser.size();
actions[2].type = kHelActionSendFromBuffer;
actions[2].flags = kHelItemChain;
actions[2].buffer = hdr->msg_iov[0].iov_base;
actions[2].length = hdr->msg_iov[0].iov_len;
actions[3].type = kHelActionRecvInline;
actions[3].flags = 0;
HEL_CHECK(helSubmitAsync(kHelThisThread, actions, 4,
globalQueue.getQueue(), 0, 0));
auto element = globalQueue.dequeueSingle();
auto offer = parseSimple(element);
auto send_req = parseSimple(element);
auto send_data = parseSimple(element);
auto recv_resp = parseInline(element);
HEL_CHECK(offer->error);
HEL_CHECK(send_req->error);
HEL_CHECK(send_data->error);
HEL_CHECK(recv_resp->error);
managarm::posix::SvrResponse<MemoryAllocator> resp(getAllocator());
resp.ParseFromArray(recv_resp->data, recv_resp->length);
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
*length = resp.size();
return 0;
}
int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length) {
__ensure(hdr->msg_iovlen);
HelAction actions[4];
globalQueue.trim();
managarm::posix::CntRequest<MemoryAllocator> req(getAllocator());
req.set_request_type(managarm::posix::CntReqType::RECVMSG);
req.set_fd(sockfd);
req.set_size(hdr->msg_iov[0].iov_len);
frigg::String<MemoryAllocator> ser(getAllocator());
req.SerializeToString(&ser);
actions[0].type = kHelActionOffer;
actions[0].flags = kHelItemAncillary;
actions[1].type = kHelActionSendFromBuffer;
actions[1].flags = kHelItemChain;
actions[1].buffer = ser.data();
actions[1].length = ser.size();
actions[2].type = kHelActionRecvInline;
actions[2].flags = kHelItemChain;
actions[3].type = kHelActionRecvToBuffer;
actions[3].flags = 0;
actions[3].buffer = hdr->msg_iov[0].iov_base;
actions[3].length = hdr->msg_iov[0].iov_len;
HEL_CHECK(helSubmitAsync(kHelThisThread, actions, 4,
globalQueue.getQueue(), 0, 0));
auto element = globalQueue.dequeueSingle();
auto offer = parseSimple(element);
auto send_req = parseSimple(element);
auto recv_resp = parseInline(element);
auto recv_data = parseLength(element);
HEL_CHECK(offer->error);
HEL_CHECK(send_req->error);
HEL_CHECK(recv_resp->error);
HEL_CHECK(recv_data->error);
managarm::posix::SvrResponse<MemoryAllocator> resp(getAllocator());
resp.ParseFromArray(recv_resp->data, recv_resp->length);
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
if(resp.fds_size()) {
auto space = CMSG_SPACE(resp.fds_size());
__ensure(hdr->msg_controllen >= space);
auto cmsg = CMSG_FIRSTHDR(hdr);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(resp.fds_size() * sizeof(int));
for(int i = 0; i < resp.fds_size(); i++) {
int fd = resp.fds(i);
memcpy(CMSG_DATA(cmsg) + i * sizeof(int), &fd, sizeof(int));
}
hdr->msg_controllen = space;
}
*length = recv_data->length;
return 0;
}
int sys_epoll_create(int flags, int *fd) {
__ensure(!(flags & ~(EPOLL_CLOEXEC)));
if(flags & EPOLL_CLOEXEC)