PatchworkOS
Loading...
Searching...
No Matches
local.c
Go to the documentation of this file.
2
3#include <kernel/fs/path.h>
4#include <kernel/log/log.h>
5#include <kernel/log/panic.h>
8#include <kernel/net/socket.h>
11#include <kernel/sched/wait.h>
12#include <kernel/sync/lock.h>
13#include <kernel/utils/ref.h>
14#include <kernel/utils/ring.h>
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/io.h>
20#include <sys/list.h>
21
23{
24 LOCK_SCOPE(&data->lock);
25
26 if (data->listen.listen == NULL)
27 {
28 return NULL;
29 }
30
31 return REF(data->listen.listen);
32}
33
35{
36 LOCK_SCOPE(&data->lock);
37
38 if (data->conn.conn == NULL)
39 {
40 return NULL;
41 }
42
43 return REF(data->conn.conn);
44}
45
47{
49 if (data == NULL)
50 {
51 return ERR;
52 }
53 lock_init(&data->lock);
54 sock->private = data;
55 return 0;
56}
57
58static void local_socket_deinit(socket_t* sock)
59{
61 if (data == NULL)
62 {
63 return;
64 }
65
66 lock_acquire(&data->lock);
67
68 switch (sock->currentState)
69 {
71 if (data->listen.listen != NULL)
72 {
73 lock_acquire(&data->listen.listen->lock);
74 data->listen.listen->isClosed = true;
75 wait_unblock(&data->listen.listen->waitQueue, WAIT_ALL, EOK);
76 lock_release(&data->listen.listen->lock);
77
78 DEREF(data->listen.listen);
79 data->listen.listen = NULL;
80 }
81 break;
83 if (data->conn.conn != NULL)
84 {
85 lock_acquire(&data->conn.conn->lock);
86 data->conn.conn->isClosed = true;
87 wait_unblock(&data->conn.conn->waitQueue, WAIT_ALL, EOK);
88 lock_release(&data->conn.conn->lock);
89
90 DEREF(data->conn.conn);
91 data->conn.conn = NULL;
92 }
93 break;
94 default:
95 break;
96 }
97
98 lock_release(&data->lock);
99
100 free(data);
101 sock->private = NULL;
102}
103
104static uint64_t local_socket_bind(socket_t* sock, const char* address)
105{
106 if (address[0] == '\0')
107 {
108 errno = EINVAL;
109 return ERR;
110 }
111
113 if (data == NULL)
114 {
115 errno = EINVAL;
116 return ERR;
117 }
118 LOCK_SCOPE(&data->lock);
119
121 if (listen == NULL)
122 {
123 return ERR;
124 }
125 DEREF_DEFER(listen);
126
127 data->listen.listen = REF(listen);
128 return 0;
129}
130
132{
133 if (backlog == 0)
134 {
135 errno = EINVAL;
136 return ERR;
137 }
138
140 if (data == NULL)
141 {
142 errno = EINVAL;
143 return ERR;
144 }
145 LOCK_SCOPE(&data->lock);
146
147 local_listen_t* listen = data->listen.listen;
148 if (listen == NULL)
149 {
150 errno = EINVAL;
151 return ERR;
152 }
153 LOCK_SCOPE(&listen->lock);
154
155 if (backlog < LOCAL_MAX_BACKLOG)
156 {
157 listen->maxBacklog = backlog;
158 }
159
160 listen->isClosed = false;
161 return 0;
162}
163
165{
166 if (address[0] == '\0')
167 {
168 errno = EINVAL;
169 return ERR;
170 }
171
173 if (data == NULL)
174 {
175 errno = EINVAL;
176 return ERR;
177 }
178 LOCK_SCOPE(&data->lock);
179
181 if (listen == NULL)
182 {
184 return ERR;
185 }
186 DEREF_DEFER(listen);
187
188 local_conn_t* conn = local_conn_new(listen);
189 if (conn == NULL)
190 {
191 return ERR;
192 }
193 DEREF_DEFER(conn);
194
195 LOCK_SCOPE(&listen->lock);
196
197 if (listen->isClosed)
198 {
200 return ERR;
201 }
202
203 if (listen->pendingAmount >= listen->maxBacklog)
204 {
206 return ERR;
207 }
208
209 listen->pendingAmount++;
210 list_push(&listen->backlog, &conn->entry);
211
213
214 data->conn.conn = REF(conn);
215 data->conn.isServer = false;
216 return 0;
217}
218
220{
222 if (data == NULL)
223 {
224 errno = EINVAL;
225 return ERR;
226 }
227
229 if (listen == NULL)
230 {
231 errno = EINVAL;
232 return ERR;
233 }
234 DEREF_DEFER(listen);
235
236 local_conn_t* conn = NULL;
237 while (true)
238 {
239 LOCK_SCOPE(&listen->lock);
240
241 if (listen->isClosed)
242 {
244 return ERR;
245 }
246
247 if (!list_is_empty(&listen->backlog))
248 {
249 list_entry_t* entry = list_pop(&listen->backlog);
250 local_conn_t* container = CONTAINER_OF(entry, local_conn_t, entry);
251 conn = REF(container);
252 listen->pendingAmount--;
253 break;
254 }
255
256 if (sock->flags & PATH_NONBLOCK)
257 {
259 return ERR;
260 }
261
262 if (WAIT_BLOCK_LOCK(&listen->waitQueue, &listen->lock, listen->isClosed || !list_is_empty(&listen->backlog)) ==
263 ERR)
264 {
265 return ERR;
266 }
267 }
268 DEREF_DEFER(conn);
269
270 assert(conn != NULL);
271
272 local_socket_data_t* newData = newSock->private;
273 if (newData == NULL)
274 {
275 errno = EINVAL;
276 return ERR;
277 }
278 lock_acquire(&newData->lock);
279 newData->conn.conn = REF(conn);
280 newData->conn.isServer = true;
281 lock_release(&newData->lock);
282
283 return 0;
284}
285
286static uint64_t local_socket_send(socket_t* sock, const void* buffer, uint64_t count, uint64_t* offset)
287{
288 (void)offset; // Unused
289
291 if (data == NULL)
292 {
293 errno = EINVAL;
294 return ERR;
295 }
296
298 if (conn == NULL)
299 {
301 return ERR;
302 }
303 DEREF_DEFER(conn);
304 LOCK_SCOPE(&conn->lock);
305
306 if (conn->isClosed)
307 {
309 return ERR;
310 }
311
313 {
314 errno = EMSGSIZE;
315 return ERR;
316 }
317
318 ring_t* ring = data->conn.isServer ? &conn->serverToClient : &conn->clientToServer;
319
321
322 uint64_t totalSize = sizeof(local_packet_header_t) + count;
323 if (ring_free_length(ring) < totalSize)
324 {
325 if (sock->flags & PATH_NONBLOCK)
326 {
327 errno = EAGAIN;
328 return ERR;
329 }
330
331 if (conn->isClosed)
332 {
334 return ERR;
335 }
336
337 if (WAIT_BLOCK_LOCK(&conn->waitQueue, &conn->lock, conn->isClosed || ring_free_length(ring) >= totalSize) ==
338 ERR)
339 {
340 return ERR;
341 }
342 }
343
344 if (ring_write(ring, &header, sizeof(local_packet_header_t)) != sizeof(local_packet_header_t) ||
346 {
347 errno = EIO;
348 return ERR;
349 }
350
352 return count;
353}
354
356{
357 (void)offset; // Unused
358
360 if (data == NULL)
361 {
362 errno = EINVAL;
363 return ERR;
364 }
365
367 if (conn == NULL)
368 {
370 return ERR;
371 }
372 DEREF_DEFER(conn);
373 LOCK_SCOPE(&conn->lock);
374
375 ring_t* ring = data->conn.isServer ? &conn->clientToServer : &conn->serverToClient;
376
377 if (conn->isClosed)
378 {
379 return 0; // EOF
380 }
381
383 {
384 if (sock->flags & PATH_NONBLOCK)
385 {
387 return ERR;
388 }
389
390 if (WAIT_BLOCK_LOCK(&conn->waitQueue, &conn->lock,
391 conn->isClosed || ring_data_length(ring) >= sizeof(local_packet_header_t)) == ERR)
392 {
393 errno = EINTR;
394 return ERR;
395 }
396 }
397
399 if (ring_read(ring, &header, sizeof(local_packet_header_t)) != sizeof(local_packet_header_t))
400 {
401 errno = EIO;
402 return ERR;
403 }
404
405 if (header.magic != LOCAL_PACKET_MAGIC)
406 {
407 errno = EBADMSG;
408 conn->isClosed = true;
410 return ERR;
411 }
412
413 if (header.size > LOCAL_MAX_PACKET_SIZE)
414 {
415 errno = EMSGSIZE;
416 conn->isClosed = true;
418 return ERR;
419 }
420
421 uint64_t readCount = header.size < count ? header.size : count;
422 if (ring_read_at(ring, 0, buffer, readCount) != readCount)
423 {
424 errno = EIO;
425 return ERR;
426 }
427
428 // Consume entire packet.
431 return readCount;
432}
433
435{
437 if (data == NULL)
438 {
439 errno = EINVAL;
440 return NULL;
441 }
442 LOCK_SCOPE(&data->lock);
443
444 switch (sock->currentState)
445 {
446 case SOCKET_LISTENING:
447 {
448 local_listen_t* listen = data->listen.listen;
449 if (listen == NULL)
450 {
451 *revents |= POLLERR;
452 return NULL;
453 }
454
455 LOCK_SCOPE(&listen->lock);
456 if (listen->isClosed)
457 {
458 *revents |= POLLERR;
459 }
460 else if (listen->pendingAmount > 0)
461 {
462 *revents |= POLLIN;
463 }
464
465 return &listen->waitQueue;
466 }
467 case SOCKET_CONNECTED:
468 {
469 local_conn_t* conn = data->conn.conn;
470 if (conn == NULL)
471 {
472 *revents |= POLLERR;
473 return NULL;
474 }
475
476 LOCK_SCOPE(&conn->lock);
477 if (conn->isClosed)
478 {
479 *revents |= POLLHUP;
480 }
481 else
482 {
483 ring_t* readRing = data->conn.isServer ? &conn->clientToServer : &conn->serverToClient;
484 ring_t* writeRing = data->conn.isServer ? &conn->serverToClient : &conn->clientToServer;
485
486 if (ring_data_length(readRing) >= sizeof(local_packet_header_t))
487 {
488 *revents |= POLLIN;
489 }
490
491 if (ring_free_length(writeRing) >= sizeof(local_packet_header_t) + 1)
492 {
493 *revents |= POLLOUT;
494 }
495 }
496
497 return &conn->waitQueue;
498 }
499 default:
500 errno = EINVAL;
501 return NULL;
502 }
503}
504
507 .deinit = local_socket_deinit,
508 .bind = local_socket_bind,
509 .listen = local_socket_listen,
510 .connect = local_socket_connect,
511 .accept = local_socket_accept,
512 .send = local_socket_send,
513 .recv = local_socket_recv,
514 .poll = local_socket_poll,
515};
516
518{
520 {
521 panic(NULL, "Failed to register local socket family");
522 }
523
525}
#define assert(expression)
Definition assert.h:29
static fd_t data
Definition dwm.c:21
@ PATH_NONBLOCK
Definition path.h:85
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
local_conn_t * local_conn_new(local_listen_t *listen)
Allocate and initialize a new local connection.
Definition local_conn.c:14
local_listen_t * local_listen_find(const char *address)
Find a local listener by its address.
local_listen_t * local_listen_new(const char *address)
Allocate and initialize a new local listener.
void local_listen_dir_init(void)
Initialize the /net/local/listen/ directory.
void net_local_init(void)
Initialize the local networking subsystem.
Definition local.c:517
#define LOCAL_MAX_PACKET_SIZE
The maximum size of a packet allowed to be sent/received via local sockets.
Definition local.h:31
#define LOCAL_PACKET_MAGIC
Magic number for local socket packets, used for validation.
Definition local.h:41
#define LOCAL_MAX_BACKLOG
The maximum backlog of connections for a local listener.
Definition local.h:36
uint64_t socket_family_register(const socket_family_ops_t *ops, const char *name, socket_type_t supportedTypes)
Register a socket family.
@ SOCKET_SEQPACKET
Definition socket_type.h:19
@ SOCKET_LISTENING
Definition socket.h:68
@ SOCKET_CONNECTED
Definition socket.h:70
uint64_t wait_unblock(wait_queue_t *waitQueue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:168
#define WAIT_ALL
Wait for all.
Definition wait.h:26
#define WAIT_BLOCK_LOCK(waitQueue, lock, condition)
Block with a spinlock.
Definition wait.h:101
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:80
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:140
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:97
#define DEREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
static uint64_t ring_write(ring_t *ring, const void *buffer, uint64_t count)
Write data to the ring buffer.
Definition ring.h:85
static void ring_move_read_forward(ring_t *ring, uint64_t offset)
Move the read index forward by a specified offset.
Definition ring.h:191
static uint64_t ring_free_length(const ring_t *ring)
Get the length of free space in the ring buffer.
Definition ring.h:69
static uint64_t ring_data_length(const ring_t *ring)
Get the length of data currently stored in the ring buffer.
Definition ring.h:58
static uint64_t ring_read(ring_t *ring, void *buffer, uint64_t count)
Read data from the ring buffer.
Definition ring.h:121
static uint64_t ring_read_at(const ring_t *ring, uint64_t offset, void *buffer, uint64_t count)
Read data from the ring buffer at a specific offset without modifying the read index.
Definition ring.h:156
#define EBADMSG
Not a data message.
Definition errno.h:397
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ECONNABORTED
Software caused connection abort.
Definition errno.h:542
#define EINTR
Interrupted system call.
Definition errno.h:52
#define EWOULDBLOCK
Operation would block.
Definition errno.h:237
#define EIO
I/O error.
Definition errno.h:57
#define ECONNREFUSED
Connection refused.
Definition errno.h:582
#define errno
Error number variable.
Definition errno.h:27
#define EOK
No error.
Definition errno.h:32
#define ECONNRESET
Connection reset by peer.
Definition errno.h:547
#define EMSGSIZE
Message too long.
Definition errno.h:477
#define EAGAIN
Try again.
Definition errno.h:87
poll_events_t
Poll events type.
Definition io.h:288
@ POLLIN
File descriptor is ready to read.
Definition io.h:290
@ POLLHUP
Stream socket peer closed connection, or shut down writing of connection.
Definition io.h:293
@ POLLOUT
File descriptor is ready to write.
Definition io.h:291
@ POLLERR
File descriptor caused an error.
Definition io.h:292
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:229
static list_entry_t * list_pop(list_t *list)
Pops the first entry from the list.
Definition list.h:361
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
static uintptr_t address
Definition hpet.c:12
static ring_t ring
Definition log_file.c:16
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static uint64_t local_socket_send(socket_t *sock, const void *buffer, uint64_t count, uint64_t *offset)
Definition local.c:286
static uint64_t local_socket_bind(socket_t *sock, const char *address)
Definition local.c:104
static uint64_t local_socket_accept(socket_t *sock, socket_t *newSock)
Definition local.c:219
static local_listen_t * local_socket_data_get_listen(local_socket_data_t *data)
Definition local.c:22
static uint64_t local_socket_connect(socket_t *sock, const char *address)
Definition local.c:164
static uint64_t local_socket_recv(socket_t *sock, void *buffer, uint64_t count, uint64_t *offset)
Definition local.c:355
static local_conn_t * local_socket_data_get_conn(local_socket_data_t *data)
Definition local.c:34
static void local_socket_deinit(socket_t *sock)
Definition local.c:58
static socket_family_ops_t ops
Definition local.c:505
static uint64_t local_socket_init(socket_t *sock)
Definition local.c:46
static wait_queue_t * local_socket_poll(socket_t *sock, poll_events_t *revents)
Definition local.c:434
static uint64_t local_socket_listen(socket_t *sock, uint32_t backlog)
Definition local.c:131
static atomic_long count
Definition main.c:9
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * calloc(size_t nmemb, size_t size)
Definition calloc.c:6
_PUBLIC void free(void *ptr)
Definition free.c:11
A entry in a doubly linked list.
Definition list.h:38
Local Connection structure.
Definition local_conn.h:29
ring_t serverToClient
Definition local_conn.h:34
lock_t lock
Definition local_conn.h:38
ring_t clientToServer
Definition local_conn.h:32
wait_queue_t waitQueue
Definition local_conn.h:39
list_entry_t entry
Definition local_conn.h:31
Local Listener structure.
uint32_t maxBacklog
wait_queue_t waitQueue
uint32_t pendingAmount
Local packet header structure. struct local_packet_header_t.
Definition local.h:48
Local socket data structure. struct local_socket_data_t.
Definition local.h:60
local_conn_t * conn
Definition local.h:68
Ring buffer structure.
Definition ring.h:19
Socket Family operations structure.
uint64_t(* init)(socket_t *sock)
Socket structure.
Definition socket.h:81
void * private
Definition socket.h:88
path_flags_t flags
Definition socket.h:87
socket_state_t currentState
Definition socket.h:89
Wait queue structure.
Definition wait.h:166