PatchworkOS
Loading...
Searching...
No Matches
socket.c
Go to the documentation of this file.
1#include <kernel/net/socket.h>
2
3#include <kernel/fs/ctl.h>
4#include <kernel/fs/file.h>
5#include <kernel/fs/mount.h>
6#include <kernel/fs/path.h>
10#include <kernel/sched/wait.h>
11#include <kernel/sync/lock.h>
12#include <kernel/sync/mutex.h>
13#include <kernel/sync/rwmutex.h>
14
15#include <errno.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <sys/io.h>
19
21{
22 socket_t* sock = file->inode->private;
23 if (sock == NULL || sock->family == NULL)
24 {
25 errno = EINVAL;
26 return ERR;
27 }
28
29 file->private = REF(sock);
30 return 0;
31}
32
34{
35 socket_t* sock = file->private;
36 if (sock == NULL)
37 {
38 return;
39 }
40
41 DEREF(sock);
42}
43
44static uint64_t socket_data_read(file_t* file, void* buf, size_t count, uint64_t* offset)
45{
46 socket_t* sock = file->private;
47 if (sock == NULL || sock->family == NULL)
48 {
49 errno = EINVAL;
50 return ERR;
51 }
52
53 if (sock->family->ops->recv == NULL)
54 {
55 errno = ENOSYS;
56 return ERR;
57 }
58
60
61 if (sock->currentState != SOCKET_CONNECTED)
62 {
64 return ERR;
65 }
66
67 return sock->family->ops->recv(sock, buf, count, offset);
68}
69
70static uint64_t socket_data_write(file_t* file, const void* buf, size_t count, uint64_t* offset)
71{
72 socket_t* sock = file->private;
73 if (sock == NULL || sock->family == NULL)
74 {
75 errno = EINVAL;
76 return ERR;
77 }
78
79 if (sock->family->ops->send == NULL)
80 {
81 errno = ENOSYS;
82 return ERR;
83 }
84
86
87 if (sock->currentState != SOCKET_CONNECTED)
88 {
90 return ERR;
91 }
92
93 return sock->family->ops->send(sock, buf, count, offset);
94}
95
97{
98 socket_t* sock = file->private;
99 if (sock == NULL || sock->family == NULL)
100 {
101 errno = EINVAL;
102 return NULL;
103 }
104
105 if (sock->family->ops->poll == NULL)
106 {
107 errno = ENOSYS;
108 return NULL;
109 }
110
111 return sock->family->ops->poll(sock, revents);
112}
113
116 .close = socket_data_close,
117 .read = socket_data_read,
118 .write = socket_data_write,
119 .poll = socket_data_poll,
120};
121
122static uint64_t socket_ctl_bind(file_t* file, uint64_t argc, const char** argv)
123{
124 (void)argc; // Unused
125
126 socket_t* sock = file->inode->private;
127 if (sock == NULL || sock->family == NULL)
128 {
129 errno = EINVAL;
130 return ERR;
131 }
132
133 if (sock->family->ops->bind == NULL)
134 {
135 errno = ENOSYS;
136 return ERR;
137 }
138
140 {
141 return ERR;
142 }
143
144 uint64_t result = sock->family->ops->bind(sock, argv[1]);
145 socket_end_transition(sock, result);
146 return result;
147}
148
149static uint64_t socket_ctl_listen(file_t* file, uint64_t argc, const char** argv)
150{
151 socket_t* sock = file->inode->private;
152 if (sock == NULL || sock->family == NULL)
153 {
154 errno = EINVAL;
155 return ERR;
156 }
157
158 if (sock->family->ops->listen == NULL)
159 {
160 errno = ENOSYS;
161 return ERR;
162 }
163
164 uint32_t backlog = 128;
165 if (argc > 1)
166 {
167 backlog = atol(argv[1]);
168 }
169
171 {
172 return ERR;
173 }
174
175 uint64_t result = sock->family->ops->listen(sock, backlog);
176 socket_end_transition(sock, result);
177 return result;
178}
179
180static uint64_t socket_ctl_connect(file_t* file, uint64_t argc, const char** argv)
181{
182 (void)argc; // Unused
183
184 socket_t* sock = file->inode->private;
185 if (sock == NULL || sock->family == NULL)
186 {
187 errno = EINVAL;
188 return ERR;
189 }
190
191 if (sock->family->ops->connect == NULL)
192 {
193 errno = ENOSYS;
194 return ERR;
195 }
196
198 {
199 return ERR;
200 }
201
202 uint64_t result = sock->family->ops->connect(sock, argv[1]);
203 if (result == ERR)
204 {
206 return result;
207 }
208
209 // TODO: Needs more verification.
210
211 bool notFinished = (sock->flags & PATH_NONBLOCK) && (result == ERR && errno == EINPROGRESS);
212 if (notFinished) // Non blocking and not yet connected.
213 {
214 socket_end_transition(sock, 0);
215
217 return ERR;
218 }
219
220 // Connection finished immediately.
222
223 socket_end_transition(sock, 0);
224 return 0;
225}
226
228 (ctl_array_t){
229 {"bind", socket_ctl_bind, 2, 2},
230 {"listen", socket_ctl_listen, 1, 2},
231 {"connect", socket_ctl_connect, 2, 2},
232 {0},
233 });
234
236{
237 socket_t* sock = file->inode->private;
238 if (sock == NULL || sock->family == NULL)
239 {
240 errno = EINVAL;
241 return ERR;
242 }
243
244 if (sock->family->ops->accept == NULL)
245 {
246 errno = ENOSYS;
247 return ERR;
248 }
249
251
252 if (sock->currentState != SOCKET_LISTENING)
253 {
254 errno = EINVAL;
255 return ERR;
256 }
257
258 socket_t* newSock = socket_new(sock->family, sock->type, file->flags);
259 if (newSock == NULL)
260 {
261 return ERR;
262 }
263
265 {
266 return ERR;
267 }
268
269 if (sock->family->ops->accept(sock, newSock) == ERR)
270 {
271 socket_end_transition(newSock, ERR);
272 DEREF(newSock);
273 return ERR;
274 }
275
277
278 socket_end_transition(newSock, 0);
279 file->private = newSock;
280 return 0;
281}
282
284{
285 socket_t* sock = file->private;
286 if (sock == NULL)
287 {
288 return;
289 }
290
291 DEREF(sock);
292}
293
296 .close = socket_accept_close,
297 .read = socket_data_read,
298 .write = socket_data_write,
299 .poll = socket_data_poll,
300};
301
302static void socket_inode_cleanup(inode_t* inode)
303{
304 socket_t* sock = inode->private;
305 if (sock == NULL)
306 {
307 return;
308 }
309
310 DEREF(sock);
311}
312
316
320static void socket_free(socket_t* sock)
321{
322 if (sock == NULL)
323 {
324 return;
325 }
326
327 if (sock->family != NULL)
328 {
329 sock->family->ops->deinit(sock);
330 }
331
332 rwmutex_deinit(&sock->mutex);
333 free(sock);
334}
335
336static void socket_unmount(superblock_t* superblock)
337{
338 if (superblock == NULL)
339 {
340 return;
341 }
342
343 socket_t* sock = superblock->private;
344 if (sock == NULL)
345 {
346 return;
347 }
348 DEREF(sock->ctlFile);
349 DEREF(sock->dataFile);
350 DEREF(sock->acceptFile);
351 DEREF(sock);
352 superblock->private = NULL;
353}
354
358
360{
361 if (family == NULL)
362 {
363 errno = EINVAL;
364 return NULL;
365 }
366
367 socket_t* sock = calloc(1, sizeof(socket_t));
368 if (sock == NULL)
369 {
370 errno = ENOMEM;
371 return NULL;
372 }
373
374 ref_init(&sock->ref, socket_free);
375 snprintf(sock->id, sizeof(sock->id), "%llu", atomic_fetch_add(&family->newId, 1));
376 sock->family = family;
377 sock->type = type;
378 sock->flags = flags;
379 sock->private = NULL;
380 rwmutex_init(&sock->mutex);
381 sock->currentState = SOCKET_NEW;
382 sock->nextState = SOCKET_NEW;
383
384 if (family->ops->init(sock) == ERR)
385 {
386 rwmutex_deinit(&sock->mutex);
387 free(sock);
388 return NULL;
389 }
390
391 path_t familyDir = PATH_EMPTY;
392 if (socket_family_get_dir(family, &familyDir) == ERR)
393 {
394 family->ops->deinit(sock);
395 rwmutex_deinit(&sock->mutex);
396 free(sock);
397 return NULL;
398 }
399
400 mount_t* mount = sysfs_mount_new(&familyDir, sock->id, &sched_process()->namespace, &superblockOps);
401 path_put(&familyDir);
402 if (mount == NULL)
403 {
404 family->ops->deinit(sock);
405 rwmutex_deinit(&sock->mutex);
406 free(sock);
407 return NULL;
408 }
409 mount->superblock->private = REF(sock);
410 DEREF(mount);
411
412 sock->ctlFile = sysfs_file_new(mount->root, "ctl", &inodeOps, &ctlOps, REF(sock));
413 if (sock->ctlFile == NULL)
414 {
415 family->ops->deinit(sock);
417 rwmutex_deinit(&sock->mutex);
418 free(sock);
419 return NULL;
420 }
421
422 sock->dataFile = sysfs_file_new(mount->root, "data", &inodeOps, &dataOps, REF(sock));
423 if (sock->dataFile == NULL)
424 {
425 family->ops->deinit(sock);
427 DEREF(sock->ctlFile);
428 rwmutex_deinit(&sock->mutex);
429 free(sock);
430 return NULL;
431 }
432
433 sock->acceptFile = sysfs_file_new(mount->root, "accept", &inodeOps, &acceptOps, REF(sock));
434 if (sock->acceptFile == NULL)
435 {
436 family->ops->deinit(sock);
438 DEREF(sock->ctlFile);
439 DEREF(sock->dataFile);
440 rwmutex_deinit(&sock->mutex);
441 free(sock);
442 return NULL;
443 }
444
445 return sock;
446}
447
449 [SOCKET_NEW] =
450 {
451 [SOCKET_BOUND] = true,
452 [SOCKET_CONNECTING] = true,
453 [SOCKET_CLOSED] = true,
454 },
455 [SOCKET_BOUND] =
456 {
457 [SOCKET_LISTENING] = true,
458 [SOCKET_CONNECTING] = true,
459 [SOCKET_CONNECTED] = true,
460 [SOCKET_CLOSED] = true,
461 },
463 {
464 [SOCKET_CONNECTED] = true,
465 [SOCKET_CLOSED] = true,
466 },
468 {
469 [SOCKET_CONNECTED] = true,
470 },
472 {
473 [SOCKET_CLOSING] = true,
474 },
476 {
477 [SOCKET_CLOSED] = true,
478 },
479 [SOCKET_CLOSED] = {},
480};
481
483{
484 if (from >= SOCKET_STATE_AMOUNT || to >= SOCKET_STATE_AMOUNT || from < 0 || to < 0)
485 {
486 return false;
487 }
488 return validTransitions[from][to];
489}
490
492{
493 if (sock == NULL)
494 {
495 errno = EINVAL;
496 return ERR;
497 }
498
500
501 if (!socket_can_transition(sock->currentState, state))
502 {
504 errno = EINVAL;
505 return ERR;
506 }
507
508 if (sock->currentState == state)
509 {
511 errno = EINVAL;
512 return ERR;
513 }
514
515 sock->nextState = state;
516 return 0;
517}
518
520{
521 sock->currentState = sock->nextState;
522
523 assert(socket_can_transition(sock->currentState, state)); // This should always pass.
524
525 sock->nextState = state;
526}
527
529{
530 if (result != ERR)
531 {
532 sock->currentState = sock->nextState;
533 }
534
535 sock->nextState = sock->currentState;
536
538}
static mount_t * mount
Definition acpi.c:15
#define assert(expression)
Definition assert.h:29
ctl_t ctl_array_t[]
Type definition for an array of ctl commands.
Definition ctl.h:72
#define CTL_STANDARD_OPS_DEFINE(name,...)
Helper macro to define a standard ctl file operations structure.
Definition ctl.h:41
void path_put(path_t *path)
Put a path.
Definition path.c:257
path_flags_t
Path flags.
Definition path.h:83
#define PATH_EMPTY
Helper to create an empty path.
Definition path.h:182
@ PATH_NONBLOCK
Definition path.h:85
uint64_t socket_family_get_dir(socket_family_t *family, path_t *outPath)
Get the directory of a socket family.
socket_type_t
Socket type enumeration.
Definition socket_type.h:18
socket_state_t
Socket states.
Definition socket.h:65
socket_t * socket_new(socket_family_t *family, socket_type_t type, path_flags_t flags)
Create a new socket.
Definition socket.c:359
void socket_continue_transition(socket_t *sock, socket_state_t state)
Without releasing the socket mutex, start a transition to a new target state.
Definition socket.c:519
uint64_t socket_start_transition(socket_t *sock, socket_state_t state)
Starts a socket state transition.
Definition socket.c:491
void socket_end_transition(socket_t *sock, uint64_t result)
Ends a socket state transition.
Definition socket.c:528
@ SOCKET_CLOSED
Definition socket.h:72
@ SOCKET_LISTENING
Definition socket.h:68
@ SOCKET_STATE_AMOUNT
Definition socket.h:73
@ SOCKET_CONNECTED
Definition socket.h:70
@ SOCKET_NEW
Definition socket.h:66
@ SOCKET_CLOSING
Definition socket.h:71
@ SOCKET_BOUND
Definition socket.h:67
@ SOCKET_CONNECTING
Definition socket.h:69
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:164
void rwmutex_write_acquire(rwmutex_t *mtx)
Acquires a rwmutex for writing, blocking until it is available.
Definition rwmutex.c:85
void rwmutex_init(rwmutex_t *mtx)
Initializes a rwmutex.
Definition rwmutex.c:10
#define RWMUTEX_READ_SCOPE(mutex)
Acquires a rwmutex for reading for the reminder of the current scope.
Definition rwmutex.h:21
void rwmutex_deinit(rwmutex_t *mtx)
Deinitializes a rwmutex.
Definition rwmutex.c:20
void rwmutex_write_release(rwmutex_t *mtx)
Releases a rwmutex from writing.
Definition rwmutex.c:124
static void ref_init(ref_t *ref, void *free)
Initialize a reference counter.
Definition ref.h:92
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOSYS
Function not implemented.
Definition errno.h:222
#define ENOMEM
Out of memory.
Definition errno.h:92
#define EINPROGRESS
Operation now in progress.
Definition errno.h:602
#define errno
Error number variable.
Definition errno.h:27
#define ENOTCONN
Transport endpoint is not connected.
Definition errno.h:562
poll_events_t
Poll events type.
Definition io.h:288
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static dentry_t * file
Definition log_file.c:17
static atomic_long count
Definition main.c:9
static inode_ops_t inodeOps
Definition socket.c:313
static file_ops_t acceptOps
Definition socket.c:294
bool socket_can_transition(socket_state_t from, socket_state_t to)
Definition socket.c:482
static const bool validTransitions[SOCKET_STATE_AMOUNT][SOCKET_STATE_AMOUNT]
Definition socket.c:448
static void socket_unmount(superblock_t *superblock)
Definition socket.c:336
static uint64_t socket_accept_open(file_t *file)
Definition socket.c:235
static uint64_t socket_ctl_bind(file_t *file, uint64_t argc, const char **argv)
Definition socket.c:122
static void socket_free(socket_t *sock)
Definition socket.c:320
static wait_queue_t * socket_data_poll(file_t *file, poll_events_t *revents)
Definition socket.c:96
static superblock_ops_t superblockOps
Definition socket.c:355
static file_ops_t dataOps
Definition socket.c:114
static uint64_t socket_ctl_connect(file_t *file, uint64_t argc, const char **argv)
Definition socket.c:180
static void socket_accept_close(file_t *file)
Definition socket.c:283
static uint64_t socket_data_write(file_t *file, const void *buf, size_t count, uint64_t *offset)
Definition socket.c:70
static void socket_inode_cleanup(inode_t *inode)
Definition socket.c:302
static uint64_t socket_data_read(file_t *file, void *buf, size_t count, uint64_t *offset)
Definition socket.c:44
static void socket_data_close(file_t *file)
Definition socket.c:33
static uint64_t socket_data_open(file_t *file)
Definition socket.c:20
static uint64_t socket_ctl_listen(file_t *file, uint64_t argc, const char **argv)
Definition socket.c:149
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:283
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
#define atol(nptr)
Definition stdlib.h:33
_PUBLIC void * calloc(size_t nmemb, size_t size)
Definition calloc.c:6
_PUBLIC void free(void *ptr)
Definition free.c:11
inode_t * inode
Definition dentry.h:87
void * private
Definition dentry.h:94
File operations structure.
Definition file.h:57
uint64_t(* open)(file_t *file)
Definition file.h:58
File structure.
Definition file.h:37
void(* cleanup)(inode_t *inode)
Definition inode.h:98
Inode structure.
Definition inode.h:54
void * private
Definition inode.h:66
Mount structure.
Definition mount.h:36
superblock_t * superblock
The superblock of the mounted filesystem.
Definition mount.h:40
dentry_t * root
The root dentry of the mounted filesystem.
Definition mount.h:42
Path structure.
Definition path.h:110
uint64_t(* bind)(socket_t *sock, const char *address)
wait_queue_t *(* poll)(socket_t *sock, poll_events_t *revents)
uint64_t(* send)(socket_t *sock, const void *buffer, uint64_t count, uint64_t *offset)
uint64_t(* connect)(socket_t *sock, const char *address)
uint64_t(* listen)(socket_t *sock, uint32_t backlog)
uint64_t(* recv)(socket_t *sock, void *buffer, uint64_t count, uint64_t *offset)
uint64_t(* init)(socket_t *sock)
void(* deinit)(socket_t *sock)
uint64_t(* accept)(socket_t *sock, socket_t *newSock)
Socket Family structure.
const socket_family_ops_t * ops
atomic_uint64_t newId
Socket structure.
Definition socket.h:81
dentry_t * dataFile
Definition socket.h:93
socket_state_t nextState
Definition socket.h:90
void * private
Definition socket.h:88
dentry_t * ctlFile
Definition socket.h:92
ref_t ref
Definition socket.h:82
path_flags_t flags
Definition socket.h:87
socket_type_t type
Definition socket.h:86
socket_state_t currentState
Definition socket.h:89
socket_family_t * family
Definition socket.h:85
char id[MAX_NAME]
Definition socket.h:83
dentry_t * acceptFile
Definition socket.h:94
rwmutex_t mutex
Definition socket.h:91
Superblock operations structure.
Definition superblock.h:70
void(* unmount)(superblock_t *superblock)
Definition superblock.h:89
Superblock structure.
Definition superblock.h:44
void * private
Definition superblock.h:50
Wait queue structure.
Definition wait.h:166
mount_t * sysfs_mount_new(const path_t *parent, const char *name, namespace_t *ns, const superblock_ops_t *superblockOps)
Mount a new instance of SysFS.
Definition sysfs.c:100
dentry_t * sysfs_file_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, const file_ops_t *fileOps, void *private)
Create a new file inside a mounted SysFS instance.
Definition sysfs.c:216