Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Assertions.h>
8#include <bits/pthread_cancel.h>
9#include <errno.h>
10#include <stdio.h>
11#include <string.h>
12#include <sys/socket.h>
13#include <sys/uio.h>
14#include <syscall.h>
15
16extern "C" {
17
18// https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html
19int socket(int domain, int type, int protocol)
20{
21 int rc = syscall(SC_socket, domain, type, protocol);
22 __RETURN_WITH_ERRNO(rc, rc, -1);
23}
24
25// https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html
26int bind(int sockfd, sockaddr const* addr, socklen_t addrlen)
27{
28 int rc = syscall(SC_bind, sockfd, addr, addrlen);
29 __RETURN_WITH_ERRNO(rc, rc, -1);
30}
31
32// https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html
33int listen(int sockfd, int backlog)
34{
35 int rc = syscall(SC_listen, sockfd, backlog);
36 __RETURN_WITH_ERRNO(rc, rc, -1);
37}
38
39// https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html
40int accept(int sockfd, sockaddr* addr, socklen_t* addrlen)
41{
42 __pthread_maybe_cancel();
43
44 return accept4(sockfd, addr, addrlen, 0);
45}
46
47int accept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags)
48{
49 Syscall::SC_accept4_params params { addr, addrlen, sockfd, flags };
50 int rc = syscall(SC_accept4, ¶ms);
51 __RETURN_WITH_ERRNO(rc, rc, -1);
52}
53
54// https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
55int connect(int sockfd, sockaddr const* addr, socklen_t addrlen)
56{
57 __pthread_maybe_cancel();
58
59 int rc = syscall(SC_connect, sockfd, addr, addrlen);
60 __RETURN_WITH_ERRNO(rc, rc, -1);
61}
62
63// https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html
64int shutdown(int sockfd, int how)
65{
66 int rc = syscall(SC_shutdown, sockfd, how);
67 __RETURN_WITH_ERRNO(rc, rc, -1);
68}
69
70// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
71ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags)
72{
73 __pthread_maybe_cancel();
74
75 int rc = syscall(SC_sendmsg, sockfd, msg, flags);
76 __RETURN_WITH_ERRNO(rc, rc, -1);
77}
78
79// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html
80ssize_t sendto(int sockfd, void const* data, size_t data_length, int flags, const struct sockaddr* addr, socklen_t addr_length)
81{
82 iovec iov = { const_cast<void*>(data), data_length };
83 msghdr msg = { const_cast<struct sockaddr*>(addr), addr_length, &iov, 1, nullptr, 0, 0 };
84 return sendmsg(sockfd, &msg, flags);
85}
86
87// https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html
88ssize_t send(int sockfd, void const* data, size_t data_length, int flags)
89{
90 return sendto(sockfd, data, data_length, flags, nullptr, 0);
91}
92
93// https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html
94ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags)
95{
96 __pthread_maybe_cancel();
97
98 int rc = syscall(SC_recvmsg, sockfd, msg, flags);
99 __RETURN_WITH_ERRNO(rc, rc, -1);
100}
101
102// https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html
103ssize_t recvfrom(int sockfd, void* buffer, size_t buffer_length, int flags, struct sockaddr* addr, socklen_t* addr_length)
104{
105 __pthread_maybe_cancel();
106
107 if (!addr_length && addr) {
108 errno = EINVAL;
109 return -1;
110 }
111
112 sockaddr_storage internal_addr;
113 iovec iov = { buffer, buffer_length };
114 msghdr msg = { addr ? &internal_addr : nullptr, addr ? (socklen_t)sizeof(internal_addr) : 0, &iov, 1, nullptr, 0, 0 };
115 ssize_t rc = recvmsg(sockfd, &msg, flags);
116 if (rc >= 0 && addr) {
117 memcpy(addr, &internal_addr, min(*addr_length, msg.msg_namelen));
118 *addr_length = msg.msg_namelen;
119 }
120 return rc;
121}
122
123// https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html
124ssize_t recv(int sockfd, void* buffer, size_t buffer_length, int flags)
125{
126 return recvfrom(sockfd, buffer, buffer_length, flags, nullptr, nullptr);
127}
128
129// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html
130int getsockopt(int sockfd, int level, int option, void* value, socklen_t* value_size)
131{
132 Syscall::SC_getsockopt_params params { sockfd, level, option, value, value_size };
133 int rc = syscall(SC_getsockopt, ¶ms);
134 __RETURN_WITH_ERRNO(rc, rc, -1);
135}
136
137// https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html
138int setsockopt(int sockfd, int level, int option, void const* value, socklen_t value_size)
139{
140 Syscall::SC_setsockopt_params params { value, sockfd, level, option, value_size };
141 int rc = syscall(SC_setsockopt, ¶ms);
142 __RETURN_WITH_ERRNO(rc, rc, -1);
143}
144
145// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html
146int getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
147{
148 Syscall::SC_getsockname_params params { sockfd, addr, addrlen };
149 int rc = syscall(SC_getsockname, ¶ms);
150 __RETURN_WITH_ERRNO(rc, rc, -1);
151}
152
153// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html
154int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
155{
156 Syscall::SC_getpeername_params params { sockfd, addr, addrlen };
157 int rc = syscall(SC_getpeername, ¶ms);
158 __RETURN_WITH_ERRNO(rc, rc, -1);
159}
160
161// https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html
162int socketpair(int domain, int type, int protocol, int sv[2])
163{
164 Syscall::SC_socketpair_params params { domain, type, protocol, sv };
165 int rc = syscall(SC_socketpair, ¶ms);
166 __RETURN_WITH_ERRNO(rc, rc, -1);
167}
168
169int sendfd(int sockfd, int fd)
170{
171 int rc = syscall(SC_sendfd, sockfd, fd);
172 __RETURN_WITH_ERRNO(rc, rc, -1);
173}
174
175int recvfd(int sockfd, int options)
176{
177 int rc = syscall(SC_recvfd, sockfd, options);
178 __RETURN_WITH_ERRNO(rc, rc, -1);
179}
180}