sc/socket/sc_sock.c

1679 lines
29 KiB
C
Raw Normal View History

2020-11-25 09:25:38 +03:00
/*
* BSD-3-Clause
2020-11-25 09:25:38 +03:00
*
* Copyright 2021 Ozan Tezcan
* All rights reserved.
2020-11-25 09:25:38 +03:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
2020-11-25 09:25:38 +03:00
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
2020-11-25 09:25:38 +03:00
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
2020-11-25 09:25:38 +03:00
*/
2021-02-10 21:33:03 +03:00
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
2021-02-10 21:33:03 +03:00
#endif
2021-02-07 22:31:04 +03:00
2020-11-25 09:25:38 +03:00
#include "sc_sock.h"
#include <errno.h>
#include <fcntl.h>
2021-02-04 02:35:34 +03:00
#include <stdarg.h>
2020-11-25 09:25:38 +03:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef SC_SIZE_MAX
#define SC_SIZE_MAX INT32_MAX
#endif
2020-11-25 09:25:38 +03:00
#if defined(_WIN32) || defined(_WIN64)
#include <afunix.h>
#include <assert.h>
#include <Ws2tcpip.h>
#pragma warning(disable : 4996)
#define sc_close(n) closesocket(n)
#define sc_unlink(n) DeleteFileA(n)
#define SC_ERR SOCKET_ERROR
#define SC_INVALID INVALID_SOCKET
#define SC_EAGAIN WSAEWOULDBLOCK
#define SC_EINPROGRESS WSAEINPROGRESS
#define SC_EINTR WSAEINTR
2020-11-25 09:25:38 +03:00
2021-01-24 17:56:18 +03:00
typedef int socklen_t;
2020-11-25 09:25:38 +03:00
static int sc_sock_err()
{
return WSAGetLastError();
2020-11-25 09:25:38 +03:00
}
static void sc_sock_errstr(struct sc_sock *s, int gai_err)
2020-11-25 09:25:38 +03:00
{
int rc;
DWORD err = WSAGetLastError();
LPSTR str = 0;
2020-11-25 09:25:38 +03:00
rc = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, (LPSTR) &str, 0, NULL);
if (rc != 0) {
strncpy(s->err, str, sizeof(s->err) - 1);
LocalFree(str);
}
2020-11-25 09:25:38 +03:00
}
int sc_sock_set_blocking(struct sc_sock *s, bool blocking)
2020-11-25 09:25:38 +03:00
{
u_long mode = blocking ? 0 : 1;
int rc = ioctlsocket(s->fdt.fd, FIONBIO, &mode);
2020-11-25 09:25:38 +03:00
return rc == 0 ? 0 : -1;
2020-11-25 09:25:38 +03:00
}
2021-02-14 16:29:50 +03:00
int sc_sock_startup()
{
int rc;
WSADATA data;
2021-02-14 16:29:50 +03:00
rc = WSAStartup(MAKEWORD(2, 2), &data);
if (rc != 0 ||
(LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)) {
return -1;
}
2021-02-14 16:29:50 +03:00
return 0;
2021-02-14 16:29:50 +03:00
}
int sc_sock_cleanup()
{
int rc;
2021-02-14 16:29:50 +03:00
rc = WSACleanup();
return rc != 0 ? -1 : 0;
2021-02-14 16:29:50 +03:00
}
int sc_sock_notify_systemd(const char *msg)
{
return -1;
}
2020-11-25 09:25:38 +03:00
#else
#include <arpa/inet.h>
#include <assert.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/un.h>
#include <unistd.h>
#define sc_close(n) close(n)
#define sc_unlink(n) unlink(n)
#define SC_ERR (-1)
#define SC_INVALID (-1)
#define SC_EAGAIN EAGAIN
#define SC_EINPROGRESS EINPROGRESS
#define SC_EINTR EINTR
2020-11-25 09:25:38 +03:00
int sc_sock_notify_systemd(const char *msg)
{
assert(msg != NULL);
int fd, rc;
const char *s;
2021-04-07 04:55:05 +03:00
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
};
struct iovec iovec = {
.iov_base = (char *) msg,
.iov_len = strlen(msg),
};
struct msghdr msghdr = {
.msg_name = &addr,
.msg_iov = &iovec,
.msg_iovlen = 1,
};
s = getenv("NOTIFY_SOCKET");
if (!s) {
errno = EINVAL;
return -1;
}
if ((s[0] != '@' && s[0] != '/') || s[1] == '\0') {
errno = EINVAL;
return -1;
}
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
return -1;
}
strncpy(addr.sun_path, s, sizeof(addr.sun_path) - 1);
if (addr.sun_path[0] == '@') {
addr.sun_path[0] = '\0';
}
msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(s);
if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) {
msghdr.msg_namelen = sizeof(struct sockaddr_un);
}
rc = sendmsg(fd, &msghdr, MSG_NOSIGNAL);
close(fd);
return rc < 0 ? -1 : 0;
}
2021-02-14 16:29:50 +03:00
int sc_sock_startup()
{
return 0;
2021-02-14 16:29:50 +03:00
}
int sc_sock_cleanup()
{
return 0;
2021-02-14 16:29:50 +03:00
}
2020-11-25 09:25:38 +03:00
static int sc_sock_err()
{
return errno;
2020-11-25 09:25:38 +03:00
}
static void sc_sock_errstr(struct sc_sock *s, int gai_err)
2020-11-25 09:25:38 +03:00
{
const char *str;
2020-11-25 09:25:38 +03:00
str = gai_err ? gai_strerror(gai_err) : strerror(errno);
strncpy(s->err, str, sizeof(s->err) - 1);
2020-11-25 09:25:38 +03:00
}
int sc_sock_set_blocking(struct sc_sock *s, bool blocking)
2020-11-25 09:25:38 +03:00
{
int flags;
2020-11-25 09:25:38 +03:00
flags = fcntl(s->fdt.fd, F_GETFL, 0);
if (flags == -1) {
return -1;
}
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(s->fdt.fd, F_SETFL, flags) == 0) ? 0 : -1;
2020-11-25 09:25:38 +03:00
}
#endif
void sc_sock_init(struct sc_sock *s, int type, bool blocking, int family)
2020-11-25 09:25:38 +03:00
{
s->fdt.fd = -1;
s->fdt.type = type;
s->fdt.op = SC_SOCK_NONE;
s->fdt.index = -1;
s->blocking = blocking;
s->family = family;
2020-11-25 09:25:38 +03:00
memset(s->err, 0, sizeof(s->err));
2020-11-25 09:25:38 +03:00
}
static int sc_sock_close(struct sc_sock *s)
2020-11-25 09:25:38 +03:00
{
int rc = 0;
2020-11-25 09:25:38 +03:00
if (s->fdt.fd != -1) {
rc = sc_close(s->fdt.fd);
s->fdt.fd = -1;
}
2020-11-25 09:25:38 +03:00
return (rc == 0) ? 0 : -1;
2020-11-25 09:25:38 +03:00
}
int sc_sock_term(struct sc_sock *s)
2020-11-25 09:25:38 +03:00
{
int rc;
2020-11-25 09:25:38 +03:00
rc = sc_sock_close(s);
if (rc != 0) {
sc_sock_errstr(s, 0);
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
}
int sc_sock_set_rcvtimeo(struct sc_sock *s, int ms)
2020-12-28 11:03:24 +03:00
{
int rc;
void *p;
2020-12-28 11:03:24 +03:00
struct timeval tv = {
.tv_usec = ms % 1000,
.tv_sec = ms / 1000,
};
2020-12-28 11:03:24 +03:00
p = (void *) &tv;
2021-02-03 08:09:50 +03:00
rc = setsockopt(s->fdt.fd, SOL_SOCKET, SO_RCVTIMEO, p, sizeof(tv));
if (rc != 0) {
sc_sock_errstr(s, 0);
}
2020-12-28 11:03:24 +03:00
return rc;
2020-12-28 11:03:24 +03:00
}
int sc_sock_set_sndtimeo(struct sc_sock *s, int ms)
2020-12-28 11:03:24 +03:00
{
int rc;
void *p;
2020-12-28 11:03:24 +03:00
struct timeval tv = {
.tv_usec = ms % 1000,
.tv_sec = ms / 1000,
};
2020-12-28 11:03:24 +03:00
p = (void *) &tv;
2021-02-03 08:09:50 +03:00
rc = setsockopt(s->fdt.fd, SOL_SOCKET, SO_SNDTIMEO, p, sizeof(tv));
if (rc != 0) {
sc_sock_errstr(s, 0);
}
2020-12-28 11:03:24 +03:00
return rc;
2020-12-28 11:03:24 +03:00
}
static int sc_sock_bind_unix(struct sc_sock *s, const char *host)
2020-11-25 09:25:38 +03:00
{
int rc;
2021-04-07 04:55:05 +03:00
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
};
2020-11-25 09:25:38 +03:00
strncpy(addr.sun_path, host, sizeof(addr.sun_path) - 1);
sc_unlink(host);
2020-11-25 09:25:38 +03:00
rc = bind(s->fdt.fd, (struct sockaddr *) &addr, sizeof(addr));
2020-11-25 09:25:38 +03:00
return rc == 0 ? 0 : -1;
2020-11-25 09:25:38 +03:00
}
static int sc_sock_bind(struct sc_sock *s, const char *host, const char *port)
2020-11-25 09:25:38 +03:00
{
int rc, rv = 0;
struct addrinfo *servinfo = NULL;
2021-04-07 04:55:05 +03:00
struct addrinfo hints = {
.ai_family = s->family,
.ai_socktype = SOCK_STREAM,
};
2020-11-25 09:25:38 +03:00
*s->err = '\0';
2020-11-25 09:25:38 +03:00
if (s->family == AF_UNIX) {
sc_sock_int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == SC_INVALID) {
goto error_unix;
}
2020-11-25 09:25:38 +03:00
s->fdt.fd = fd;
2020-11-25 09:25:38 +03:00
rc = sc_sock_bind_unix(s, host);
if (rc != 0) {
goto error_unix;
}
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
error_unix:
sc_sock_errstr(s, 0);
sc_sock_close(s);
return -1;
}
rc = getaddrinfo(host, port, &hints, &servinfo);
if (rc != 0) {
sc_sock_errstr(s, rc);
return -1;
}
for (struct addrinfo *p = servinfo; p != NULL; p = p->ai_next) {
const int tsz = sizeof(int);
sc_sock_int fd;
void *tmp;
fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (fd == SC_INVALID) {
continue;
}
s->fdt.fd = fd;
if (s->family == AF_INET6) {
rc = setsockopt(s->fdt.fd, IPPROTO_IPV6, IPV6_V6ONLY,
(void *) &(int){1}, tsz);
if (rc != 0) {
goto error;
}
}
rc = sc_sock_set_blocking(s, s->blocking);
if (rc != 0) {
goto error;
}
tmp = (void *) &(int){1};
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, tmp, sizeof(int));
if (rc != 0) {
goto error;
}
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, tmp, sizeof(int));
if (rc != 0) {
goto error;
}
rc = bind(s->fdt.fd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rc == -1) {
goto error;
}
goto out;
}
2020-11-25 09:25:38 +03:00
error:
sc_sock_errstr(s, 0);
sc_sock_close(s);
rv = -1;
2020-11-25 09:25:38 +03:00
out:
freeaddrinfo(servinfo);
2020-11-25 09:25:38 +03:00
return rv;
2020-11-25 09:25:38 +03:00
}
int sc_sock_finish_connect(struct sc_sock *s)
2020-11-25 09:25:38 +03:00
{
int ret, rc;
socklen_t len = sizeof(ret);
2020-11-25 09:25:38 +03:00
rc = getsockopt(s->fdt.fd, SOL_SOCKET, SO_ERROR, (void *) &ret, &len);
if (rc == 0 && ret != 0) {
errno = ret;
rc = -1;
}
if (rc != 0) {
sc_sock_errstr(s, 0);
return -1;
}
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
static int sc_sock_connect_unix(struct sc_sock *s, const char *addr)
2020-11-25 09:25:38 +03:00
{
const size_t len = strlen(addr);
2020-11-25 09:25:38 +03:00
int rc;
sc_sock_int fd;
2021-04-07 04:55:05 +03:00
struct sockaddr_un un = {
.sun_family = AF_UNIX,
};
2020-11-25 09:25:38 +03:00
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == SC_INVALID) {
goto err;
}
2020-11-25 09:25:38 +03:00
s->fdt.fd = fd;
2020-11-25 09:25:38 +03:00
if (len >= sizeof(un.sun_path)) {
errno = EINVAL;
goto err;
}
2020-11-25 09:25:38 +03:00
strcpy(un.sun_path, addr);
2020-11-25 09:25:38 +03:00
rc = connect(s->fdt.fd, (struct sockaddr *) &un, sizeof(un));
if (rc != 0) {
goto err;
}
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
err:
sc_sock_errstr(s, 0);
sc_sock_close(s);
2020-11-25 09:25:38 +03:00
return -1;
}
static int sc_sock_bind_src(struct sc_sock *s, const char *addr,
const char *port)
{
int rc;
struct addrinfo *p = NULL, *i;
struct addrinfo inf = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
};
2020-11-25 09:25:38 +03:00
rc = getaddrinfo(addr, port, &inf, &p);
if (rc != 0) {
goto gai_err;
}
2020-11-25 09:25:38 +03:00
for (i = p; i != NULL; i = i->ai_next) {
rc = bind(s->fdt.fd, i->ai_addr, (socklen_t) i->ai_addrlen);
if (rc != -1) {
break;
}
}
freeaddrinfo(p);
if (rc == -1) {
goto err;
}
return 0;
gai_err:
sc_sock_errstr(s, rc);
return -1;
err:
sc_sock_errstr(s, 0);
return -1;
}
int sc_sock_connect(struct sc_sock *s, const char *dst_addr,
const char *dst_port, const char *src_addr,
const char *src_port)
{
int family = s->family;
int rc, rv = 0;
sc_sock_int fd;
2021-04-07 04:55:05 +03:00
void *tmp;
struct addrinfo *sinfo = NULL, *p;
struct addrinfo inf = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
};
if (family == AF_UNIX) {
return sc_sock_connect_unix(s, dst_addr);
}
rc = getaddrinfo(dst_addr, dst_port, &inf, &sinfo);
if (rc != 0) {
sc_sock_errstr(s, rc);
return -1;
}
for (int i = 0; i < 2; i++) {
for (p = sinfo; p != NULL; p = p->ai_next) {
// Try same family addresses in the first iteration.
if ((i == 0) ^ (p->ai_family == family)) {
continue;
}
fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (fd == SC_INVALID) {
continue;
}
s->family = p->ai_family;
s->fdt.fd = fd;
rc = sc_sock_set_blocking(s, s->blocking);
if (rc != 0) {
goto error;
}
tmp = (void *) &(int){1};
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, tmp, sizeof(int));
if (rc != 0) {
goto error;
}
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, tmp, sizeof(int));
if (rc != 0) {
goto error;
}
if (src_addr || src_port) {
rc = sc_sock_bind_src(s, src_addr, src_port);
if (rc != 0) {
goto bind_error;
}
}
rc = connect(fd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rc != 0) {
if (!s->blocking && (sc_sock_err() == SC_EINPROGRESS ||
sc_sock_err() == SC_EAGAIN)) {
errno = EAGAIN;
rv = -1;
goto end;
}
sc_sock_close(s);
continue;
}
goto end;
}
}
2020-11-25 09:25:38 +03:00
error:
sc_sock_errstr(s, 0);
bind_error:
rv = -1;
sc_sock_close(s);
2020-11-25 09:25:38 +03:00
end:
freeaddrinfo(sinfo);
2020-11-25 09:25:38 +03:00
return rv;
2020-11-25 09:25:38 +03:00
}
int sc_sock_send(struct sc_sock *s, char *buf, int len, int flags)
2020-11-25 09:25:38 +03:00
{
int n, err;
2020-11-25 09:25:38 +03:00
if (len <= 0) {
return len;
}
2020-11-25 09:25:38 +03:00
retry:
n = (int) send(s->fdt.fd, buf, (size_t) len, flags);
if (n == SC_ERR) {
err = sc_sock_err();
if (err == SC_EINTR) {
goto retry;
}
2020-11-25 09:25:38 +03:00
if (err == SC_EAGAIN) {
errno = EAGAIN;
return -1;
}
2020-11-25 09:25:38 +03:00
sc_sock_errstr(s, 0);
n = -1;
}
2020-11-25 09:25:38 +03:00
return n;
2020-11-25 09:25:38 +03:00
}
int sc_sock_recv(struct sc_sock *s, char *buf, int len, int flags)
2020-11-25 09:25:38 +03:00
{
int n, err;
2020-11-25 09:25:38 +03:00
if (len <= 0) {
return len;
}
2020-11-25 09:25:38 +03:00
retry:
n = (int) recv(s->fdt.fd, buf, (size_t) len, flags);
if (n == 0) {
errno = EOF;
return -1;
} else if (n == SC_ERR) {
err = sc_sock_err();
if (err == SC_EINTR) {
goto retry;
}
if (err == SC_EAGAIN) {
errno = EAGAIN;
return -1;
}
sc_sock_errstr(s, 0);
n = -1;
}
return n;
}
int sc_sock_accept(struct sc_sock *s, struct sc_sock *in)
{
const void *tmp = (void *) &(int){1};
int rc;
sc_sock_int fd;
fd = accept(s->fdt.fd, NULL, NULL);
if (fd == SC_INVALID) {
sc_sock_errstr(s, 0);
return -1;
}
in->fdt.fd = fd;
in->fdt.op = SC_SOCK_NONE;
in->family = s->family;
if (in->family != AF_UNIX) {
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, tmp, sizeof(int));
if (rc != 0) {
goto error;
}
}
rc = sc_sock_set_blocking(in, s->blocking);
if (rc != 0) {
goto error;
}
return 0;
2020-11-25 09:25:38 +03:00
error:
sc_sock_errstr(s, 0);
sc_sock_close(in);
2020-11-25 09:25:38 +03:00
return -1;
2020-11-25 09:25:38 +03:00
}
int sc_sock_listen(struct sc_sock *s, const char *host, const char *port)
2020-11-25 09:25:38 +03:00
{
int rc;
2020-11-25 09:25:38 +03:00
rc = sc_sock_bind(s, host, port);
if (rc != 0) {
return rc;
}
2020-11-25 09:25:38 +03:00
rc = listen(s->fdt.fd, 4096);
if (rc != 0) {
goto err;
}
2020-11-25 09:25:38 +03:00
return 0;
err:
sc_sock_errstr(s, 0);
sc_sock_close(s);
return -1;
2020-11-25 09:25:38 +03:00
}
const char *sc_sock_error(struct sc_sock *s)
2020-11-25 09:25:38 +03:00
{
s->err[sizeof(s->err) - 1] = '\0';
return s->err;
2020-11-25 09:25:38 +03:00
}
static const char *sc_sock_addr(struct sc_sock *sock, int af, void *cp,
char *buf, socklen_t len)
2020-11-25 09:25:38 +03:00
{
const char *dest;
2020-11-25 09:25:38 +03:00
dest = inet_ntop(af, cp, buf, len);
if (dest == NULL) {
sc_sock_errstr(sock, 0);
*buf = '\0';
}
2020-11-25 09:25:38 +03:00
return dest;
2020-11-25 09:25:38 +03:00
}
static const char *sc_sock_print_storage(struct sc_sock *sock,
struct sockaddr_storage *storage,
char *buf, size_t len)
2020-11-25 09:25:38 +03:00
{
const char *dst;
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
struct sockaddr_un *addr_un;
char tmp[INET6_ADDRSTRLEN];
2020-11-25 09:25:38 +03:00
*buf = '\0';
2020-11-25 09:25:38 +03:00
switch (storage->ss_family) {
case AF_INET:
addr = (struct sockaddr_in *) storage;
dst = sc_sock_addr(sock, AF_INET, &addr->sin_addr, tmp,
sizeof(tmp));
snprintf(buf, len, "%s:%d", dst, ntohs(addr->sin_port));
break;
2020-11-25 09:25:38 +03:00
case AF_INET6:
addr6 = (struct sockaddr_in6 *) storage;
dst = sc_sock_addr(sock, AF_INET6, &addr6->sin6_addr, tmp,
sizeof(tmp));
snprintf(buf, len, "%s:%d", dst, ntohs(addr6->sin6_port));
break;
2020-11-25 09:25:38 +03:00
case AF_UNIX:
addr_un = (struct sockaddr_un *) storage;
snprintf(buf, len, "%s", addr_un->sun_path);
break;
}
2020-11-25 09:25:38 +03:00
return buf;
2020-11-25 09:25:38 +03:00
}
2021-01-24 17:56:18 +03:00
const char *sc_sock_local_str(struct sc_sock *sock, char *buf, size_t len)
2020-11-25 09:25:38 +03:00
{
int rc;
struct sockaddr_storage st;
socklen_t storage_len = sizeof(st);
2020-11-25 09:25:38 +03:00
rc = getsockname(sock->fdt.fd, (struct sockaddr *) &st, &storage_len);
if (rc != 0) {
sc_sock_errstr(sock, 0);
*buf = '\0';
return NULL;
}
2020-11-25 09:25:38 +03:00
return sc_sock_print_storage(sock, &st, buf, len);
2020-11-25 09:25:38 +03:00
}
2021-01-24 17:56:18 +03:00
const char *sc_sock_remote_str(struct sc_sock *sock, char *buf, size_t len)
2020-11-25 09:25:38 +03:00
{
int rc;
struct sockaddr_storage st;
socklen_t storage_len = sizeof(st);
2020-11-25 09:25:38 +03:00
rc = getpeername(sock->fdt.fd, (struct sockaddr *) &st, &storage_len);
if (rc != 0) {
sc_sock_errstr(sock, 0);
*buf = '\0';
return NULL;
}
2020-11-25 09:25:38 +03:00
return sc_sock_print_storage(sock, &st, buf, len);
2020-11-25 09:25:38 +03:00
}
2021-01-24 17:56:18 +03:00
void sc_sock_print(struct sc_sock *sock, char *buf, size_t len)
2020-11-25 09:25:38 +03:00
{
char l[128];
char r[128];
2020-11-25 09:25:38 +03:00
sc_sock_local_str(sock, l, sizeof(l));
sc_sock_remote_str(sock, r, sizeof(r));
2020-11-25 09:25:38 +03:00
snprintf(buf, len, "Local(%s), Remote(%s) ", l, r);
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
const char *sc_sock_pipe_err(struct sc_sock_pipe *pipe)
{
return pipe->err;
2021-02-04 02:35:34 +03:00
}
static void sc_sock_pipe_set_err(struct sc_sock_pipe *pipe, const char *fmt,
...)
2021-02-04 02:35:34 +03:00
{
va_list args;
2021-02-04 02:35:34 +03:00
va_start(args, fmt);
vsnprintf(pipe->err, sizeof(pipe->err), fmt, args);
va_end(args);
2021-02-04 02:35:34 +03:00
pipe->err[sizeof(pipe->err) - 1] = '\0';
2021-02-04 02:35:34 +03:00
}
2020-11-25 09:25:38 +03:00
#if defined(_WIN32) || defined(_WIN64)
int sc_sock_pipe_init(struct sc_sock_pipe *p, int type)
{
SOCKET listener;
int rc;
struct sockaddr_in addr;
int addrlen = sizeof(addr);
int val = 1;
BOOL nodelay = 1;
*p = (struct sc_sock_pipe){
.fds = {SC_INVALID, SC_INVALID},
};
p->fdt.type = type;
p->fdt.op = SC_SOCK_NONE;
p->fdt.index = -1;
p->fds[0] = INVALID_SOCKET;
p->fds[1] = INVALID_SOCKET;
/* Create listening socket. */
listener = socket(AF_INET, SOCK_STREAM, 0);
if (listener == SOCKET_ERROR) {
goto wsafail;
}
rc = setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(char *) &val, sizeof(val));
if (rc == SOCKET_ERROR) {
goto wsafail;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = 0;
rc = bind(listener, (const struct sockaddr *) &addr, sizeof(addr));
if (rc == SOCKET_ERROR) {
goto wsafail;
}
rc = getsockname(listener, (struct sockaddr *) &addr, &addrlen);
if (rc == SOCKET_ERROR) {
goto wsafail;
}
rc = listen(listener, 1);
if (rc == SOCKET_ERROR) {
goto wsafail;
}
p->fds[1] = socket(AF_INET, SOCK_STREAM, 0);
if (p->fds[1] == SOCKET_ERROR) {
goto wsafail;
}
rc = setsockopt(p->fds[1], IPPROTO_TCP, TCP_NODELAY, (char *) &nodelay,
sizeof(nodelay));
if (rc == SOCKET_ERROR) {
goto wsafail;
}
rc = connect(p->fds[1], (struct sockaddr *) &addr, sizeof(addr));
if (rc == SOCKET_ERROR) {
goto wsafail;
}
p->fds[0] = accept(listener, (struct sockaddr *) &addr, &addrlen);
if (p->fds[0] == INVALID_SOCKET) {
goto wsafail;
}
closesocket(listener);
return 0;
2020-11-25 09:25:38 +03:00
wsafail:
sc_sock_pipe_set_err(p, "sc_sock_pipe_init() : %d ", WSAGetLastError());
return -1;
2020-11-25 09:25:38 +03:00
}
int sc_sock_pipe_term(struct sc_sock_pipe *p)
{
int rc = 0, rv;
2020-11-25 09:25:38 +03:00
if (p->fds[0] == SC_INVALID) {
return 0;
}
rv = closesocket(p->fds[0]);
if (rv != 0) {
rc = -1;
sc_sock_pipe_set_err(p, "closesocket() : err(%d) ",
WSAGetLastError());
}
2020-11-25 09:25:38 +03:00
rv = closesocket(p->fds[1]);
if (rv != 0) {
rc = -1;
sc_sock_pipe_set_err(p, "closesocket() : err(%d) ",
WSAGetLastError());
}
2020-11-25 09:25:38 +03:00
p->fds[0] = SC_INVALID;
p->fds[1] = SC_INVALID;
return rc;
2020-11-25 09:25:38 +03:00
}
2021-02-03 08:09:50 +03:00
int sc_sock_pipe_write(struct sc_sock_pipe *p, void *data, unsigned int len)
2020-11-25 09:25:38 +03:00
{
int rc;
2020-11-25 09:25:38 +03:00
rc = send(p->fds[1], data, len, 0);
if (rc == SOCKET_ERROR || (unsigned int) rc != len) {
sc_sock_pipe_set_err(p, "pipe send() : err(%d) ",
WSAGetLastError());
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
}
2021-02-03 08:09:50 +03:00
int sc_sock_pipe_read(struct sc_sock_pipe *p, void *data, unsigned int len)
2020-11-25 09:25:38 +03:00
{
int rc;
2020-11-25 09:25:38 +03:00
rc = recv(p->fds[0], (char *) data, len, 0);
if (rc == SOCKET_ERROR || (unsigned int) rc != len) {
sc_sock_pipe_set_err(p, "pipe recv() : err(%d) ",
WSAGetLastError());
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
}
#else
int sc_sock_pipe_init(struct sc_sock_pipe *p, int type)
{
int rc;
2020-11-25 09:25:38 +03:00
*p = (struct sc_sock_pipe){
.fds = {SC_INVALID, SC_INVALID},
};
rc = pipe(p->fds);
if (rc != 0) {
sc_sock_pipe_set_err(p, "pipe() : %s ", strerror(errno));
return -1;
}
2020-11-25 09:25:38 +03:00
p->fdt.type = type;
p->fdt.op = SC_SOCK_NONE;
p->fdt.fd = p->fds[0];
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
int sc_sock_pipe_term(struct sc_sock_pipe *p)
{
int rc = 0, rv;
2020-11-25 09:25:38 +03:00
if (p->fds[0] == SC_INVALID) {
return 0;
}
rv = close(p->fds[0]);
if (rv != 0) {
rc = -1;
sc_sock_pipe_set_err(p, "pipe close() : %s ", strerror(errno));
}
2020-11-25 09:25:38 +03:00
rv = close(p->fds[1]);
if (rv != 0) {
rc = -1;
sc_sock_pipe_set_err(p, "pipe close() : %s ", strerror(errno));
}
2020-11-25 09:25:38 +03:00
p->fds[0] = SC_INVALID;
p->fds[1] = SC_INVALID;
return rc;
2020-11-25 09:25:38 +03:00
}
2021-01-24 17:56:18 +03:00
int sc_sock_pipe_write(struct sc_sock_pipe *p, void *data, unsigned int len)
2020-11-25 09:25:38 +03:00
{
ssize_t n;
char *b = data;
2020-11-25 09:25:38 +03:00
retry:
n = write(p->fds[1], b, len);
if (n == -1 && errno == EINTR) {
goto retry;
}
2020-11-25 09:25:38 +03:00
return n;
2020-11-25 09:25:38 +03:00
}
2021-01-24 17:56:18 +03:00
int sc_sock_pipe_read(struct sc_sock_pipe *p, void *data, unsigned int len)
2020-11-25 09:25:38 +03:00
{
ssize_t n;
char *b = data;
2020-11-25 09:25:38 +03:00
retry:
n = read(p->fds[0], b, len);
if (n == -1 && errno == EINTR) {
goto retry;
}
2020-11-25 09:25:38 +03:00
return n;
2020-11-25 09:25:38 +03:00
}
#endif
2021-02-04 02:35:34 +03:00
const char *sc_sock_poll_err(struct sc_sock_poll *p)
{
return p->err;
2021-02-04 02:35:34 +03:00
}
static void sc_sock_poll_set_err(struct sc_sock_poll *p, const char *fmt, ...)
{
va_list args;
2021-02-04 02:35:34 +03:00
va_start(args, fmt);
vsnprintf(p->err, sizeof(p->err), fmt, args);
va_end(args);
2021-02-04 02:35:34 +03:00
p->err[sizeof(p->err) - 1] = '\0';
2021-02-04 02:35:34 +03:00
}
2020-11-25 09:25:38 +03:00
#if defined(__linux__)
2021-02-04 02:35:34 +03:00
int sc_sock_poll_init(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int fds;
2020-11-25 09:25:38 +03:00
*p = (struct sc_sock_poll){0};
2020-11-25 09:25:38 +03:00
p->events = sc_sock_malloc(sizeof(*p->events) * 16);
if (p->events == NULL) {
errno = ENOMEM;
goto error;
}
2020-11-25 09:25:38 +03:00
fds = epoll_create1(0);
if (fds == -1) {
goto error;
}
2020-11-25 09:25:38 +03:00
p->cap = 16;
p->fds = fds;
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
error:
sc_sock_poll_set_err(p, strerror(errno));
sc_sock_free(p->events);
p->events = NULL;
p->fds = -1;
2020-11-25 09:25:38 +03:00
return -1;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_term(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int rc;
if (!p->events) {
return 0;
}
sc_sock_free(p->events);
rc = close(p->fds);
if (rc != 0) {
sc_sock_poll_set_err(p, strerror(errno));
}
p->events = NULL;
p->fds = SC_INVALID;
p->cap = 0;
p->count = 0;
return rc;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
static int sc_sock_poll_expand(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int cap, rc = 0;
void *ev;
2020-11-25 09:25:38 +03:00
if (p->count == p->cap) {
if (p->cap >= SC_SIZE_MAX / 2) {
goto error;
}
2020-11-25 09:25:38 +03:00
cap = p->cap * 2;
ev = sc_sock_realloc(p->events, cap * sizeof(*p->events));
if (ev == NULL) {
goto error;
}
2020-11-25 09:25:38 +03:00
p->cap = cap;
p->events = ev;
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
error:
sc_sock_poll_set_err(p, "Out of memory.");
return -1;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_add(struct sc_sock_poll *p, struct sc_sock_fd *fdt,
enum sc_sock_ev events, void *data)
2020-11-25 09:25:38 +03:00
{
int rc, op = EPOLL_CTL_MOD;
enum sc_sock_ev mask = fdt->op | events;
2020-11-25 09:25:38 +03:00
struct epoll_event ep_ev = {
.data.ptr = data,
.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP,
};
2020-11-25 09:25:38 +03:00
if ((fdt->op & events) == events) {
return 0;
}
2020-11-25 09:25:38 +03:00
if (fdt->op == SC_SOCK_NONE) {
rc = sc_sock_poll_expand(p);
if (rc != 0) {
return -1;
}
2020-11-25 09:25:38 +03:00
op = EPOLL_CTL_ADD;
}
2020-11-25 09:25:38 +03:00
if (mask & SC_SOCK_READ) {
ep_ev.events |= EPOLLIN;
}
2020-11-25 09:25:38 +03:00
if (mask & SC_SOCK_WRITE) {
ep_ev.events |= EPOLLOUT;
}
2020-11-25 09:25:38 +03:00
rc = epoll_ctl(p->fds, op, fdt->fd, &ep_ev);
if (rc != 0) {
sc_sock_poll_set_err(p, "epoll_ctl : %s ", strerror(errno));
return -1;
}
2020-11-25 09:25:38 +03:00
p->count += fdt->op == SC_SOCK_NONE;
fdt->op = mask;
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_del(struct sc_sock_poll *p, struct sc_sock_fd *fdt,
enum sc_sock_ev events, void *data)
2020-11-25 09:25:38 +03:00
{
int rc, op;
2021-04-07 04:55:05 +03:00
struct epoll_event ep_ev = {
.data.ptr = data,
.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP,
};
2020-11-25 09:25:38 +03:00
if ((fdt->op & events) == 0) {
return 0;
}
2020-11-25 09:25:38 +03:00
fdt->op &= ~events;
op = fdt->op == SC_SOCK_NONE ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
2020-11-25 09:25:38 +03:00
if (fdt->op & SC_SOCK_READ) {
ep_ev.events |= EPOLLIN;
}
2020-11-25 09:25:38 +03:00
if (fdt->op & SC_SOCK_WRITE) {
ep_ev.events |= EPOLLOUT;
}
2020-11-25 09:25:38 +03:00
rc = epoll_ctl(p->fds, op, fdt->fd, &ep_ev);
if (rc != 0) {
sc_sock_poll_set_err(p, "epoll_ctl : %s ", strerror(errno));
return -1;
}
2020-11-25 09:25:38 +03:00
if (fdt->op == SC_SOCK_NONE) {
p->count--;
}
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
void *sc_sock_poll_data(struct sc_sock_poll *p, int i)
2020-11-25 09:25:38 +03:00
{
return p->events[i].data.ptr;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
uint32_t sc_sock_poll_event(struct sc_sock_poll *p, int i)
2020-11-25 09:25:38 +03:00
{
uint32_t ev = 0;
uint32_t epoll_ev = p->events[i].events;
2020-11-25 09:25:38 +03:00
if (epoll_ev & EPOLLIN) {
ev |= SC_SOCK_READ;
}
2020-11-25 09:25:38 +03:00
if (epoll_ev & EPOLLOUT) {
ev |= SC_SOCK_WRITE;
}
2020-11-25 09:25:38 +03:00
epoll_ev &= EPOLLHUP | EPOLLRDHUP | EPOLLERR;
if (epoll_ev != 0) {
ev = (SC_SOCK_READ | SC_SOCK_WRITE);
}
2020-11-25 09:25:38 +03:00
return ev;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_wait(struct sc_sock_poll *p, int timeout)
2020-11-25 09:25:38 +03:00
{
int n;
2020-11-25 09:25:38 +03:00
do {
n = epoll_wait(p->fds, &p->events[0], p->cap, timeout);
} while (n < 0 && errno == EINTR);
2020-11-25 09:25:38 +03:00
if (n == -1) {
sc_sock_poll_set_err(p, "epoll_wait : %s ", strerror(errno));
}
2020-11-25 09:25:38 +03:00
return n;
2020-11-25 09:25:38 +03:00
}
#elif defined(__APPLE__) || defined(__FreeBSD__)
2021-02-04 02:35:34 +03:00
int sc_sock_poll_init(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int fds;
2020-11-25 09:25:38 +03:00
*p = (struct sc_sock_poll){0};
2020-11-25 09:25:38 +03:00
p->events = sc_sock_malloc(sizeof(*p->events) * 16);
if (p->events == NULL) {
errno = ENOMEM;
goto err;
}
2020-11-25 09:25:38 +03:00
fds = kqueue();
if (fds == -1) {
goto err;
}
2020-11-25 09:25:38 +03:00
p->cap = 16;
p->fds = fds;
2020-11-25 09:25:38 +03:00
return 0;
err:
sc_sock_poll_set_err(p, strerror(errno));
sc_sock_free(p->events);
p->events = NULL;
p->fds = -1;
2020-11-25 09:25:38 +03:00
return -1;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
static int sc_sock_poll_expand(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int rc = 0, cap;
void *ev;
2020-11-25 09:25:38 +03:00
if (p->count == p->cap) {
if (p->cap >= SC_SIZE_MAX / 2) {
goto err;
}
2020-11-25 09:25:38 +03:00
cap = p->cap * 2;
ev = sc_sock_realloc(p->events, cap * sizeof(*p->events));
if (ev == NULL) {
goto err;
}
2020-11-25 09:25:38 +03:00
p->cap = cap;
p->events = ev;
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
err:
sc_sock_poll_set_err(p, "Out of memory.");
return -1;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_term(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int rc;
if (!p->events) {
return 0;
}
sc_sock_free(p->events);
rc = close(p->fds);
if (rc != 0) {
sc_sock_poll_set_err(p, strerror(errno));
}
p->events = NULL;
p->fds = SC_INVALID;
p->cap = 0;
p->count = 0;
return rc;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_add(struct sc_sock_poll *p, struct sc_sock_fd *fdt,
enum sc_sock_ev events, void *data)
2020-11-25 09:25:38 +03:00
{
int rc, count = 0;
struct kevent ev[2];
int mask = fdt->op | events;
2020-11-25 09:25:38 +03:00
if ((fdt->op & events) == events) {
2021-04-27 20:44:34 +03:00
return 0;
}
2020-11-25 09:25:38 +03:00
if (fdt->op == SC_SOCK_NONE) {
rc = sc_sock_poll_expand(p);
if (rc != 0) {
return -1;
}
}
2020-11-25 09:25:38 +03:00
if (mask & SC_SOCK_WRITE) {
EV_SET(&ev[count++], fdt->fd, EVFILT_WRITE, EV_ADD, 0, 0, data);
}
2020-11-25 09:25:38 +03:00
if (mask & SC_SOCK_READ) {
EV_SET(&ev[count++], fdt->fd, EVFILT_READ, EV_ADD, 0, 0, data);
}
2020-11-25 09:25:38 +03:00
rc = kevent(p->fds, ev, count, NULL, 0, NULL);
if (rc != 0) {
sc_sock_poll_set_err(p, "kevent : %s ", strerror(errno));
return -1;
}
2020-11-25 09:25:38 +03:00
p->count += fdt->op == SC_SOCK_NONE;
fdt->op = mask;
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_del(struct sc_sock_poll *p, struct sc_sock_fd *fdt,
enum sc_sock_ev events, void *data)
2020-11-25 09:25:38 +03:00
{
(void) data;
2021-02-07 22:36:57 +03:00
int rc, count = 0;
struct kevent ev[2];
int mask = fdt->op & events;
2020-11-25 09:25:38 +03:00
if (mask == 0) {
return 0;
}
2020-11-25 09:25:38 +03:00
if (mask & SC_SOCK_READ) {
EV_SET(&ev[count++], fdt->fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
}
2020-11-25 09:25:38 +03:00
if (mask & SC_SOCK_WRITE) {
EV_SET(&ev[count++], fdt->fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
}
2020-11-25 09:25:38 +03:00
rc = kevent(p->fds, ev, count, NULL, 0, NULL);
if (rc != 0) {
sc_sock_poll_set_err(p, "kevent : %s ", strerror(errno));
return -1;
}
2020-11-25 09:25:38 +03:00
fdt->op &= ~events;
p->count -= fdt->op == SC_SOCK_NONE;
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
void *sc_sock_poll_data(struct sc_sock_poll *p, int i)
2020-11-25 09:25:38 +03:00
{
return p->events[i].udata;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
uint32_t sc_sock_poll_event(struct sc_sock_poll *p, int i)
2020-11-25 09:25:38 +03:00
{
uint32_t events = 0;
2020-11-25 09:25:38 +03:00
if (p->events[i].flags & EV_EOF) {
events = (SC_SOCK_READ | SC_SOCK_WRITE);
} else if (p->events[i].filter == EVFILT_READ) {
events |= SC_SOCK_READ;
} else if (p->events[i].filter == EVFILT_WRITE) {
events |= SC_SOCK_WRITE;
}
2020-11-25 09:25:38 +03:00
return events;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_wait(struct sc_sock_poll *p, int timeout)
2020-11-25 09:25:38 +03:00
{
int n;
struct timespec ts;
2020-11-25 09:25:38 +03:00
do {
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
2020-11-25 09:25:38 +03:00
n = kevent(p->fds, NULL, 0, &p->events[0], p->cap,
timeout >= 0 ? &ts : NULL);
} while (n < 0 && errno == EINTR);
2020-11-25 09:25:38 +03:00
if (n == -1) {
sc_sock_poll_set_err(p, "kevent : %s ", strerror(errno));
}
2020-11-25 09:25:38 +03:00
return n;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
#else // WINDOWS
int sc_sock_poll_init(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
*p = (struct sc_sock_poll){0};
2020-11-25 09:25:38 +03:00
p->events = sc_sock_malloc(sizeof(*p->events) * 16);
if (p->events == NULL) {
goto err;
}
2020-11-25 09:25:38 +03:00
p->data = sc_sock_malloc(sizeof(void *) * 16);
if (p->data == NULL) {
goto err;
}
2020-11-25 09:25:38 +03:00
p->cap = 16;
2020-11-25 09:25:38 +03:00
for (int i = 0; i < p->cap; i++) {
p->events[i].fd = SC_INVALID;
}
2020-11-25 09:25:38 +03:00
return 0;
err:
sc_sock_free(p->events);
p->events = NULL;
p->data = NULL;
sc_sock_poll_set_err(p, "Out of memory.");
return -1;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_term(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
if (p->events == NULL) {
return 0;
}
sc_sock_free(p->events);
sc_sock_free(p->data);
p->events = NULL;
p->cap = 0;
p->count = 0;
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-14 16:29:50 +03:00
static int sc_sock_poll_expand(struct sc_sock_poll *p)
2020-11-25 09:25:38 +03:00
{
int cap, rc = 0;
void **data = NULL;
struct pollfd *ev = NULL;
2020-11-25 09:25:38 +03:00
if (p->count == p->cap) {
if (p->cap >= SC_SIZE_MAX / 2) {
goto err;
}
2020-11-25 09:25:38 +03:00
cap = p->cap * 2;
ev = sc_sock_realloc(p->events, cap * sizeof(*ev));
if (ev == NULL) {
goto err;
}
2020-11-25 09:25:38 +03:00
data = sc_sock_realloc(p->data, cap * sizeof(*data));
if (data == NULL) {
goto err;
}
2020-11-25 09:25:38 +03:00
p->events = ev;
p->data = data;
for (int i = p->cap; i < cap; i++) {
p->events[i].fd = SC_INVALID;
}
2020-11-25 09:25:38 +03:00
p->cap = cap;
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
err:
sc_sock_free(ev);
sc_sock_poll_set_err(p, "Out of memory.");
return -1;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_add(struct sc_sock_poll *p, struct sc_sock_fd *fdt,
enum sc_sock_ev events, void *data)
2020-11-25 09:25:38 +03:00
{
int rc;
int index = fdt->index;
2020-11-25 09:25:38 +03:00
if ((fdt->op & events) == events) {
2021-04-27 20:44:34 +03:00
return 0;
}
2020-11-25 09:25:38 +03:00
if (fdt->op == SC_SOCK_NONE) {
rc = sc_sock_poll_expand(p);
if (rc != 0) {
sc_sock_poll_set_err(p, "Out of memory.");
return -1;
}
2020-11-25 09:25:38 +03:00
p->count++;
2020-11-25 09:25:38 +03:00
for (int i = 0; i < p->cap; i++) {
if (p->events[i].fd == SC_INVALID) {
index = i;
break;
}
}
2020-11-25 09:25:38 +03:00
assert(index != -1);
2020-11-25 09:25:38 +03:00
p->events[index].fd = fdt->fd;
fdt->index = index;
}
2020-11-25 09:25:38 +03:00
assert(index != -1);
2020-11-25 09:25:38 +03:00
fdt->op |= events;
2020-11-25 09:25:38 +03:00
p->events[fdt->index].events = 0;
p->events[fdt->index].revents = 0;
2020-11-25 09:25:38 +03:00
if (events & SC_SOCK_READ) {
p->events[fdt->index].events |= POLLIN;
}
2020-11-25 09:25:38 +03:00
if (events & SC_SOCK_WRITE) {
p->events[fdt->index].events |= POLLOUT;
}
2020-11-25 09:25:38 +03:00
p->data[fdt->index] = data;
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
int sc_sock_poll_del(struct sc_sock_poll *p, struct sc_sock_fd *fdt,
enum sc_sock_ev events, void *data)
2020-11-25 09:25:38 +03:00
{
if ((fdt->op & events) == 0) {
return 0;
}
2020-11-25 09:25:38 +03:00
fdt->op &= ~events;
if (fdt->op == SC_SOCK_NONE) {
p->events[fdt->index].fd = SC_INVALID;
p->count--;
fdt->index = -1;
} else {
p->events[fdt->index].events = 0;
2020-11-25 09:25:38 +03:00
if (fdt->op & SC_SOCK_READ) {
p->events[fdt->index].events |= POLLIN;
}
2020-11-25 09:25:38 +03:00
if (fdt->op & SC_SOCK_WRITE) {
p->events[fdt->index].events |= POLLOUT;
}
2020-11-25 09:25:38 +03:00
p->data[fdt->index] = data;
}
2020-11-25 09:25:38 +03:00
return 0;
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
void *sc_sock_poll_data(struct sc_sock_poll *p, int i)
2020-11-25 09:25:38 +03:00
{
return p->data[i];
2020-11-25 09:25:38 +03:00
}
2021-02-04 02:35:34 +03:00
uint32_t sc_sock_poll_event(struct sc_sock_poll *p, int i)
2020-11-25 09:25:38 +03:00
{
uint32_t evs = 0;
uint32_t poll_evs = p->events[i].revents;
2020-11-25 09:25:38 +03:00
if (poll_evs & POLLIN) {
evs |= SC_SOCK_READ;
}
2020-11-25 09:25:38 +03:00
if (poll_evs & POLLOUT) {
evs |= SC_SOCK_WRITE;
}
2020-11-25 09:25:38 +03:00
poll_evs &= POLLHUP | POLLERR;
if (poll_evs != 0) {
evs = (SC_SOCK_READ | SC_SOCK_WRITE);
}
2020-11-25 09:25:38 +03:00
return evs;
2020-11-25 09:25:38 +03:00
}
2021-02-14 16:29:50 +03:00
int sc_sock_poll_wait(struct sc_sock_poll *p, int timeout)
2020-11-25 09:25:38 +03:00
{
int n, rc = p->cap;
2020-11-25 09:25:38 +03:00
timeout = (timeout == -1) ? 16 : timeout;
2020-11-25 09:25:38 +03:00
do {
n = WSAPoll(p->events, (ULONG) p->cap, timeout);
} while (n < 0 && errno == EINTR);
2020-11-25 09:25:38 +03:00
if (n == SC_INVALID) {
rc = -1;
sc_sock_poll_set_err(p, "poll : %s ", strerror(errno));
}
2020-11-25 09:25:38 +03:00
return rc;
2020-11-25 09:25:38 +03:00
}
#endif