#include "sockhelper.h" #include "memlog.h" #include #include #include #include #include static inline int connect_shared(const int client_sock, void* addr, const int addrlen, int connect_ms, int rw_ms) { struct timeval tv; // Connect to server tv.tv_sec = connect_ms / 1000; tv.tv_usec = connect_ms * 1000; setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); if (connect(client_sock, (struct sockaddr *)addr, addrlen) == -1) { //int e = errno; //printf("connect -1 (%d)\n", e); return -1; } // Apply read/write timeout tv.tv_sec = rw_ms / 1000; tv.tv_usec = rw_ms * 1000; setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); return client_sock; } int sock_connect4(struct sockaddr_in *addr, const int connect_ms, const int rw_ms) { int client_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (client_sock == -1) return -1; return connect_shared(client_sock, addr, sizeof(struct sockaddr_in), connect_ms, rw_ms); } int sock_connect6(struct sockaddr_in6 *addr, const int connect_ms, const int rw_ms) { #ifdef WITH_IPV6 int client_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); if (client_sock == -1) return -1; return connect_shared(client_sock, addr, sizeof(struct sockaddr_in6), connect_ms, rw_ms); #else printf("[DEBUG] Not compiled with IPv6 support.\n"); return -1; #endif } int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const int rw_ms) { if (addr->type == AF_INET) { // Set host (IPv4) struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_family = AF_INET; memcpy(&addr4.sin_addr, addr->addr, 4); addr4.sin_port = addr->port; return sock_connect4(&addr4, connect_ms, rw_ms); } #ifdef WITH_IPV6 else if (addr->type == AF_INET6) { // Set host (IPv6) struct sockaddr_in6 addr6; memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; memcpy(&addr6.sin6_addr, addr->addr, 16); addr6.sin6_port = addr->port; return sock_connect6(&addr6, connect_ms, rw_ms); } #endif printf("[DEBUG] Unsupported address type: %d\n", (int)addr->type); return -1; } void sock_set_timeout(const int sockfd, const int milliseconds) { struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds * 1000; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); } int sock_listen_any(int protocol_family, uint16_t port) { struct sockaddr_storage addr; memset(&addr, 0, sizeof(addr)); if (protocol_family == PF_INET) { struct sockaddr_in *v4 = (struct sockaddr_in *)&addr; v4->sin_addr.s_addr = INADDR_ANY; v4->sin_port = htons(port); v4->sin_family = AF_INET; } #ifdef WITH_IPV6 else if (protocol_family == PF_INET6) { struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&addr; v6->sin6_addr = in6addr_any; v6->sin6_port = htons(port); v6->sin6_family = AF_INET6; } #endif else { printf("[DEBUG] sock_listen: Unsupported protocol: %d\n", protocol_family); return -1; } return sock_listen(&addr, sizeof(addr)); } int sock_listen(struct sockaddr_storage *addr, int addrlen) { int pf; // On Linux AF_* == PF_*, but this is not guaranteed on all platforms, so let's be safe here: if (addr->ss_family == AF_INET) pf = PF_INET; #ifdef WITH_IPV6 else if (addr->ss_family == AF_INET6) pf = PF_INET6; #endif else { printf("[DEBUG] sock_listen: unsupported address type: %d\n", (int)addr->ss_family); return -1; } int sock; // Create socket sock = socket(pf, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { memlogf("[ERROR] sock_listen: Socket setup failure"); // TODO: print port number to help troubleshooting return -1; } const int on = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (pf == PF_INET6) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); // Bind to socket if (bind(sock, (struct sockaddr *) addr, addrlen) < 0) { int e = errno; close(sock); memlogf("[ERROR] Bind failure (%d)", e); // TODO: print port number to help troubleshooting return -1; } // Listen on socket if (listen(sock, 20) == -1) { close(sock); memlogf("[ERROR] Listen failure"); // TODO ... return -1; } return sock; } int accept_any(const int * const sockets, const int socket_count, struct sockaddr_storage *addr, socklen_t *length_ptr) { fd_set set; FD_ZERO(&set); int max = 0; for (int i = 0; i < socket_count; ++i) { FD_SET(sockets[i], &set); if (sockets[i] > max) max = sockets[i]; } if (select(max + 1, &set, NULL, NULL, NULL) <= 0) return -1; for (int i = 0; i < socket_count; ++i) { if (FD_ISSET(sockets[i], &set)) return accept(sockets[i], (struct sockaddr *)addr, length_ptr); } return -1; } void sock_set_nonblock(int sock) { int flags = fcntl(sock, F_GETFL, 0); if (flags == -1) flags = 0; fcntl(sock, F_SETFL, flags | O_NONBLOCK); } void sock_set_block(int sock) { int flags = fcntl(sock, F_GETFL, 0); if (flags == -1) flags = 0; fcntl(sock, F_SETFL, flags & ~(int)O_NONBLOCK); } int sock_add_array(const int sock, int *array, int *array_fill, const int array_length) { if (sock == -1) return TRUE; for (int i = 0; i < *array_fill; ++i) { if (array[i] == -1) { array[i] = sock; return TRUE; } } if (*array_fill >= array_length) return FALSE; array[*array_fill] = sock; (*array_fill) += 1; return TRUE; }