#include "barev_net.h" #include #include #include #include #include #include #include #include #include #include int barev_net_set_nonblocking(int fd) { int flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) return 0; if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) return 0; return 1; } int barev_net_listen_v6(unsigned short port) { int fd; int on; struct sockaddr_in6 sa; fd = socket(AF_INET6, SOCK_STREAM, 0); if (fd < 0) return -1; on = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_port = htons(port); sa.sin6_addr = in6addr_any; if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { close(fd); return -1; } if (listen(fd, 16) < 0) { close(fd); return -1; } if (!barev_net_set_nonblocking(fd)) { close(fd); return -1; } return fd; } int barev_net_accept_v6(int listen_fd, char *addr_out, size_t addr_out_n, unsigned short *port_out) { int fd; struct sockaddr_in6 sa; socklen_t sl; const char *r; sl = (socklen_t)sizeof(sa); memset(&sa, 0, sizeof(sa)); fd = accept(listen_fd, (struct sockaddr *)&sa, &sl); if (fd < 0) return -1; if (addr_out && addr_out_n > 0) { r = inet_ntop(AF_INET6, &sa.sin6_addr, addr_out, (socklen_t)addr_out_n); if (!r) addr_out[0] = '\0'; } if (port_out) *port_out = ntohs(sa.sin6_port); barev_net_set_nonblocking(fd); return fd; } int barev_net_connect_v6(const char *ipv6, unsigned short port) { int fd; int rc; struct sockaddr_in6 sa; fd = socket(AF_INET6, SOCK_STREAM, 0); if (fd < 0) return -1; if (!barev_net_set_nonblocking(fd)) { close(fd); return -1; } memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_port = htons(port); if (inet_pton(AF_INET6, ipv6, &sa.sin6_addr) != 1) { close(fd); return -1; } rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); if (rc == 0) return fd; if (rc < 0 && (errno == EINPROGRESS || errno == EWOULDBLOCK)) return fd; close(fd); return -1; } int barev_net_is_readable(int fd, int timeout_ms) { fd_set rfds; struct timeval tv; int rc; FD_ZERO(&rfds); FD_SET(fd, &rfds); tv.tv_sec = timeout_ms / 1000; tv.tv_usec = (timeout_ms % 1000) * 1000; rc = select(fd + 1, &rfds, 0, 0, &tv); if (rc <= 0) return 0; return FD_ISSET(fd, &rfds) ? 1 : 0; } int barev_net_send_all(int fd, const char *buf, size_t n) { ssize_t w; size_t done; done = 0; while (done < n) { w = send(fd, buf + done, n - done, 0); if (w > 0) { done += (size_t)w; continue; } if (w < 0 && (errno == EINTR)) continue; if (w < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) break; return -1; } return (int)done; } int barev_net_recv_some(int fd, char *buf, size_t n) { ssize_t r; r = recv(fd, buf, n, 0); if (r > 0) return (int)r; if (r == 0) return 0; if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) return -2; return -1; } void barev_net_close(int fd) { if (fd >= 0) close(fd); }