#include #include #include #include #include #include #include #include #include "socket.h" int socket_nonblock(const psocket *psock) { int flags; flags = fcntl(psock->fd, F_GETFL, 0); if (flags < 0) return 1; flags |= O_NONBLOCK; if (fcntl(psock->fd, F_SETFL, flags) == -1) return 1; return 0; } int socket_init_in(const char *addr, const char *port, struct addrinfo **results) { int s; struct addrinfo hints; assert(addr || port); /* getaddrinfo wants either node or service */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* IPV4 && IPV6 */ hints.ai_socktype = SOCK_STREAM; /* TCP */ hints.ai_flags = AI_PASSIVE; /* all interfaces */ s = getaddrinfo(addr, port, &hints, results); if (s) { freeaddrinfo(*results); *results = NULL; } return s; } int socket_bind_in(psocket *psock, struct addrinfo **results) { int s = 1, fd = -1, rv, reuse_enable = 1; struct addrinfo *rp = NULL; assert(psock && results && *results); psock->fd = -1; for (rp = *results; rp != NULL; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd < 0) continue; rv = bind(fd, rp->ai_addr, rp->ai_addrlen); if (!rv) break; close(fd); } if (!rp) goto finalise; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_enable, sizeof(int)); psock->fd = fd; psock->addr_len = rp->ai_addrlen; psock->addr = *rp->ai_addr; psock->family = rp->ai_family; psock->socktype = rp->ai_socktype; psock->protocol = rp->ai_protocol; s = socket_nonblock(psock); finalise: freeaddrinfo(*results); *results = NULL; return s; } int socket_listen_in(psocket *psock) { assert(psock); return listen(psock->fd, POTD_BACKLOG); } int socket_accept_in(const psocket *psock, psocket *client_psock) { int fd; assert(psock && client_psock); client_psock->fd = -1; client_psock->addr_len = psock->addr_len; fd = accept(psock->fd, &client_psock->addr, &client_psock->addr_len); if (fd < 0) return 1; if (socket_nonblock(psock)) { close(fd); return 1; } client_psock->fd = fd; return 0; } int socket_connect_in(psocket *psock, struct addrinfo **results) { int s = 1, fd = -1, rv, reuse_enable = 1; struct addrinfo *rp = NULL; assert(psock && results && *results); psock->fd = -1; for (rp = *results; rp != NULL; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd < 0) continue; rv = connect(fd, rp->ai_addr, rp->ai_addrlen); if (!rv) break; close(fd); } if (!rp) goto finalise; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_enable, sizeof(int)); psock->fd = fd; psock->addr_len = rp->ai_addrlen; psock->addr = *(rp->ai_addr); psock->family = rp->ai_family; psock->socktype = rp->ai_socktype; psock->protocol = rp->ai_protocol; s = socket_nonblock(psock); finalise: freeaddrinfo(*results); *results = NULL; return s; } int socket_addrtostr_in(const psocket *psock, char hbuf[NI_MAXHOST], char sbuf[NI_MAXSERV]) { int s; assert(psock); s = getnameinfo(&psock->addr, psock->addr_len, &hbuf[0], NI_MAXHOST, &sbuf[0], NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); return s; } int socket_reconnect_in(psocket *psock) { int rv; int reuse_enable = 1; assert(psock); if (psock->fd >= 0) return -1; psock->fd = socket(psock->family, psock->socktype, psock->protocol); if (psock->fd < 0) return -2; rv = connect(psock->fd, &psock->addr, psock->addr_len); if (rv) { socket_close(psock); return -3; } if (setsockopt(psock->fd, SOL_SOCKET, SO_REUSEADDR, &reuse_enable, sizeof(int)) < 0) { socket_close(psock); return -4; } return socket_nonblock(psock); } int socket_close(psocket *psock) { int rv; assert(psock); if (psock->fd < 0) return 0; rv = close(psock->fd); psock->fd = -1; return rv; } void socket_clone(const psocket *src, psocket *dst) { assert(src && dst); memcpy(dst, src, sizeof(*dst)); dst->fd = -1; }