182 lines
4.3 KiB
C
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);
|
|
}
|