AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
sys_net.c
Go to the documentation of this file.
1
7
8#include "syscalls.h"
9
19long sys_socket(int domain, int type, int protocol)
20{
21 syscall_log(LOG_DEBUG, "socket(domain=%d, type=%d, protocol=%d)\n",
22 domain, type, protocol);
23
24 int fd = proc_fd_get(curproc);
25
26 if (fd == -1) { /* every descriptor is in use */
27 return -EMFILE;
28 }
29
30 int err = 0;
31 struct file *file = file_new();
32
33 if (!file || (err = socket_create(file, domain, type, protocol))) {
34 /* the file was never opened: there's nothing to close */
35 kfree(file);
37 return file ? err : -ENOMEM;
38 }
39
41 return fd;
42}
43
44/*
45 * Socket addresses. The kernel works on its own copy, as big as the
46 * biggest address (AF_UNIX's). An address coming in is `len` bytes of user
47 * memory. An address going out is the protocol's, `klen` bytes, of which
48 * as much as fits in the user's buffer (`*ulen` bytes) is copied out; then
49 * `*ulen` is set to its full size.
50 */
51union ksockaddr {
52 struct sockaddr sa;
53 struct sockaddr_un un;
54};
55
58static int sockaddr_copyin(union ksockaddr *k, const struct sockaddr *uaddr, socklen_t len)
59{
60 if (len > sizeof(*k))
61 return -EINVAL;
62
63 return copyin(k, uaddr, len);
64}
65
68static int sockaddr_room(socklen_t *ulen, socklen_t *klen)
69{
70 if (copyin(klen, ulen, sizeof(*klen)))
71 return -EFAULT;
72
73 *klen = MIN(*klen, sizeof(union ksockaddr));
74 return 0;
75}
76
79static int sockaddr_copyout(struct sockaddr *uaddr, socklen_t *ulen, const union ksockaddr *k, socklen_t klen, socklen_t room)
80{
81 if (copyout(uaddr, k, MIN(klen, room)) || copyout(ulen, &klen, sizeof(klen)))
82 return -EFAULT;
83
84 return 0;
85}
86
97long sys_accept(int fd, const struct sockaddr *addr, socklen_t *len)
98{
99 syscall_log(LOG_DEBUG, "accept(fd=%d, addr=%p, len=%p)\n",
100 fd, addr, len);
101
102 struct file *socket = fd_file(fd);
103
104 if (!socket) {
105 return -EBADF;
106 }
107
108 int conn_fd = proc_fd_get(curproc);
109
110 if (conn_fd == -1) {
111 return -EMFILE;
112 }
113
114 struct file *conn = file_new();
115
116 if (!conn) {
117 proc_fd_release(curproc, conn_fd);
118 return -ENOMEM;
119 }
120
121 union ksockaddr k;
122 memset(&k, 0, sizeof(k));
123 socklen_t room = 0, klen = 0;
124 int err = 0;
125
126 if (addr && (err = sockaddr_room(len, &room))) {
127 kfree(conn);
128 proc_fd_release(curproc, conn_fd);
129 return err;
130 }
131
132 klen = room;
133
134 if ((err = socket_accept(socket, conn, addr ? &k.sa : NULL, addr ? &klen : NULL))) {
135 kfree(conn);
136 proc_fd_release(curproc, conn_fd);
137 return err;
138 }
139
140 proc_fd_install(curproc, conn_fd, conn, 0);
141
142 /* if the peer's address can't be written out, the connection is
143 * closed */
144 if (addr && sockaddr_copyout((struct sockaddr *) addr, len, &k, klen, room)) {
145 proc_fd_close(curproc, conn_fd);
146 return -EFAULT;
147 }
148
149 return conn_fd;
150}
151
161long sys_bind(int fd, const struct sockaddr *addr, socklen_t len)
162{
163 syscall_log(LOG_DEBUG, "bind(fd=%d, addr=%p, len=%d)\n",
164 fd, addr, len);
165
166 struct file *file = fd_file(fd);
167
168 if (!file) {
169 return -EBADF;
170 }
171
172 union ksockaddr k;
173 memset(&k, 0, sizeof(k));
174 int err = 0;
175
176 if ((err = sockaddr_copyin(&k, addr, len)) || (err = socket_bind(file, &k.sa, len))) {
177 return err;
178 }
179
180 return 0;
181}
182
192long sys_connect(int fd, const struct sockaddr *addr, socklen_t len)
193{
194 syscall_log(LOG_DEBUG, "connect(fd=%d, addr=%p, len=%d)\n",
195 fd, addr, len);
196
197 struct file *socket = fd_file(fd);
198
199 if (!socket) {
200 return -EBADF;
201 }
202
203 union ksockaddr k;
204 memset(&k, 0, sizeof(k));
205 int err = 0;
206
207 if ((err = sockaddr_copyin(&k, addr, len)) || (err = socket_connect(socket, &k.sa, len))) {
208 return err;
209 }
210
211 return 0;
212}
213
221long sys_listen(int fd, int backlog)
222{
223 syscall_log(LOG_DEBUG, "listen(fd=%d, backlog=%d)\n", fd, backlog);
224
225 struct file *file = fd_file(fd);
226
227 if (!file) {
228 return -EBADF;
229 }
230
231 int err = 0;
232
233 if ((err = socket_listen(file, backlog))) {
234 return err;
235 }
236
237 return 0;
238}
239
249long sys_send(struct aquila_socket_io_args *us)
250{
251 struct aquila_socket_io_args _s, *s = &_s;
252
253 if (copyin(s, us, sizeof(*s))) {
254 return -EFAULT;
255 }
256
257 int fd = s->fd;
258 void *buf = s->buf;
259 size_t len = s->len;
260 int flags = s->flags;
261
262 syscall_log(LOG_DEBUG, "send(fd=%d, buf=%p, len=%d, flags=%x)\n",
263 fd, buf, len, flags);
264
265 struct file *file = fd_file(fd);
266
267 if (!file) {
268 return -EBADF;
269 }
270
271 int err = 0;
272
273 if (uaccess_check(buf, len)) {
274 return -EFAULT;
275 }
276
277 /* sendto(): the destination */
278 union ksockaddr to;
279 memset(&to, 0, sizeof(to));
280 socklen_t tolen = 0;
281
282 if (s->addr) {
283 if (copyin(&tolen, s->addrlen, sizeof(tolen))) {
284 return -EFAULT;
285 }
286
287 if ((err = sockaddr_copyin(&to, s->addr, tolen))) {
288 return err;
289 }
290 }
291
292 struct iobuf io;
293 iobuf_init(&io, buf, len, 1);
294
295 ssize_t ret = socket_send(file, &io, flags, s->addr ? &to.sa : NULL, tolen);
296
297 /* a connection that can't send anymore raises SIGPIPE too, as write()
298 * does (not with MSG_NOSIGNAL) */
299 if (ret == -EPIPE && !(flags & MSG_NOSIGNAL))
300 signal_proc_send(curproc, SIGPIPE);
301
302 return ret;
303}
304
313long sys_recv(struct aquila_socket_io_args *us)
314{
315 struct aquila_socket_io_args _s, *s = &_s;
316
317 if (copyin(s, us, sizeof(*s))) {
318 return -EFAULT;
319 }
320
321 int fd = s->fd;
322 void *buf = s->buf;
323 size_t len = s->len;
324 int flags = s->flags;
325
326 syscall_log(LOG_DEBUG, "recv(fd=%d, buf=%p, len=%d, flags=%x)\n",
327 fd, buf, len, flags);
328
329 struct file *file = fd_file(fd);
330
331 if (!file) {
332 return -EBADF;
333 }
334
335 int err = 0;
336
337 if (uaccess_check(buf, len)) {
338 return -EFAULT;
339 }
340
341 /* recvfrom(): the sender's address */
342 union ksockaddr from;
343 memset(&from, 0, sizeof(from));
344 socklen_t room = 0, fromlen = 0;
345
346 if (s->addr && (err = sockaddr_room(s->addrlen, &room))) {
347 return err;
348 }
349
350 fromlen = room;
351
352 struct iobuf io;
353 iobuf_init(&io, buf, len, 1);
354
355 ssize_t ret = socket_recv(file, &io, flags, s->addr ? &from.sa : NULL, s->addr ? &fromlen : NULL);
356
357 if (ret >= 0 && s->addr && sockaddr_copyout(s->addr, s->addrlen, &from, fromlen, room))
358 ret = -EFAULT;
359
360 return ret;
361}
362
365static long socket_name(int fd, struct sockaddr *addr, socklen_t *len, int peer)
366{
367 struct file *file = fd_file(fd);
368
369 if (!file) {
370 return -EBADF;
371 }
372
373 union ksockaddr k;
374 memset(&k, 0, sizeof(k));
375 socklen_t room, klen;
376 int err;
377
378 if ((err = sockaddr_room(len, &room))) {
379 return err;
380 }
381
382 klen = room;
383
384 if (!(err = socket_getname(file, &k.sa, &klen, peer)))
385 err = sockaddr_copyout(addr, len, &k, klen, room);
386
387 return err;
388}
389
398long sys_getsockname(int fd, struct sockaddr *addr, socklen_t *len)
399{
400 syscall_log(LOG_DEBUG, "getsockname(fd=%d, addr=%p, len=%p)\n", fd, addr, len);
401 return socket_name(fd, addr, len, 0);
402}
403
412long sys_getpeername(int fd, struct sockaddr *addr, socklen_t *len)
413{
414 syscall_log(LOG_DEBUG, "getpeername(fd=%d, addr=%p, len=%p)\n", fd, addr, len);
415 return socket_name(fd, addr, len, 1);
416}
417
429long sys_getsockopt(int fd, int level, int name, void *val, socklen_t *len)
430{
431 syscall_log(LOG_DEBUG, "getsockopt(fd=%d, level=%d, name=%d, val=%p, len=%p)\n",
432 fd, level, name, val, len);
433
434 struct file *file = fd_file(fd);
435
436 if (!file) {
437 return -EBADF;
438 }
439
440 /* the kernel's copy of the value (the biggest is a struct timeval) */
441 char kval[64];
442 memset(kval, 0, sizeof(kval));
443 socklen_t room, klen;
444 int err;
445
446 if (copyin(&room, len, sizeof(room))) {
447 return -EFAULT;
448 }
449
450 klen = room = MIN(room, sizeof(kval));
451
452 if (!(err = socket_getsockopt(file, level, name, kval, &klen)) &&
453 (copyout(val, kval, MIN(klen, room)) || copyout(len, &klen, sizeof(klen))))
454 err = -EFAULT;
455
456 return err;
457}
458
470long sys_setsockopt(int fd, int level, int name, const void *val, socklen_t len)
471{
472 syscall_log(LOG_DEBUG, "setsockopt(fd=%d, level=%d, name=%d, val=%p, len=%d)\n",
473 fd, level, name, val, len);
474
475 struct file *file = fd_file(fd);
476
477 if (!file) {
478 return -EBADF;
479 }
480
481 char kval[64];
482
483 len = MIN(len, sizeof(kval));
484
485 if (copyin(kval, val, len)) {
486 return -EFAULT;
487 }
488
489 return socket_setsockopt(file, level, name, kval, len);
490}
491
501long sys_shutdown(int fd, int how)
502{
503 syscall_log(LOG_DEBUG, "shutdown(fd=%d, how=%d)\n", fd, how);
504
505 struct file *file = fd_file(fd);
506
507 if (!file) {
508 return -EBADF;
509 }
510
511 return socket_shutdown_dir(file, how);
512}
struct file * file_new(void)
Makes a new open file, with one reference.
Definition file.c:32
#define MIN(a, b)
Definition system.h:11
void iobuf_init(struct iobuf *io, void *buf, size_t len, int user)
Sets up an iobuf for one buffer.
Definition iobuf.c:19
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
#define LOG_DEBUG
Definition printk.h:19
int proc_fd_get(struct proc *proc)
Reserves the lowest free descriptor of a process, while a system call sets it up: no other thread tak...
Definition proc.c:514
int proc_fd_close(struct proc *proc, int fd)
Closes a descriptor: it is free again, and its reference to the open file is dropped.
Definition proc.c:578
void proc_fd_release(struct proc *proc, int fd)
Frees a reserved descriptor that wasn't set up after all.
Definition proc.c:532
void proc_fd_install(struct proc *proc, int fd, struct file *file, int flags)
Makes a reserved descriptor refer to an open file.
Definition proc.c:547
#define curproc
Definition sched.h:13
int signal_proc_send(struct proc *proc, int signal)
Sends a signal to a process.
Definition signal.c:310
int socket_listen(struct file *file, int backlog)
Makes a socket listen for connections, for listen().
Definition socket.c:120
int socket_shutdown_dir(struct file *file, int how)
Shuts down reading, writing or both on a socket, for shutdown().
Definition socket.c:245
int socket_getsockopt(struct file *file, int level, int name, void *val, socklen_t *len)
Reads a socket option, for getsockopt().
Definition socket.c:325
int socket_connect(struct file *file, const struct sockaddr *addr, socklen_t len)
Connects a socket to a peer, for connect().
Definition socket.c:102
int socket_setsockopt(struct file *file, int level, int name, const void *val, socklen_t len)
Sets a socket option, for setsockopt().
Definition socket.c:361
int socket_create(struct file *file, int domain, int type, int protocol)
Makes a socket of a domain in an open file, for socket().
Definition socket.c:27
int socket_accept(struct file *file, struct file *conn, const struct sockaddr *addr, socklen_t *len)
Accepts a connection on a listening socket, for accept().
Definition socket.c:59
ssize_t socket_recv(struct file *file, struct iobuf *io, int flags, struct sockaddr *from, socklen_t *fromlen)
Receives data from a socket, for recv(), recvfrom() and read().
Definition socket.c:169
int socket_getname(struct file *file, struct sockaddr *addr, socklen_t *len, int peer)
Gets a socket's local address, or its peer's, for getsockname() and getpeername().
Definition socket.c:289
ssize_t socket_send(struct file *file, struct iobuf *io, int flags, const struct sockaddr *to, socklen_t tolen)
Sends data on a socket, for send(), sendto() and write().
Definition socket.c:141
int socket_bind(struct file *file, const struct sockaddr *addr, socklen_t len)
Gives a socket its local address, for bind().
Definition socket.c:83
#define NULL
Definition stddef.h:27
A file descriptor: the open file it refers to (fs/file.c, shared with the descriptors that dup() and ...
Definition proc.h:47
int flags
Definition proc.h:49
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
An iobuf.
Definition iobuf.h:35
A socket.
Definition socket.h:16
struct file * fd_file(int fd)
Finds the open file that a descriptor of the current process refers to, and holds it until the system...
Definition syscall.c:22
long sys_getpeername(int fd, struct sockaddr *addr, socklen_t *len)
Implements getpeername(): the address of a socket's peer.
Definition sys_net.c:412
long sys_getsockname(int fd, struct sockaddr *addr, socklen_t *len)
Implements getsockname(): a socket's local address.
Definition sys_net.c:398
long sys_connect(int fd, const struct sockaddr *addr, socklen_t len)
Implements connect(): connects a socket to a peer.
Definition sys_net.c:192
long sys_socket(int domain, int type, int protocol)
Implements socket(): makes a socket, open on a new descriptor.
Definition sys_net.c:19
static int sockaddr_copyout(struct sockaddr *uaddr, socklen_t *ulen, const union ksockaddr *k, socklen_t klen, socklen_t room)
Copies an address out to user memory, as much of it as fits in room, and sets *ulen to its full size ...
Definition sys_net.c:79
static int sockaddr_copyin(union ksockaddr *k, const struct sockaddr *uaddr, socklen_t len)
Copies an address of len bytes from user memory.
Definition sys_net.c:58
long sys_accept(int fd, const struct sockaddr *addr, socklen_t *len)
Implements accept(): takes a connection from a listening socket, open on a new descriptor.
Definition sys_net.c:97
long sys_getsockopt(int fd, int level, int name, void *val, socklen_t *len)
Implements getsockopt(): reads a socket option.
Definition sys_net.c:429
static int sockaddr_room(socklen_t *ulen, socklen_t *klen)
Reads how much room the user's buffer has for an address going out, into *klen, at most the kernel co...
Definition sys_net.c:68
long sys_recv(struct aquila_socket_io_args *us)
Implements recv() and recvfrom().
Definition sys_net.c:313
long sys_send(struct aquila_socket_io_args *us)
Implements send() and sendto().
Definition sys_net.c:249
long sys_shutdown(int fd, int how)
Implements shutdown(): shuts down reading, writing or both on a socket, which stays open.
Definition sys_net.c:501
long sys_setsockopt(int fd, int level, int name, const void *val, socklen_t len)
Implements setsockopt(): sets a socket option.
Definition sys_net.c:470
static long socket_name(int fd, struct sockaddr *addr, socklen_t *len, int peer)
Gets a socket's local address or its peer's, for getsockname() and getpeername(), and copies it out.
Definition sys_net.c:365
long sys_listen(int fd, int backlog)
Implements listen(): makes a socket accept connections.
Definition sys_net.c:221
long sys_bind(int fd, const struct sockaddr *addr, socklen_t len)
Implements bind(): gives a socket its local address.
Definition sys_net.c:161
long int ssize_t
Definition types.h:12
static int uaccess_check(const void *ptr, size_t len)
Checks that [ptr, ptr + len) is in user space.
Definition uaccess.h:27
struct sockaddr_un un
Definition sys_net.c:53
struct sockaddr sa
Definition sys_net.c:52