#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <bits/types.h>
#include <errno.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <liburing/io_uring.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include "numbers.h"
#include <liburing.h>
#include "net.h"
#define sfree(p) do { free(p); (p) = NULL; } while(0)
#define MESSAGE_HEADERS_SIZE 9
static inline void serialize_message_headers(const MessageHeaders *msg, uint8_t *buf) {
for (int i = 0; i < 8; i++) {
buf[i] = (msg->size >> (i * 8)) & 0xFF;
}
buf[8] = msg->compr_alg; }
static inline void deserialize_message_headers(const uint8_t *buf, MessageHeaders *msg) {
msg->size = 0;
for (int i = 0; i < 8; i++) {
msg->size |= ((uint64_t)buf[i]) << (i * 8);
}
msg->compr_alg = buf[8];
}
int start(Networker* self, struct NetworkerSettings* s){
struct NetworkerSettings settings = *s;
if (self->initiated > 0){
return 0;
}
self->client_num = s->max_clients;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0){
return -errno;
}
struct sockaddr_in sockad;
sockad.sin_family = AF_INET;
sockad.sin_port = htons(settings.port);
inet_pton(AF_INET, settings.host, &sockad.sin_addr);
int _l = bind(sock, (struct sockaddr*)&sockad, sizeof(sockad));
if (_l < 0){
return -errno;
}
int _l1 = listen(sock, settings.max_queue);
if (_l1 < 0){
return -errno;
}
self->sock = sock;
self->initiated = 1;
self->clients = (Client*)calloc(self->client_num, sizeof(Client));
if(!self->clients){
return -ENOMEM;
}
for(usize i = 0; i < self->client_num; i++){
self->clients[i].id = i;
self->clients[i].request = NULL;
self->clients[i].response = NULL;
self->clients[i].state = NonExistent;
}
self->author_log = calloc(self->client_num,sizeof(u64));
if(!self->author_log){
free(self->clients);
close(sock);
return -ENOMEM;
}
self->ring = calloc(1,sizeof(struct io_uring));
if (!self->ring){
free(self->author_log);
free(self->clients);
close(sock);
return -ENOMEM;
}
{
int res = io_uring_queue_init(self->client_num>0?self->client_num:1, self->ring, 0);
if(res < 0) {
free(self->author_log);
free(self->clients);
free(self->ring);
close(sock);
return res;
}
}
return 0;
}
int proc(Networker* self){
#define ring *self->ring
u64 *author_log = self->author_log;
u64 calls = 0;
#define LOG_AUTHOR \
author_log[calls] = i;\
#define REGISTER \
LOG_AUTHOR \
calls++ \
u64 now = time(NULL);
for(u64 i = 0; i < self->client_num; i++){
if(self->clients[i].state == NonExistent){
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_accept(sqe, self->sock, NULL,NULL, 0);
sqe->user_data = OP_SocketAcc;
REGISTER;
continue;
}
if(self->clients[i].state == Idle){
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
if((now-self->clients[i].activity) > 1200){
sqe->user_data = OP_Close;
io_uring_prep_close(sqe, self->clients[i].sock);
self->clients[i].state = NonExistent;
sfree(self->clients[i].response);
sfree(self->clients[i].request);
continue;
}
sqe->user_data = OP_Read;
self->clients[i].state = Finished_H;
io_uring_prep_read(sqe,self->clients[i].sock, (char*)(&self->clients[i].req_headers)+self->clients[i].recv_offset, MESSAGE_HEADERS_SIZE-self->clients[i].recv_offset, 0);
REGISTER;
continue;
}
if(self->clients[i].state == Finished_H){
if(self->clients[i].recv_offset == MESSAGE_HEADERS_SIZE){
self->clients[i].recv_offset = 0;
unsigned char buffer [MESSAGE_HEADERS_SIZE];
memcpy(buffer, &self->clients[i].req_headers, MESSAGE_HEADERS_SIZE);
deserialize_message_headers(buffer, &self->clients[i].req_headers);
self->clients[i].state = Reading;
}else{
self->clients[i].state = Idle;
continue;
}
}
if(self->clients[i].state == Reading){
if(self->clients[i].capacity < self->clients[i].req_headers.size || self->clients[i].request == NULL){
sfree(self->clients[i].request);
self->clients[i].request = malloc(self->clients[i].req_headers.size);
self->clients[i].capacity = self->clients[i].req_headers.size;
}
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
sqe->user_data = OP_Read;
self->clients[i].state = Finished_R;
io_uring_prep_read(sqe,self->clients[i].sock,self->clients[i].request + self->clients[i].recv_offset,self->clients[i].req_headers.size-self->clients[i].recv_offset,0);
REGISTER;
continue;
}
if(self->clients[i].state == Finished_R){
if(self->clients[i].recv_offset == self->clients[i].req_headers.size){
self->clients[i].recv_offset = 0;
self->clients[i].state = Available;
}else{
self->clients[i].state = Reading;
}
continue;
}
if(self->clients[i].state == Ready){
self->clients[i].writev_offset = 0;
self->clients[i].activity = now;
self->clients[i].state = WrittingSock;
continue;
}
if(self->clients[i].state == WrittingSock){
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
sqe->user_data = OP_Write;
io_uring_prep_write(sqe, self->clients[i].sock,
(self->clients[i].response) + self->clients[i].writev_offset,
self->clients[i].response_size - self->clients[i].writev_offset, 0);
self->clients[i].state = Finished_WS;
REGISTER;
continue;
}
if(self->clients[i].state == Finished_WS){
if(self->clients[i].writev_offset >= self->clients[i].response_size){
self->clients[i].writev_offset = 0;
self->clients[i].state = Idle;
}else{
self->clients[i].state = WrittingSock;
}
continue;
}
if(self->clients[i].state == Kill){
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
sqe->user_data = OP_Close;
io_uring_prep_close(sqe, self->clients[i].sock);
self->clients[i].state = NonExistent;
self->clients[i].recv_offset = 0;
self->clients[i].writev_offset = 0;
sfree(self->clients[i].response);
sfree(self->clients[i].request);
REGISTER;
continue;
}
}
{
int res = io_uring_submit(&ring);
if (res < 0){
return res;
};
}
for(usize i = 0; i < calls; i++){
u64 ptr = self->author_log[i];
struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
__S32_TYPE res = cqe->res;
io_uring_cqe_seen(&ring, cqe);
if(res < 0){
self->clients[ptr].state = Kill;
continue;
}
int what = cqe->user_data;
if(cqe->res < 0){
continue;
}
if(what == OP_Read){
self->clients[ptr].recv_offset += res;
continue;
}
if(what == OP_Write){
self->clients[ptr].writev_offset += res;
continue;
}
if(what == OP_SocketAcc){
u64 saved_id = self->clients[ptr].id;
memset(&self->clients[ptr], 0, sizeof(Client));
self->clients[ptr].sock = res;
self->clients[ptr].state = Idle;
self->clients[ptr].activity = now;
self->clients[ptr].id = saved_id;
continue;
}
}
return 0;
}
int apply_client_response(Networker* self, u64 client_id, unsigned char* buffer, u64 buffer_size, int compression_algorithm){
if (!(client_id < self->client_num && self->clients[client_id].state == Processing)){
return -ENOPKG;
}
MessageHeaders headers;
headers.size = buffer_size;
headers.compr_alg = compression_algorithm;
usize rbs = sizeof(MessageHeaders) + buffer_size;
unsigned char* response_buffer = malloc(rbs);
if(!response_buffer){
return -ENOMEM;
}
serialize_message_headers(&headers, response_buffer);
memcpy(response_buffer+MESSAGE_HEADERS_SIZE, buffer, buffer_size);
self->clients[client_id].response = response_buffer;
self->clients[client_id].response_size = rbs;
self->clients[client_id].state = Ready;
return 0;
}
SomeClient get_client(Networker* self){
for(usize i = 0; i < self->client_num; i ++) {
if(self->clients[i].state == Available){
return (SomeClient) {&self->clients[i],1};
}
}
return (SomeClient){NULL, 0};
}
int claim_client(Networker* self, u64 client_id){
if(client_id < self->client_num && self->clients[client_id].state == Available){
self->clients[client_id].state = Processing;
return 0;
}
return -ENOPKG;
}
int kill_client(Networker* self, u64 client_id){
if(client_id < self->client_num){
self->clients[client_id].state = Kill;
return 0;
}
return -ENOPKG;
}
int cycle(Networker* self){
if (self->initiated != 1) return -1;
return proc(self); }