Mercurial
view seobeo/s_linux_network.c @ 54:b3e82d22f961
[PostDog] Initial commit BROKEN
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Fri, 19 Dec 2025 13:58:52 -0800 |
| parents | 84672efec192 |
| children | ea9ef388ab97 |
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) { printf("Closing: %d", socket_fd); perror("listen"); close(socket_fd); return NULL; } int flags = fcntl(socket_fd, F_GETFL, 0); if(fcntl(socket_fd, F_SETFL, flags | 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->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->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; // Set non blocking... int flags = fcntl(client_fd, F_GETFL, 0); if (flags == -1) return NULL; fcntl(client_fd, F_SETFL, flags | O_NONBLOCK); 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; // Need to check if (!atomic_compare_exchange_strong(&p_handle->destroyed, &expected, true)) { return; } if (p_handle->host) Dowa_Free(p_handle->host); if (p_handle->port) Dowa_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) { printf("Closing: %d", p_handle->socket); close(p_handle->socket); } if (p_handle->read_buffer) Dowa_Free(p_handle->read_buffer); if (p_handle->write_buffer) Dowa_Free(p_handle->write_buffer); Dowa_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 { printf("socket: %d\n", p_handle->socket); 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; } if (!p_handle) { printf("[ERROR] p_handle is NULL before memcpy\n"); return; } if (!p_handle->write_buffer) { printf("[ERROR] p_handle->write_buffer is NULL (len=%zu, size=%zu)\n", p_handle->write_buffer_len, data_size); return; } printf("[DEBUG] memcpy -> dest=%p (write_buffer=%p + offset=%zu), src=%p, size=%zu\n", p_handle->write_buffer + p_handle->write_buffer_len, p_handle->write_buffer, p_handle->write_buffer_len, data, data_size); memcpy(p_handle->write_buffer + p_handle->write_buffer_len, data, data_size); p_handle->write_buffer_len += 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); }