7#define _WIN32_WINNT 0x0600
16#include <sys/select.h>
21static void mx_socket_store_inet_address(
MXSocket *sock,
const struct sockaddr *addr, socklen_t addrlen) {
22 if (sock ==
nullptr || addr ==
nullptr)
26 if (addr->sa_family == AF_INET6) {
27 size_t len_size = ((size_t)addrlen >
sizeof(sock->
inet6)) ?
sizeof(sock->
inet6) : (size_t)addrlen;
28 memcpy(&sock->
inet6, addr, len_size);
29 }
else if (addr->sa_family == AF_INET) {
30 size_t len_size = ((size_t)addrlen >
sizeof(sock->
inet)) ?
sizeof(sock->
inet) : (size_t)addrlen;
31 memcpy(&sock->
inet, addr, len_size);
35static bool mx_socket_inet_listen(
MXSocket *sock,
const char *port,
int backlog,
int type,
int family) {
42 struct addrinfo hints;
43 struct addrinfo *rt, *rp;
47 memset(&hints, 0,
sizeof(
struct addrinfo));
48 hints.ai_canonname =
nullptr;
49 hints.ai_addr =
nullptr;
50 hints.ai_next =
nullptr;
51 hints.ai_socktype = type;
52 hints.ai_family = family;
53 hints.ai_flags = AI_PASSIVE;
54 s = getaddrinfo(
nullptr, port, &hints, &rt);
58 for (rp = rt; rp != NULL; rp = rp->ai_next) {
59 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
61 if (sfd == INVALID_SOCKET)
68 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (
const char *)&optval,
sizeof(optval)) == -1) {
70 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval)) == -1) {
77 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
91 if (listen(sfd, backlog) == -1) {
97 mx_socket_store_inet_address(sock, rp->ai_addr, rp->ai_addrlen);
109static bool mx_socket_inet_connect(
MXSocket *sock,
const char *host,
const char *port,
int type,
int family) {
110 if (host ==
nullptr || port ==
nullptr)
116 struct addrinfo hints;
117 struct addrinfo *rt, *rp;
119 memset(&hints, 0,
sizeof(
struct addrinfo));
120 hints.ai_canonname =
nullptr;
121 hints.ai_addr =
nullptr;
122 hints.ai_next =
nullptr;
123 hints.ai_family = family;
124 hints.ai_socktype = type;
125 s = getaddrinfo(host, port, &hints, &rt);
130 for (rp = rt; rp !=
nullptr; rp = rp->ai_next) {
131 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
133 if (sfd == INVALID_SOCKET)
139 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
150 mx_socket_store_inet_address(sock, rp->ai_addr, rp->ai_addrlen);
162static bool mx_socket_inet_bind(
MXSocket *sock,
const char *port,
int family) {
167 struct addrinfo hints = {};
168 struct addrinfo *result =
nullptr;
169 struct addrinfo *rp =
nullptr;
170 hints.ai_family = family;
171 hints.ai_socktype = SOCK_DGRAM;
172 hints.ai_flags = AI_PASSIVE;
173 int s = getaddrinfo(
nullptr, port, &hints, &result);
177 bool set_value =
false;
178 for (rp = result; rp !=
nullptr; rp = rp->ai_next) {
179 sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
181 if (sockfd == INVALID_SOCKET)
187 if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) {
188 mx_socket_store_inet_address(sock, rp->ai_addr, rp->ai_addrlen);
195 freeaddrinfo(result);
207 struct sockaddr_un addr;
210 if (sockfd == INVALID_SOCKET) {
217 if (remove(path) == -1 && errno == ENOENT) {
222 memset(&addr, 0,
sizeof(
struct sockaddr_un));
223 strncpy(addr.sun_path, path,
sizeof(addr.sun_path) - 1);
224 addr.sun_family = AF_UNIX;
225 if (bind(sockfd, (
struct sockaddr *)&addr,
sizeof(
struct sockaddr_un)) == -1) {
231 if (listen(sockfd, backlog) == -1) {
247 struct sockaddr_un addr;
248 memset(&addr, 0,
sizeof(
struct sockaddr_un));
249 addr.sun_family = AF_UNIX;
250 sockfd = socket(AF_UNIX, type, 0);
252 if (sockfd == INVALID_SOCKET) {
259 strncpy(addr.sun_path, path,
sizeof(addr.sun_path) - 1);
260 if (connect(sockfd, (
struct sockaddr *)&addr,
sizeof(
struct sockaddr_un)) == -1) {
271 return mx_socket_inet_listen(sock, port, backlog, type, AF_INET);
275 return mx_socket_inet_listen(sock, port, backlog, type, AF_INET6);
279 if (input ==
nullptr || output ==
nullptr)
287 if (newfd == INVALID_SOCKET)
289 u_long mode = input->
blocking ? 0 : 1;
290 if (ioctlsocket(newfd, FIONBIO, &mode) != 0) {
298 int flags = fcntl(newfd, F_GETFL);
304 flags &= ~O_NONBLOCK;
307 if (fcntl(newfd, F_SETFL, flags) == -1) {
336 u_long mode = state ? 0 : 1;
337 if (ioctlsocket(sock->
sockfd, FIONBIO, &mode) != 0) {
338 fprintf(stderr,
"Error setting flags for: %d\n", (
int)sock->
sockfd);
342 int flags = fcntl(sock->
sockfd, F_GETFL);
344 fprintf(stderr,
"Error getting flags for: %d\n", sock->
sockfd);
348 flags &= ~O_NONBLOCK;
351 if (fcntl(sock->
sockfd, F_SETFL, flags) == -1) {
352 fprintf(stderr,
"Error setting flags for: %d\n", sock->
sockfd);
363 return mx_socket_inet_connect(sock, host, port, type, AF_INET);
367 return mx_socket_inet_connect(sock, host, port, type, AF_INET6);
371 return mx_socket_inet_bind(sock, port, AF_INET);
375 return mx_socket_inet_bind(sock, port, AF_INET6);
384 if (sockfd == INVALID_SOCKET) {
392 struct sockaddr_un caddy;
393 memset(&caddy, 0,
sizeof(
struct sockaddr_un));
394 caddy.sun_family = AF_UNIX;
395 strncpy(caddy.sun_path, path,
sizeof(caddy.sun_path) - 1);
396 if (bind(sockfd, (
struct sockaddr *)&caddy,
sizeof(caddy)) == -1) {
423 if (sock ==
nullptr || buf ==
nullptr || len == 0)
429 return recv(sock->
sockfd, (
char *)buf,
MX_LEN(len), flags);
433 if (sock ==
nullptr || buf ==
nullptr || len == 0)
439 return send(sock->
sockfd, (
const char *)buf,
MX_LEN(len), flags);
447 ssize_t r = recv(sock->
sockfd, &c, 1, MSG_PEEK);
448#elif defined(MX_HAVE_MSG_DONTWAIT)
449 ssize_t r = recv(sock->
sockfd, &c, 1, MSG_PEEK | MSG_DONTWAIT);
453 FD_SET(sock->
sockfd, &readfds);
455 struct timeval timeout = {0, 0};
456 const int ready = select((
int)(sock->
sockfd + 1), &readfds,
nullptr,
nullptr, &timeout);
462 ssize_t r = recv(sock->
sockfd, &c, 1, MSG_PEEK);
475 if (sock ==
nullptr || buffer ==
nullptr || size ==
nullptr)
486 size_t init_size = 4096;
487 char *temp = (
char *)malloc(init_size + 1);
493 ssize_t read_val = recv(sock->
sockfd, &c, 1, 0);
497 if (index >= init_size) {
498 size_t new_init_size = init_size * 2;
499 char *t = (
char *)realloc(temp, new_init_size + 1);
505 init_size = new_init_size;
536 if (sock ==
nullptr || buf ==
nullptr || bytes == 0)
539 const char *ptr = (
const char *)buf;
542 ssize_t written = send(sock->
sockfd, (
const char *)ptr,
MX_LEN(left), 0);
549 left -= (size_t)written;
552 return (ssize_t)bytes;
556 if (sock ==
nullptr || buf ==
nullptr || bytes == 0)
559 char *ptr = (
char *)buf;
562 ssize_t bytes_read = recv(sock->
sockfd, (
char *)ptr,
MX_LEN(left), 0);
563 if (bytes_read == -1) {
571 left -= (size_t)bytes_read;
574 return (ssize_t)(bytes - left);
579 signal(SIGPIPE, SIG_IGN);
584 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0)
588 bytes = sendto(sock->
sockfd, (
const char *)buf,
MX_LEN(src_bytes), 0, (
struct sockaddr *)&sock->
inet, sock->
addrlen);
593 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0)
597 bytes = sendto(sock->
sockfd, (
const char *)buf,
MX_LEN(src_bytes), 0, (
struct sockaddr *)&sock->
inet6, sock->
addrlen);
602 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0)
606 socklen_t len = (socklen_t)
sizeof(
struct sockaddr_storage);
607 struct sockaddr_storage caddr;
608 bytes = recvfrom(sock->
sockfd, (
char *)buf,
MX_LEN(src_bytes), 0, (
struct sockaddr *)&caddr, &len);
610 mx_socket_store_inet_address(sock, (
const struct sockaddr *)&caddr, len);
615 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0 || address ==
nullptr)
618 ssize_t bytes = recvfrom(sock->
sockfd, (
char *)buf,
MX_LEN(src_bytes), 0,
621 mx_socket_store_inet_address(sock, (
const struct sockaddr *)&address->
storage, address->
length);
626 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0 || address ==
nullptr || address->
length == 0)
628 return sendto(sock->
sockfd, (
const char *)buf,
MX_LEN(src_bytes), 0,
629 (
const struct sockaddr *)&address->
storage, address->
length);
633 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0)
637 socklen_t len = (socklen_t)
sizeof(
struct sockaddr_storage);
638 struct sockaddr_storage caddr;
639 bytes = recvfrom(sock->
sockfd, (
char *)buf,
MX_LEN(src_bytes), 0, (
struct sockaddr *)&caddr, &len);
641 mx_socket_store_inet_address(sock, (
const struct sockaddr *)&caddr, len);
646 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0)
650 bytes = sendto(sock->
sockfd, (
const char *)buf,
MX_LEN(src_bytes), 0, (
struct sockaddr *)&sock->
sun, sock->
addrlen);
654 if (sock ==
nullptr || buf ==
nullptr || src_bytes == 0)
658 socklen_t len = (socklen_t)
sizeof(
struct sockaddr_storage);
659 struct sockaddr_storage caddr;
660 bytes = recvfrom(sock->
sockfd, (
char *)buf,
MX_LEN(src_bytes), 0, (
struct sockaddr *)&caddr, &len);
bool mx_socket_unix_listen(MXSocket *sock, const char *path, int backlog, int type)
Create and bind a UNIX-domain socket for listening.
ssize_t mx_socket_send(MXSocket *sock, const void *buf, size_t len, int flags)
Write data to a socket.
bool mx_socket_unix_bind(MXSocket *s, const char *path)
Bind a UNIX-domain socket to a local path.
ssize_t mx_socket_read_all(MXSocket *sock, void *buf, size_t bytes)
Read the requested number of bytes from a socket.
ssize_t mx_socket_recvfrom(MXSocket *sock, void *buf, size_t src_bytes)
Receive a datagram using an Internet socket.
bool mx_socket_valid(const MXSocket *sock)
Check whether the socket handle is valid.
ssize_t mx_socket_recvfrom_address(MXSocket *sock, void *buf, size_t src_bytes, MXSocketAddress *address)
ssize_t mx_socket_sendto_address(MXSocket *sock, const void *buf, size_t src_bytes, const MXSocketAddress *address)
bool mx_socket_readline(MXSocket *sock, char **buffer, size_t *size)
Read a line of text from a socket.
bool mx_socket_ipv6_listen(MXSocket *sock, const char *port, int backlog, int type)
Create and bind an IPv6 Internet socket for listening.
ssize_t mx_socket_unix_recvfrom(MXSocket *sock, void *buf, size_t src_bytes)
Receive a datagram using a UNIX-domain socket.
bool mx_socket_ipv6_bind(MXSocket *sock, const char *port)
Bind an IPv6 Internet socket to a local port.
void mx_socket_ignore_pipe_signal()
Ignore SIGPIPE on platforms that require it.
bool mx_socket_bind(MXSocket *sock, const char *port)
Bind an Internet socket to a local port.
void mx_socket_close(MXSocket *sock)
Close a socket if it is open.
ssize_t mx_socket_write_all(MXSocket *sock, const void *buf, size_t bytes)
Write the requested number of bytes to a socket.
ssize_t mx_socket_ipv6_sendto(MXSocket *sock, const void *buf, size_t src_bytes)
Send a datagram using an IPv6 Internet socket.
bool mx_socket_listen(MXSocket *sock, const char *port, int backlog, int type)
Create and bind an Internet socket for listening.
bool mx_socket_connect(MXSocket *sock, const char *host, const char *port, int type)
Connect an Internet socket to a remote host.
ssize_t mx_socket_read(MXSocket *sock, void *buf, size_t len, int flags)
Read data from a socket.
ssize_t mx_socket_sendto(MXSocket *sock, const void *buf, size_t src_bytes)
Send a datagram using an Internet socket.
bool mx_socket_set_blocking(MXSocket *sock, bool state)
Toggle blocking mode for a socket.
bool mx_socket_accept(const MXSocket *input, MXSocket *output)
Accept an incoming connection.
bool mx_socket_unix_connect(MXSocket *sock, const char *path, int type)
Connect a UNIX-domain socket to a local path.
bool mx_socket_init(MXSocket *sock)
Initialize a socket structure with default values.
bool mx_socket_ipv6_connect(MXSocket *sock, const char *host, const char *port, int type)
Connect an IPv6 Internet socket to a remote host.
ssize_t mx_socket_unix_sendto(MXSocket *sock, const void *buf, size_t src_bytes)
Send a datagram using a UNIX-domain socket.
ssize_t mx_socket_ipv6_recvfrom(MXSocket *sock, void *buf, size_t src_bytes)
Receive a datagram using an IPv6 Internet socket.
bool mx_socket_is_open(const MXSocket *sock)
Check whether the socket is open.
#define mx_close_socket(s)
struct sockaddr_storage storage
Cross-platform socket state used by the C API.
struct sockaddr_in6 inet6
IPv6 address storage.
bool blocking
True when the socket is in blocking mode.
struct sockaddr_in inet
IPv4 address storage.
struct sockaddr_un sun
UNIX-domain address storage.
mx_socket_fd sockfd
Underlying socket handle.
socklen_t addrlen
Length of the active address structure.