PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
local.c
Go to the documentation of this file.
1#include "local.h"
2
3#include "local_conn.h"
4#include "local_listen.h"
5
7#include <kernel/fs/netfs.h>
8#include <kernel/fs/path.h>
9#include <kernel/log/log.h>
10#include <kernel/log/panic.h>
12#include <kernel/sched/wait.h>
13#include <kernel/sync/lock.h>
14#include <kernel/utils/fifo.h>
15#include <kernel/utils/ref.h>
16
17#include <stdlib.h>
18#include <sys/fs.h>
19#include <sys/list.h>
20
22{
23 if (data->listen == NULL)
24 {
25 return NULL;
26 }
27
28 return REF(data->listen);
29}
30
32{
33 if (data->conn == NULL)
34 {
35 return NULL;
36 }
37
38 return REF(data->conn);
39}
40
42{
43 if (sock->type != SOCKET_SEQPACKET)
44 {
45 errno = EINVAL;
46 return ERR;
47 }
48
50 if (data == NULL)
51 {
52 return ERR;
53 }
54 sock->data = data;
55 return 0;
56}
57
58static void local_socket_deinit(socket_t* sock)
59{
60 local_socket_t* data = sock->data;
61 if (data == NULL)
62 {
63 return;
64 }
65
66 switch (sock->state)
67 {
68 default:
69 break;
70 }
71
72 if (data->listen != NULL)
73 {
74 lock_acquire(&data->listen->lock);
75 data->listen->isClosed = true;
76 wait_unblock(&data->listen->waitQueue, WAIT_ALL, EOK);
77 lock_release(&data->listen->lock);
78 UNREF(data->listen);
79 }
80
81 if (data->conn != NULL)
82 {
83 lock_acquire(&data->conn->lock);
84 data->conn->isClosed = true;
85 wait_unblock(&data->conn->waitQueue, WAIT_ALL, EOK);
86 lock_release(&data->conn->lock);
87 UNREF(data->conn);
88 }
89
90 free(data);
91 sock->data = NULL;
92}
93
95{
96 local_socket_t* data = sock->data;
97 if (data == NULL)
98 {
99 errno = EINVAL;
100 return ERR;
101 }
102
103 if (data->listen != NULL)
104 {
105 errno = EINVAL;
106 return ERR;
107 }
108
109 local_listen_t* listen = local_listen_new(sock->address);
110 if (listen == NULL)
111 {
112 return ERR;
113 }
114
115 data->listen = listen;
116 return 0;
117}
118
120{
121 local_socket_t* data = sock->data;
122 if (data == NULL)
123 {
124 errno = EINVAL;
125 return ERR;
126 }
127
128 local_listen_t* listen = data->listen;
129 if (listen == NULL)
130 {
131 errno = EINVAL;
132 return ERR;
133 }
134 LOCK_SCOPE(&listen->lock);
135
136 if (backlog < LOCAL_MAX_BACKLOG)
137 {
138 listen->maxBacklog = backlog;
139 }
140
141 listen->isClosed = false;
142 return 0;
143}
144
146{
147 local_socket_t* data = sock->data;
148 if (data == NULL)
149 {
150 errno = EINVAL;
151 return ERR;
152 }
153
154 if (data->conn != NULL)
155 {
156 errno = EISCONN;
157 return ERR;
158 }
159
161 if (listen == NULL)
162 {
164 return ERR;
165 }
166 UNREF_DEFER(listen);
167
168 local_conn_t* conn = local_conn_new(listen);
169 if (conn == NULL)
170 {
171 return ERR;
172 }
173 UNREF_DEFER(conn);
174
175 LOCK_SCOPE(&listen->lock);
176
177 if (listen->isClosed)
178 {
180 return ERR;
181 }
182
183 if (listen->pendingAmount >= listen->maxBacklog)
184 {
186 return ERR;
187 }
188
189 listen->pendingAmount++;
190 list_push_back(&listen->backlog, &conn->entry);
191
193
194 data->conn = REF(conn);
195 data->isServer = false;
196 return 0;
197}
198
200{
201 local_socket_t* data = sock->data;
202 if (data == NULL)
203 {
204 errno = EINVAL;
205 return ERR;
206 }
207
209 if (listen == NULL)
210 {
211 errno = EINVAL;
212 return ERR;
213 }
214 UNREF_DEFER(listen);
215
216 local_conn_t* conn = NULL;
217 while (true)
218 {
219 LOCK_SCOPE(&listen->lock);
220
221 if (listen->isClosed)
222 {
224 return ERR;
225 }
226
227 if (!list_is_empty(&listen->backlog))
228 {
229 list_entry_t* entry = list_pop_front(&listen->backlog);
230 local_conn_t* container = CONTAINER_OF(entry, local_conn_t, entry);
231 conn = REF(container);
232 listen->pendingAmount--;
233 break;
234 }
235
236 if (mode & MODE_NONBLOCK)
237 {
239 return ERR;
240 }
241
242 if (WAIT_BLOCK_LOCK(&listen->waitQueue, &listen->lock, listen->isClosed || !list_is_empty(&listen->backlog)) ==
243 ERR)
244 {
245 return ERR;
246 }
247 }
248 UNREF_DEFER(conn);
249
250 assert(conn != NULL);
251
252 local_socket_t* newData = newSock->data;
253 if (newData == NULL)
254 {
255 errno = EINVAL;
256 return ERR;
257 }
258 newData->conn = REF(conn);
259 newData->isServer = true;
260
261 return 0;
262}
263
264static size_t local_socket_send(socket_t* sock, const void* buffer, size_t count, size_t* offset, mode_t mode)
265{
266 UNUSED(offset);
267
268 local_socket_t* data = sock->data;
269 if (data == NULL)
270 {
271 errno = EINVAL;
272 return ERR;
273 }
274
276 if (conn == NULL)
277 {
279 return ERR;
280 }
281 UNREF_DEFER(conn);
282 LOCK_SCOPE(&conn->lock);
283
284 if (conn->isClosed)
285 {
286 errno = EPIPE;
287 return ERR;
288 }
289
291 {
292 errno = EMSGSIZE;
293 return ERR;
294 }
295
296 fifo_t* ring = data->isServer ? &conn->serverToClient : &conn->clientToServer;
297
299
300 size_t totalSize = sizeof(local_packet_header_t) + count;
301 while (fifo_bytes_writeable(ring) < totalSize)
302 {
303 if (conn->isClosed)
304 {
305 errno = EPIPE;
306 return ERR;
307 }
308 if (mode & MODE_NONBLOCK)
309 {
310 errno = EAGAIN;
311 return ERR;
312 }
313 if (WAIT_BLOCK_LOCK(&conn->waitQueue, &conn->lock, conn->isClosed || fifo_bytes_writeable(ring) >= totalSize) ==
314 ERR)
315 {
316 return ERR;
317 }
318 if (conn->isClosed)
319 {
320 errno = EPIPE;
321 return ERR;
322 }
323 }
324
325 fifo_write(ring, &header, sizeof(local_packet_header_t));
326 fifo_write(ring, buffer, count);
327
329 return count;
330}
331
332static size_t local_socket_recv(socket_t* sock, void* buffer, size_t count, size_t* offset, mode_t mode)
333{
334 UNUSED(offset);
335
336 local_socket_t* data = sock->data;
337 if (data == NULL)
338 {
339 errno = EINVAL;
340 return ERR;
341 }
342
344 if (conn == NULL)
345 {
347 return ERR;
348 }
349 UNREF_DEFER(conn);
350 LOCK_SCOPE(&conn->lock);
351
352 fifo_t* ring = data->isServer ? &conn->clientToServer : &conn->serverToClient;
353
354 while (fifo_bytes_readable(ring) < sizeof(local_packet_header_t))
355 {
356 if (conn->isClosed)
357 {
358 return 0; // EOF
359 }
360 if (mode & MODE_NONBLOCK)
361 {
363 return ERR;
364 }
365 if (WAIT_BLOCK_LOCK(&conn->waitQueue, &conn->lock,
366 conn->isClosed || fifo_bytes_readable(ring) >= sizeof(local_packet_header_t)) == ERR)
367 {
368 return ERR;
369 }
370 }
371
373 fifo_read(ring, &header, sizeof(local_packet_header_t));
374
375 if (header.magic != LOCAL_PACKET_MAGIC)
376 {
377 errno = EBADMSG;
378 conn->isClosed = true;
380 return ERR;
381 }
382
383 if (header.size > LOCAL_MAX_PACKET_SIZE)
384 {
385 errno = EMSGSIZE;
386 conn->isClosed = true;
388 return ERR;
389 }
390
391 size_t readCount = header.size < count ? header.size : count;
392 fifo_read(ring, buffer, readCount);
393
394 if (header.size > readCount)
395 {
396 uint64_t remaining = header.size - readCount;
397 char temp[128];
398 while (remaining > 0)
399 {
400 uint64_t toRead = remaining < sizeof(temp) ? remaining : sizeof(temp);
401 fifo_read(ring, temp, toRead);
402 remaining -= toRead;
403 }
404 }
406 return readCount;
407}
408
410{
411 local_socket_t* data = sock->data;
412 if (data == NULL)
413 {
414 errno = EINVAL;
415 return NULL;
416 }
417
418 switch (sock->state)
419 {
420 case SOCKET_LISTENING:
421 {
422 local_listen_t* listen = data->listen;
423 if (listen == NULL)
424 {
425 *revents |= POLLERR;
426 return NULL;
427 }
428
429 LOCK_SCOPE(&listen->lock);
430 if (listen->isClosed)
431 {
432 *revents |= POLLERR;
433 }
434 else if (listen->pendingAmount > 0)
435 {
436 *revents |= POLLIN;
437 }
438
439 return &listen->waitQueue;
440 }
441 case SOCKET_CONNECTED:
442 {
443 local_conn_t* conn = data->conn;
444 if (conn == NULL)
445 {
446 *revents |= POLLERR;
447 return NULL;
448 }
449
450 LOCK_SCOPE(&conn->lock);
451 if (conn->isClosed)
452 {
453 *revents |= POLLHUP;
454 }
455 else
456 {
457 fifo_t* readRing = data->isServer ? &conn->clientToServer : &conn->serverToClient;
458 fifo_t* writeRing = data->isServer ? &conn->serverToClient : &conn->clientToServer;
459
460 if (fifo_bytes_readable(readRing) >= sizeof(local_packet_header_t))
461 {
462 *revents |= POLLIN;
463 }
464
465 if (fifo_bytes_writeable(writeRing) >= sizeof(local_packet_header_t) + 1)
466 {
467 *revents |= POLLOUT;
468 }
469 }
470
471 return &conn->waitQueue;
472 }
473 default:
474 errno = EINVAL;
475 return NULL;
476 }
477}
478
480 .name = "local",
481 .init = local_socket_init,
482 .deinit = local_socket_deinit,
483 .bind = local_socket_bind,
484 .listen = local_socket_listen,
485 .connect = local_socket_connect,
486 .accept = local_socket_accept,
487 .send = local_socket_send,
488 .recv = local_socket_recv,
489 .poll = local_socket_poll,
490};
491
493{
494 switch (event->type)
495 {
498 {
499 return ERR;
500 }
501 break;
504 break;
505 default:
506 break;
507 }
508
509 return 0;
510}
511
512MODULE_INFO("Local Networking", "Kai Norberg", "Local networking module", OS_VERSION, "MIT", "BOOT_ALWAYS");
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static fd_t data
Definition dwm.c:21
uint64_t netfs_family_register(netfs_family_t *family)
Register a network family.
Definition netfs.c:813
void netfs_family_unregister(netfs_family_t *family)
Unregister a network family.
Definition netfs.c:832
@ SOCKET_LISTENING
Definition netfs.h:114
@ SOCKET_CONNECTED
Definition netfs.h:116
@ SOCKET_SEQPACKET
A sequenced, reliable, two-way connection-based packet stream.
Definition netfs.h:100
mode_t
Path flags and permissions.
Definition path.h:79
@ MODE_NONBLOCK
Definition path.h:84
#define MODULE_INFO(_name, _author, _description, _version, _licence, _deviceTypes)
Macro to define module information.
Definition module.h:200
@ MODULE_EVENT_LOAD
Definition module.h:239
@ MODULE_EVENT_UNLOAD
Definition module.h:245
uint64_t wait_unblock(wait_queue_t *queue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:307
#define WAIT_ALL
Used to indicate that the wait should unblock all waiting threads.
Definition wait.h:43
#define WAIT_BLOCK_LOCK(queue, lock, condition)
Blocks until the condition is true, condition will be tested on every wakeup. Will release the lock b...
Definition wait.h:109
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:58
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
static size_t fifo_read(fifo_t *fifo, void *buffer, size_t count)
Read data from a fifo buffer at a specific offset.
Definition fifo.h:113
static size_t fifo_bytes_writeable(const fifo_t *fifo)
Return the number of bytes available for writing in a fifo buffer.
Definition fifo.h:95
static size_t fifo_write(fifo_t *fifo, const void *buffer, size_t count)
Write data to the fifo buffer.
Definition fifo.h:155
static size_t fifo_bytes_readable(const fifo_t *fifo)
Return the number of bytes available for reading in a fifo buffer.
Definition fifo.h:79
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:122
#define REF(ptr)
Increment reference count.
Definition ref.h:82
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
#define EISCONN
Transport endpoint is already connected.
Definition errno.h:557
#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 EWOULDBLOCK
Operation would block.
Definition errno.h:237
#define EPIPE
Broken pipe.
Definition errno.h:192
#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
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
poll_events_t
Poll events type.
Definition fs.h:286
@ POLLIN
File descriptor is ready to read.
Definition fs.h:288
@ POLLHUP
Stream socket peer closed connection, or shut down writing of connection.
Definition fs.h:291
@ POLLOUT
File descriptor is ready to write.
Definition fs.h:289
@ POLLERR
File descriptor caused an error.
Definition fs.h:290
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:366
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
local_conn_t * local_conn_new(local_listen_t *listen)
Allocate and initialize a new local connection.
Definition local_conn.c:12
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.
#define LOCAL_MAX_PACKET_SIZE
The maximum size of a packet allowed to be sent/received via local sockets.
Definition local.h:28
#define LOCAL_PACKET_MAGIC
Magic number for local socket packets, used for validation.
Definition local.h:38
#define LOCAL_MAX_BACKLOG
The maximum backlog of connections for a local listener.
Definition local.h:33
static uint64_t offset
Definition screen.c:19
static netfs_family_t local
Definition local.c:479
static local_conn_t * local_socket_get_conn(local_socket_t *data)
Definition local.c:31
static local_listen_t * local_socket_get_listen(local_socket_t *data)
Definition local.c:21
static uint64_t local_socket_accept(socket_t *sock, socket_t *newSock, mode_t mode)
Definition local.c:199
static uint64_t local_socket_connect(socket_t *sock)
Definition local.c:145
static size_t local_socket_send(socket_t *sock, const void *buffer, size_t count, size_t *offset, mode_t mode)
Definition local.c:264
static void local_socket_deinit(socket_t *sock)
Definition local.c:58
uint64_t _module_procedure(const module_event_t *event)
Definition local.c:492
static uint64_t local_socket_init(socket_t *sock)
Definition local.c:41
static wait_queue_t * local_socket_poll(socket_t *sock, poll_events_t *revents)
Definition local.c:409
static uint64_t local_socket_listen(socket_t *sock, uint32_t backlog)
Definition local.c:119
static size_t local_socket_recv(socket_t *sock, void *buffer, size_t count, size_t *offset, mode_t mode)
Definition local.c:332
static uint64_t local_socket_bind(socket_t *sock)
Definition local.c:94
static atomic_long count
Definition main.c:11
__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
FIFO Buffer.
Definition fifo.h:20
A entry in a doubly linked list.
Definition list.h:37
Local Connection structure.
Definition local_conn.h:29
fifo_t clientToServer
Definition local_conn.h:32
lock_t lock
Definition local_conn.h:38
fifo_t serverToClient
Definition local_conn.h:34
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:45
Local socket data structure. struct local_socket_t.
Definition local.h:57
bool isServer
Definition local.h:60
local_conn_t * conn
Definition local.h:59
module_event_type_t type
Definition module.h:268
Socket Family structure.
Definition netfs.h:144
const char * name
Definition netfs.h:145
Socket structure.
Definition netfs.h:126
char address[MAX_PATH]
Definition netfs.h:130
socket_type_t type
Definition netfs.h:132
socket_state_t state
Definition netfs.h:133
void * data
Definition netfs.h:135
The primitive that threads block on.
Definition wait.h:185