#include #include #include #include #include #include #include "addr.h" #include "../io/log.h" void create_ip_addr(uint8_t* domain, IpAddr* addr) { addr->type = V4; memcpy(&addr->data.v4, domain, 4); } void create_ip_addr6(uint8_t* domain, IpAddr* addr) { addr->type = V6; memcpy(&addr->data.v6, domain, 16); } void ip_addr_any(IpAddr* addr) { addr->type = V4; addr->data.v4.s_addr = htonl(INADDR_ANY); } void ip_addr_any6(IpAddr* addr) { addr->type = V6; addr->data.v6 = in6addr_any; } static struct sockaddr_in create_socket_addr_v4(IpAddr addr, uint16_t port) { struct sockaddr_in socketaddr; memset(&socketaddr, 0, sizeof(socketaddr)); socketaddr.sin_family = AF_INET; socketaddr.sin_port = htons(port); socketaddr.sin_addr = addr.data.v4; return socketaddr; } static struct sockaddr_in6 create_socket_addr_v6(IpAddr addr, uint16_t port) { struct sockaddr_in6 socketaddr; memset(&socketaddr, 0, sizeof(socketaddr)); socketaddr.sin6_family = AF_INET6; socketaddr.sin6_port = htons(port); socketaddr.sin6_addr = addr.data.v6; return socketaddr; } static size_t get_addr_len(AddrType type) { if (type == V4) { return sizeof(struct sockaddr_in); } else if (type == V6) { return sizeof(struct sockaddr_in6); } else { return 0; } } void create_socket_addr(uint16_t port, IpAddr addr, SocketAddr* socket) { socket->type = addr.type; if (addr.type == V4) { socket->data.v4 = create_socket_addr_v4(addr, port); } else if(addr.type == V6) { socket->data.v6 = create_socket_addr_v6(addr, port); } else { ERROR("Tried to create socketaddr with invalid protocol type"); exit(EXIT_FAILURE); } socket->len = get_addr_len(addr.type); } void print_socket_addr(SocketAddr* addr, char* buffer) { INIT_LOG_BOUNDS if(addr->type == V4) { APPEND(buffer, "%hhu.%hhu.%hhu.%hhu:%hu", (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr >> 24), (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr >> 16), (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr >> 8), (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr), ntohs(addr->data.v4.sin_port) ); } else { uint8_t* a = (uint8_t*) &addr->data.v6.sin6_addr; for(int i = 0; i < 8; i++) { APPEND(buffer, "%02hhx%02hhx:", a[i*2 + 0], a[i*2 + 1] ); } APPEND(buffer, ":[%hu]", ntohs(addr->data.v6.sin6_port)); } } #define ADDR_DOMAIN(addr, var) \ struct sockaddr* var; \ if (addr->type == V4) { \ var = (struct sockaddr*) &addr->data.v4; \ } else if (addr->type == V6) { \ var = (struct sockaddr*) &addr->data.v6; \ } else { \ return -1; \ } #define ADDR_AFNET(type, var) \ int var; \ if (type == V4) { \ var = AF_INET; \ } else if (type == V6) { \ var = AF_INET6; \ } else { \ return -1; \ } int32_t create_udp_socket(AddrType type, UdpSocket* sock) { ADDR_AFNET(type, __domain) sock->type = type; sock->sockfd = socket(__domain, SOCK_DGRAM, 0); return sock->sockfd; } int32_t bind_udp_socket(SocketAddr* addr, UdpSocket* sock) { if (addr->type == V6) { int v6OnlyEnabled = 0; int32_t res = setsockopt( sock->sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &v6OnlyEnabled, sizeof(v6OnlyEnabled) ); if (res < 0) return res; } ADDR_DOMAIN(addr, __addr) return bind(sock->sockfd, __addr, addr->len); } int32_t read_udp_socket(UdpSocket* socket, void* buffer, uint16_t len, SocketAddr* clientaddr) { clientaddr->type = socket->type; clientaddr->len = get_addr_len(socket->type); ADDR_DOMAIN(clientaddr, __addr) return recvfrom( socket->sockfd, buffer, (size_t) len, MSG_WAITALL, __addr, (uint32_t*) &clientaddr->len ); } int32_t write_udp_socket(UdpSocket* socket, void* buffer, uint16_t len, SocketAddr* clientaddr) { ADDR_DOMAIN(clientaddr, __addr) return sendto( socket->sockfd, buffer, (size_t) len, MSG_CONFIRM, __addr, (uint32_t) clientaddr->len ); } static int get_socket_error(int fd) { int err = 1; socklen_t len = sizeof err; if (-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &len)) return 0; if (err) errno = err; return err; } static int close_socket(int fd) { if (fd >= 0) { get_socket_error(fd); // first clear any errors, which can cause close to fail if (shutdown(fd, SHUT_RDWR) < 0) // secondly, terminate the 'reliable' delivery if (errno != ENOTCONN && errno != EINVAL) // SGI causes EINVAL perror("shutdown"); if (close(fd) < 0) // finally call close() perror("close"); } return 0; } int32_t close_udp_socket(UdpSocket* socket) { return close_socket(socket->sockfd); } int32_t create_tcp_socket(AddrType type, TcpSocket* sock) { ADDR_AFNET(type, __domain) sock->type = type; sock->sockfd = socket(__domain, SOCK_STREAM, 0); return sock->sockfd; } int32_t bind_tcp_socket(SocketAddr* addr, TcpSocket* sock) { if (addr->type == V6) { int v6OnlyEnabled = 0; int32_t res = setsockopt( sock->sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &v6OnlyEnabled, sizeof(v6OnlyEnabled) ); if (res < 0) return res; } ADDR_DOMAIN(addr, __addr) return bind(sock->sockfd, __addr, addr->len); } int32_t listen_tcp_socket(TcpSocket* socket, uint32_t max) { return listen(socket->sockfd, max); } int32_t accept_tcp_socket(TcpSocket* socket, TcpStream* stream) { stream->clientaddr.type = socket->type; memset(&stream->clientaddr, 0, sizeof(SocketAddr)); SocketAddr* addr = &stream->clientaddr; ADDR_DOMAIN(addr, __addr) stream->streamfd = accept( socket->sockfd, __addr, (uint32_t*) &stream->clientaddr.len ); return stream->streamfd; } int32_t close_tcp_socket(TcpSocket* socket) { return close_socket(socket->sockfd); } int32_t connect_tcp_stream(SocketAddr* servaddr, TcpStream* stream) { TcpSocket socket; int32_t res = create_tcp_socket(servaddr->type, &socket); if (res < 0) return res; stream->clientaddr = *servaddr; stream->streamfd = socket.sockfd; ADDR_DOMAIN(servaddr, __addr) return connect( socket.sockfd, __addr, servaddr->len ); } int32_t read_tcp_stream(TcpStream* stream, void* buffer, uint16_t len) { return recv(stream->streamfd, buffer, len, MSG_WAITALL); } int32_t write_tcp_stream(TcpStream* stream, void* buffer, uint16_t len) { return send(stream->streamfd, buffer, len, MSG_NOSIGNAL); } int32_t close_tcp_stream(TcpStream* stream) { return close_socket(stream->streamfd); }