Mercurial
view seobeo/s_linux_network.c @ 22:947b81010aba
[Dowa & Seobeo] Updated so that Dowa hashmaps can use arena and not be broken. Split up web so taht it can handle different paths. Also fixes issues with hash collisions which was pain in the ass.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Tue, 07 Oct 2025 07:11:02 -0700 |
| parents | 875bb6e10db7 |
| children | c0f6c8c7829f |
line wrap: on
line source
#include "seobeo/seobeo.h" Seobeo_PHandle Seobeo_Stream_Handle_Server_Create(const char *host, const char* port) { Seobeo_PHandle p_handle; struct addrinfo hints, *server_infos, *free_server_info; int32 socket_fd, yes = 1; // Need this for setsockopt memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; if (getaddrinfo(host, port, &hints, &server_infos) != 0) { perror("getaddrinfo"); return NULL; } for ( free_server_info = server_infos; free_server_info != NULL; free_server_info = free_server_info->ai_next ) { if((socket_fd = socket(free_server_info->ai_family, free_server_info->ai_socktype, free_server_info->ai_protocol)) == -1) { perror("socket"); continue; } if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { perror("setsockopt"); continue; } if (bind(socket_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1) { perror("v_network: Couldn't make socket non-blocking\n"); continue; } break; } if (listen(socket_fd, 16) != 0) { perror("listen"); close(socket_fd); return NULL; } if(fcntl(socket_fd, F_SETFL, O_NONBLOCK) != 0) { perror("fcntl"); return NULL; } freeaddrinfo(server_infos); p_handle = malloc(sizeof(*p_handle)); p_handle->socket = socket_fd; p_handle->type = SEOBEO_STREAM_TYPE_SERVER; p_handle->connected = FALSE; p_handle->host = host != NULL ? strdup(host) : "localhost"; p_handle->port = strdup(port); p_handle->ssl_ctx = NULL; p_handle->ssl = NULL; p_handle->read_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); p_handle->read_buffer_capacity = INITIAL_BUFFER_CAPACITY; p_handle->read_buffer_len = 0; p_handle->write_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); p_handle->write_buffer_capacity = INITIAL_BUFFER_CAPACITY; p_handle->write_buffer_len = 0; p_handle->file = NULL; p_handle->text_copy = NULL; p_handle->file_name = NULL; p_handle->destroyed = false; return p_handle; } Seobeo_PHandle Seobeo_Stream_Handle_Client_Create(const char *host, const char* port, boolean use_tls) { Seobeo_PHandle p_handle; p_handle = malloc(sizeof(*p_handle)); struct addrinfo hints, *server_infos; int32 socket_fd; // Need this for setsockopt memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, port, &hints, &server_infos) != 0) { perror("getaddrinfo"); return NULL; } if((socket_fd = socket(server_infos->ai_family, server_infos->ai_socktype, server_infos->ai_protocol)) == -1) { perror("socket"); return NULL; } if (connect(socket_fd, server_infos->ai_addr, server_infos->ai_addrlen) != 0) { perror("connect"); return NULL; } freeaddrinfo(server_infos); p_handle->socket = socket_fd; p_handle->type = SEOBEO_STREAM_TYPE_CLIENT; if (use_tls) { printf("USE SSL\n\n"); Seobeo_Web_SSL_Init(); p_handle->ssl_ctx = SSL_CTX_new(TLS_client_method()); SSL_CTX_set_default_verify_paths(p_handle->ssl_ctx); p_handle->ssl = SSL_new(p_handle->ssl_ctx); SSL_set_fd(p_handle->ssl, p_handle->socket); SSL_set_tlsext_host_name(p_handle->ssl, host); // Blocking for TSL handshake fcntl(socket_fd, F_SETFL, 0); if (SSL_connect(p_handle->ssl) != 1) { fprintf(stderr, "SSL_connect failed\n"); ERR_print_errors_fp(stderr); return NULL; } }else { p_handle->ssl_ctx = NULL; p_handle->ssl = NULL; } p_handle->connected = true; p_handle->host = host != NULL ? strdup(host) : "localhost"; p_handle->port = strdup(port); p_handle->read_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); p_handle->read_buffer_capacity = INITIAL_BUFFER_CAPACITY; p_handle->read_buffer_len = 0; p_handle->write_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); p_handle->write_buffer_capacity = INITIAL_BUFFER_CAPACITY; p_handle->write_buffer_len = 0; p_handle->file = NULL; p_handle->text_copy = NULL; p_handle->file_name = NULL; p_handle->destroyed = false; return p_handle; } Seobeo_PHandle Seobeo_Stream_Handle_Server_Accept(Seobeo_PHandle p_server_handle) { struct sockaddr_storage addr; socklen_t addrlen = sizeof addr; char client_inet_addr[INET6_ADDRSTRLEN]; int client_fd = accept(p_server_handle->socket, (struct sockaddr*)&addr, &addrlen); inet_ntop( addr.ss_family, Seobeo_Get_IP4_Or_IP6((struct sockaddr *)&addr), client_inet_addr, sizeof client_inet_addr); if (client_fd == -1) { return NULL; } Seobeo_PHandle p_client_handle = malloc(sizeof *p_client_handle); p_client_handle->socket = client_fd; p_client_handle->type = SEOBEO_STREAM_TYPE_CLIENT; p_client_handle->connected = true; // TODO: support SSL in the future. p_client_handle->ssl_ctx = NULL; p_client_handle->ssl = NULL; p_client_handle->host = strdup(client_inet_addr); p_client_handle->port = NULL; p_client_handle->read_buffer_capacity = p_server_handle->read_buffer_capacity; p_client_handle->read_buffer_len = 0; p_client_handle->read_buffer = malloc(p_client_handle->read_buffer_capacity); p_client_handle->write_buffer_capacity = p_server_handle->write_buffer_capacity; p_client_handle->write_buffer_len = 0; p_client_handle->write_buffer = malloc(p_client_handle->write_buffer_capacity); p_client_handle->destroyed = false; return p_client_handle; } void Seobeo_Handle_Destroy(Seobeo_PHandle p_handle) { if (!p_handle) return; bool expected = false; if (!atomic_compare_exchange_strong(&p_handle->destroyed, &expected, true)) { // Already destroyed by another thread return; } if (p_handle->host) free(p_handle->host); if (p_handle->port) free(p_handle->port); if (p_handle->ssl) { SSL_shutdown(p_handle->ssl); SSL_free(p_handle->ssl); p_handle->ssl = NULL; } if (p_handle->ssl_ctx) { SSL_CTX_free(p_handle->ssl_ctx); p_handle->ssl_ctx = NULL; } if (p_handle->socket) close(p_handle->socket); if (p_handle->read_buffer) free(p_handle->read_buffer); if (p_handle->write_buffer) free(p_handle->write_buffer); if (p_handle->text_copy) free(p_handle->text_copy); if (p_handle->file_name) free(p_handle->file_name); free(p_handle); } int32 Seobeo_Handle_Flush(Seobeo_PHandle p_handle) { uint32 total = p_handle->write_buffer_len; uint32 sent = 0; printf("Total: %d\n\n", p_handle->write_buffer_len); while (sent < total) { if (p_handle->ssl) { int n = SSL_write(p_handle->ssl, p_handle->write_buffer + sent, total - sent); if (n < 0) { int err = SSL_get_error(p_handle->ssl, n); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { // caller must wait for socket readiness and retry return 0; } ERR_print_errors_fp(stderr); return -1; } sent += (uint32)n; }else { ssize_t n = write( p_handle->socket, p_handle->write_buffer + sent, total - sent ); if (n < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return 1; return -1; } sent += (uint32)n; } } p_handle->write_buffer_len = 0; return 0; } int32 Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8 *data, uint32 data_size) { if (p_handle->write_buffer_len + data_size > p_handle->write_buffer_capacity) { int32 rc = Seobeo_Handle_Flush(p_handle); if (rc < 0) return -1; if (rc > 0) return 1; } if (data_size > p_handle->write_buffer_capacity) { uint32 offset = 0; while (offset < data_size) { ssize_t n = write(p_handle->socket, data + offset, data_size - offset); if (n==0) { // DEBUG printf("NONE %d\n", offset); break; } if (n < 0) { if (errno == EINTR || errno == EAGAIN) { // DEBUG // printf("Partial write, returning early (offset=%d)\n", offset); continue; } if (errno == EAGAIN) return 1; return -1; } offset += (uint32)n; // DEBUG printf("\n\noffset: %d data_size: %d\n\n", offset, data_size); } // DEBUG printf("\n\nTotal: %d\n", offset); return 0; } memcpy(p_handle->write_buffer + p_handle->write_buffer_len, data, data_size); p_handle->write_buffer_len += data_size; // DEBUG printf("\nheader data_size: %d\n\n", data_size); return 0; } int32 Seobeo_Handle_Read(Seobeo_PHandle p_handle) { int32 read_size; if (!p_handle) return -1; // How many bytes we can still read into the buffer uint32 free_space = p_handle->read_buffer_capacity - p_handle->read_buffer_len; if (free_space == 0) return -1; if (p_handle->ssl) { read_size = (int32)SSL_read(p_handle->ssl, p_handle->read_buffer, free_space); if (read_size <= 0) { int err = SSL_get_error(p_handle->ssl, read_size); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return 0; case SSL_ERROR_ZERO_RETURN: default: // TODO: Handle these errors return -2; } } }else { read_size = (int32)read(p_handle->socket, p_handle->read_buffer + p_handle->read_buffer_len, free_space); if (read_size == 0) return -2; if (read_size < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; return -1; } } p_handle->read_buffer_len += (uint32)read_size; return read_size; } void Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed) { if (consumed >= p_handle->read_buffer_len) { p_handle->read_buffer_len = 0; return; } // Slide remaining bytes to the front memmove( p_handle->read_buffer, p_handle->read_buffer + consumed, p_handle->read_buffer_len - consumed ); p_handle->read_buffer_len -= consumed; } void *Seobeo_Get_IP4_Or_IP6(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); }