diff options
Diffstat (limited to 'lib/mlibc/sysdeps/managarm/generic/socket.cpp')
-rw-r--r-- | lib/mlibc/sysdeps/managarm/generic/socket.cpp | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/lib/mlibc/sysdeps/managarm/generic/socket.cpp b/lib/mlibc/sysdeps/managarm/generic/socket.cpp new file mode 100644 index 0000000..5bdc1fc --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/socket.cpp @@ -0,0 +1,423 @@ + +#include <bits/ensure.h> +#include <errno.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <netinet/tcp.h> +#include <netinet/in.h> + +#include <mlibc/allocator.hpp> +#include <mlibc/debug.hpp> +#include <mlibc/posix-pipe.hpp> +#include <mlibc/all-sysdeps.hpp> +#include <fs.frigg_bragi.hpp> +#include <posix.frigg_bragi.hpp> + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc { + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + SignalGuard sguard; + + managarm::posix::AcceptRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::WOULD_BLOCK) { + return EWOULDBLOCK; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *newfd = resp.fd(); + } + + if(addr_ptr && addr_length) { + if(int e = mlibc::sys_peername(*newfd, addr_ptr, *addr_length, addr_length); e) { + errno = e; + return -1; + } + } + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_BIND); + + auto [offer, send_req, send_creds, send_buf, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(addr_ptr, addr_length), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(send_buf.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::FILE_NOT_FOUND) { + return ENOENT; + } else if(resp.error() == managarm::fs::Errors::ADDRESS_IN_USE) { + return EADDRINUSE; + } else if(resp.error() == managarm::fs::Errors::ALREADY_EXISTS) { + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::ACCESS_DENIED) { + return EACCES; + } else if(resp.error() == managarm::fs::Errors::ADDRESS_NOT_AVAILABLE) { + return EADDRNOTAVAIL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_CONNECT); + + frg::string<MemoryAllocator> ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, imbue_creds, send_addr, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(const_cast<struct sockaddr *>(addr_ptr), addr_length), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_addr.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::FILE_NOT_FOUND) { + return ENOENT; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } + + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SOCKNAME); + req.set_fd(fd); + req.set_size(max_addr_length); + + auto [offer, send_req, recv_resp, recv_addr] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(addr_ptr, max_addr_length)) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return ENOTSOCK; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + HEL_CHECK(recv_addr.error()); + *actual_length = resp.file_size(); + return 0; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PEERNAME); + req.set_fd(fd); + req.set_size(max_addr_length); + + frg::string<MemoryAllocator> ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, sendReq, recvResp, recvData] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline(), + helix_ng::recvBuffer(addr_ptr, max_addr_length) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + if(recvResp.error() == kHelErrDismissed) + return ENOTSOCK; + HEL_CHECK(recvResp.error()); + HEL_CHECK(recvData.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return ENOTSOCK; + }else if(resp.error() == managarm::fs::Errors::NOT_CONNECTED) { + return ENOTCONN; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *actual_length = resp.file_size(); + return 0; + } +} + +int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + SignalGuard sguard; + + if(layer == SOL_SOCKET && number == SO_PEERCRED) { + if(*size != sizeof(struct ucred)) + return EINVAL; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_GET_OPTION); + req.set_command(SO_PEERCRED); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + struct ucred creds; + creds.pid = resp.pid(); + creds.uid = resp.uid(); + creds.gid = resp.gid(); + memcpy(buffer, &creds, sizeof(struct ucred)); + return 0; + }else if(layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; + *(int *)buffer = 4096; + return 0; + }else if(layer == SOL_SOCKET && number == SO_TYPE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is unimplemented, hardcoding SOCK_STREAM\e[39m" << frg::endlog; + *(int *)buffer = SOCK_STREAM; + return 0; + }else if(layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else if(layer == SOL_SOCKET && number == SO_LINGER) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_LINGER is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } +} + +int sys_setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size) { + SignalGuard sguard; + + if(layer == SOL_SOCKET && number == SO_PASSCRED) { + int value; + __ensure(size == sizeof(int)); + memcpy(&value, buffer, sizeof(int)); + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SET_OPTION); + req.set_command(SO_PASSCRED); + req.set_value(value); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; + }else if(layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEADDR is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_REUSEPORT) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEPORT is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_RCVBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_RCVBUF is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_NODELAY) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_NODELAY is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_ACCEPTCONN) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_ACCEPTCONN is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_KEEPIDLE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPIDLE is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_NETLINK && number == NETLINK_EXT_ACK) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and NETLINK_EXT_ACK is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_NETLINK && number == NETLINK_GET_STRICT_CHK) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and NETLINK_EXT_ACK is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_KEEPINTVL) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPINTVL is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_KEEPCNT) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPCNT is unimplemented\e[39m" << frg::endlog; + return 0; + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } +} + +int sys_listen(int fd, int) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_LISTEN); + + frg::string<MemoryAllocator> ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; +} + +} //namespace mlibc |