aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorjustanothercatgirl <sotov@twistea.su>2025-02-08 22:13:52 +0300
committerjustanothercatgirl <sotov@twistea.su>2025-02-08 22:13:52 +0300
commitcab382db088d9f240253466a1c5a26c62f3967c8 (patch)
treec5502f1b49211dccd3e29e163e708708495a6407 /doc
parent3eeee14d5d5c93ae3d156aabae5a96d1c09f185a (diff)
Implemented multiplexing in main thread (TCP loop). Removed CMake files.HEADmaster
TODO: Implement multiplexing in worker threads (UDP loops), implement channel_pool interface.
Diffstat (limited to 'doc')
-rw-r--r--doc/PROTOCOLS10
-rw-r--r--doc/channel_multiplexing84
2 files changed, 89 insertions, 5 deletions
diff --git a/doc/PROTOCOLS b/doc/PROTOCOLS
index c15a83d..996bf0c 100644
--- a/doc/PROTOCOLS
+++ b/doc/PROTOCOLS
@@ -72,11 +72,11 @@ permission required.
arguments. Returns an array as follows: first 8 bytes are uint64 array_size,
next 8*array_size bytes are channels. Last 8 bytes are zeroes (they are after
the last channel). Possible memory layout (divided in 8 byte [64 bit] blocks):
-| 5 | 69 | 70 | 71 | 72 | 42 | 0 |
- ^ ^ ^ ^
- | |-start of data | |-leading zero
- |-size of array |-end of data
-1.3. Functions.
+| 5 | 69 | 70 | 71 | 727 | 420 | 0 |
+ ^ ^ ^ ^
+ | |-start of data | |-leading zero
+ |-size of array |-end of data
+1.3. Functions.
As the interface mainly uses `uint64` type for communications, there are 2
functions that are for some reason not present in linux api:
`uint64 hton64(uint64)`: Host TO Network: convert uint64 to
diff --git a/doc/channel_multiplexing b/doc/channel_multiplexing
new file mode 100644
index 0000000..a1ba681
--- /dev/null
+++ b/doc/channel_multiplexing
@@ -0,0 +1,84 @@
+This document is mostly for the developer to settle down ideas that are sitting
+in his mind.
+
+Server structure:
+Main thread: accepting TCP socket and reading-writing TCP sockets created by
+an accepting one. TODO: rewrite so that the entire system is using poll.
+
+Other `get_nprocs() - 1` threads (if `get_nprocs() == 1`, then only 1
+additional thread) are channel pools.
+
+Additionally, main thread maintains a list of all channels and threads
+associated with them. When new channel is requested, is is created on a thread
+that is maintaining the least amount of channels at the time.
+
+Each channel pool consists of an anonymous UNIX domain socket (which is used
+for recieving system messages from main thread) and some amount of INET domain
+sockets. All of them are switched on using `poll` system call.
+
+Each channel in the channel pool has an associated list of peers with it. When
+data is recieved on a channel, it is forwarded to every peer (except the
+sender).
+
+The basic structure of the loop should look something like this:
+
+```
+fds = {timerfd, master socket, udp1, udp2, ...};
+while (poll(fds, nfds, -1) > 0) {
+ if (socket is master and has data) process_system_commands();
+ if (timerfd is ready) check_keepalives(all sockets);
+ for (every socket that has data)
+ handle_peers(socket);
+}
+
+void process_system_commands() {
+ command = read(master);
+ switch (parse_command()) {
+ case add_user: addto(channel, user); break;
+ case add_channel: array_append(channels, new_channel()); break;
+ case remove_user: rmfrom(channel, user); break;
+ case remove_channel: array_pop(channel); break;
+ }
+}
+
+void handle_peers(int socket) {
+ data = read(socket);
+ for (every peer of socket)
+ sendto(socket, data, peer, O_NONBLOCK); // MSG_DONTWAIT, maybe?
+}
+
+void check_keepalives(int socket) {
+ for (every peer of socket) {
+ if (keepalive of peer too old) rmfrom(channel, user);
+ }
+}
+```
+
+Data structures:
+inside main thread:
+ struct channel{u64 id, int port};
+ struct channel_pool {
+ u16 num,
+ int master_pipe,
+ u64 thread_id,
+ array<struct channel> chs
+ };
+ // modern linux kernel has limit on maximim amount of cores:
+ // 8192. this would break 65535 port limit very fast anyways.
+ array<struct channel_pool> threads;
+inside pool:
+ struct ch_user { u64 id, u32 ip, u16 port, u64 last_keepalive };
+ struct channel {
+ u64 id,
+ u64 owner,
+ int udo,
+ hash_set<ch_user>* users
+ };
+ array<struct channel> channels;
+ int master = pipe
+
+Communication between threads will be done through pipes. Yes, this will be
+inefficient in a sense that there will be 2 file descriptors opened for each
+thread, but what are other options? Yes, none. If there are, mail this to me
+please
+