vessel/core/socket.c
Arija A. 0a8709bf31
refact: Rename src->core
Signed-off-by: Arija A. <ari@ari.lt>
2025-06-14 02:27:39 +03:00

182 lines
4.3 KiB
C

#include "include/conf.h"
#include "include/socket.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
static int vs_socket_options[_vs_SocketOption_end] = {
/* Sockets */
[vs_SocketOption_sock_reuseaddr] = SO_REUSEADDR,
[vs_SocketOption_sock_broadcast] = SO_BROADCAST,
[vs_SocketOption_sock_keepalive] = SO_KEEPALIVE,
[vs_SocketOption_sock_linger] = SO_LINGER,
[vs_SocketOption_sock_readto] = SO_RCVTIMEO,
[vs_SocketOption_sock_writeto] = SO_SNDTIMEO,
/* TCP */
[vs_SocketOption_tcp_nodelay] = TCP_NODELAY,
[vs_SocketOption_tcp_maxseg] = TCP_MAXSEG,
/* IP */
[vs_SocketOption_ip_ttl] = IP_TTL,
[vs_SocketOption_ip_hdrinc] = IP_HDRINCL,
};
bool vs_Socket_new(vs_File *fsocket, vs_SocketDomain domain, vs_SocketType type) {
if (!fsocket || vs_File_isopen(fsocket)) {
return false;
}
int odomain = 0;
int otype = 0;
int oprotocol = 0;
/* Domain */
if (domain == vs_SocketDomain_IPv4) {
odomain = AF_INET;
} else if (domain == vs_SocketDomain_IPv6) {
odomain = AF_INET6;
} else if (domain == vs_SocketDomain_BT) {
odomain = AF_BLUETOOTH;
} else if (domain == vs_SocketDomain_local) {
odomain = AF_UNIX;
} else {
return false;
}
/* Type and protocol */
if (type == vs_SocketType_TCP) {
otype = SOCK_STREAM;
oprotocol = IPPROTO_TCP;
} else if (type == vs_SocketType_UDP) {
otype = SOCK_DGRAM;
oprotocol = IPPROTO_UDP;
} else if (type == vs_SocketType_packet) {
otype = SOCK_SEQPACKET;
oprotocol = 0;
} else if (type == vs_SocketType_raw) {
otype = SOCK_RAW;
oprotocol = 0;
} else {
return false;
}
/* Create a new socket */
const vs_FileSocket sock = socket(odomain, otype, oprotocol);
if (sock < 0) {
vs_File_seterr(fsocket);
return false;
}
return vs_File_usesock(fsocket, sock);
}
bool vs_Socket_setopt(vs_File *fsocket,
vs_SocketOption opt,
const void *value,
vs_SockLen value_size) {
if (!fsocket || !vs_File_issock(fsocket)) {
return false;
}
int level = 0;
int optname = 0;
/* Determine level */
if (opt > _vs_SocketOption_sock_start && opt < _vs_SocketOption_sock_end) {
level = SOL_SOCKET;
} else if (opt > _vs_SocketOption_sock_end && opt < _vs_SocketOption_tcp_end) {
level = IPPROTO_TCP;
} else if (opt > _vs_SocketOption_tcp_end && opt < _vs_SocketOption_ip_end) {
level = IPPROTO_IP;
} else {
return false;
}
/* Determine option */
optname = vs_socket_options[opt];
/* Call setsockopt() */
if (setsockopt(fsocket->_fs, level, optname, value, value_size) < 0) {
return false;
}
return true;
}
bool vs_Socket_bind(vs_File *fsocket, const struct sockaddr *addr, vs_SockLen addrlen) {
if (!fsocket || !addr || !vs_File_issock(fsocket)) {
return false;
}
if (bind(fsocket->_fs, addr, addrlen) < 0) {
return false;
}
return true;
}
bool vs_Socket_accept(vs_File *server,
vs_File *client,
struct sockaddr *addr,
vs_SockLen *addrlen) {
if (!server || !client || !addr || !vs_File_issock(server) || vs_File_isopen(client)) {
return false;
}
vs_FileSocket sock = accept(server->_fs, addr, addrlen);
if (sock < 0) {
return false;
}
if (!vs_File_usesock(client, sock)) {
shutdown(sock, SHUT_RDWR);
close(sock);
return false;
}
return true;
}
bool vs_Socket_listen(vs_File *fsocket, int backlog) {
if (!fsocket || backlog < 1 || !vs_File_issock(fsocket)) {
return false;
}
if (listen(fsocket->_fs, backlog) < 0) {
return false;
}
return true;
}
size_t vs_Socket_recv(vs_File *fsocket, void *buf, size_t count) {
if (!fsocket) {
return 0;
}
return vs_File_read(fsocket, buf, count);
}
size_t vs_Socket_send(vs_File *fsocket, const void *buf, size_t count) {
if (!fsocket) {
return 0;
}
return vs_File_write(fsocket, buf, count);
}