Mercurial
view seobeo/s_linux_network.c @ 16:fb2cff495a60
[Seobeo] Fixed the problem with edge server.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Fri, 03 Oct 2025 09:55:51 -0700 |
| parents | 1e61008b9980 |
| children | d97ec3ded2ae |
line wrap: on
line source
#include "seobeo/seobeo.h" int Seobeo_CreateSocket(int32 stream, const char *host, const char* port, int32 backlog) { struct addrinfo hints = {0}, *server_infos, *free_server_info; int32 sock_fd, yes = 1; // Need this for setsockopt hints.ai_family = AF_INET; hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM; hints.ai_protocol = stream ? IPPROTO_TCP : IPPROTO_UDP; hints.ai_flags = stream ? AI_PASSIVE : 0; if (getaddrinfo(host, port, &hints, &server_infos) != 0) { perror("getaddrinfo"); return -1; } for ( free_server_info = server_infos; free_server_info != NULL; free_server_info = free_server_info->ai_next ) { if ( (sock_fd = socket( free_server_info->ai_family, free_server_info->ai_socktype, free_server_info->ai_protocol )) == -1 ) { perror("socket"); continue; } if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { perror("setsockopt"); continue; } if (bind(sock_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1) { close(sock_fd); perror("setsockopt"); continue; } // UDP should be non blocking if(!stream) { if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) != 0) { close(sock_fd); perror("v_network: Couldn't make socket non-blocking\n"); return -1; } } // binded to a open server infos; break; } // No longer need these values freeaddrinfo(server_infos); if (free_server_info == NULL) { perror("No free server"); return -1; } // TCP listen if(stream) { if (listen(sock_fd, backlog) != 0) { perror("listen"); close(sock_fd); return -1; } } return sock_fd; } Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host, const char* port) { Seobeo_PHandle p_handle; p_handle = malloc(sizeof(*p_handle)); p_handle->socket = Seobeo_CreateSocket(1, host, port, 10); // socke fd 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_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_GetIP4OrIP6((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->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); 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->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); } int Seobeo_Handle_Flush(Seobeo_PHandle p_handle) { uint32 total = p_handle->write_buffer_len; uint32 sent = 0; while (sent < total) { 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; } int Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8_t *data, uint32_t data_size) { if (p_handle->write_buffer_len + data_size > p_handle->write_buffer_capacity) { int 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_t offset = 0; while (offset < data_size) { ssize_t n = write(p_handle->socket, data + offset, data_size - offset); if (n < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return 1; return -1; } offset += (uint32_t)n; } return 0; } memcpy(p_handle->write_buffer + p_handle->write_buffer_len, data, data_size); p_handle->write_buffer_len += data_size; return 0; } int Seobeo_Handle_Read(Seobeo_PHandle p_handle) { // 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; ssize_t n = read( p_handle->socket, p_handle->read_buffer + p_handle->read_buffer_len, free_space ); if (n < 0) { if (errno == EINTR) return Seobeo_Handle_Read(p_handle); if (errno == EAGAIN) return 0; // no data available right now return -1; // fatal error } if (n == 0) { return -2; // peer closed the connection } p_handle->read_buffer_len += (uint32)n; return (int)n; // number of bytes read } 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_GetIP4OrIP6(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); }