diff options
Diffstat (limited to 'src/server/helper.c')
-rw-r--r-- | src/server/helper.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/server/helper.c b/src/server/helper.c new file mode 100644 index 0000000..2dbc3ea --- /dev/null +++ b/src/server/helper.c @@ -0,0 +1,146 @@ +#include "helper.h" +#include <arpa/inet.h> +#include <stdlib.h> +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include <sys/socket.h> + +#ifdef HAVE_THREAD_NAMES +#include <sys/prctl.h> // For thread names +#endif + +/** + * Parse IPv4 or IPv6 address in string representation to a suitable format usable by the BSD socket library + * !! Contents of 'string' might be modified by this function !! + * + * @param string eg. "1.2.3.4" or "2a01::10:5", optially with port appended, eg "1.2.3.4:6666" or "[2a01::10:5]:6666" + * @param host pointer to dnbd3_host_t that will be filled with the following data: + * .type will contain either HOST_IP4 or HOST_IP6 + * .addr will contain the address in network representation + * .port will contain the port in network representation, defaulting to #define PORT if none was given + * @return true on success, false in failure. contents of af, addr and port are undefined in the latter case + */ +bool parse_address(char *string, dnbd3_host_t *host) +{ + struct in_addr v4; + struct in6_addr v6; + + memset( host, 0, sizeof(*host) ); + // Try IPv4 without port + if ( 1 == inet_pton( AF_INET, string, &v4 ) ) { + host->type = HOST_IP4; + memcpy( host->addr, &v4, 4 ); + host->port = htons( PORT ); + return true; + } + // Try IPv6 without port + if ( 1 == inet_pton( AF_INET6, string, &v6 ) ) { + host->type = HOST_IP6; + memcpy( host->addr, &v6, 16 ); + host->port = htons( PORT ); + return true; + } + + // Scan for port + char *portpos = NULL, *ptr = string; + while ( *ptr ) { + if ( *ptr == ':' ) portpos = ptr; + ++ptr; + } + if ( portpos == NULL ) return false; // No port in string + // Consider IP being surrounded by [ ] + if ( *string == '[' && *(portpos - 1) == ']' ) { + ++string; + *(portpos - 1) = '\0'; + } + *portpos++ = '\0'; + int p = atoi( portpos ); + if ( p < 1 || p > 65535 ) return false; // Invalid port + host->port = htons( (uint16_t)p ); + + // Try IPv4 with port + if ( 1 == inet_pton( AF_INET, string, &v4 ) ) { + host->type = HOST_IP4; + memcpy( host->addr, &v4, 4 ); + return true; + } + // Try IPv6 with port + if ( 1 == inet_pton( AF_INET6, string, &v6 ) ) { + host->type = HOST_IP6; + memcpy( host->addr, &v6, 16 ); + return true; + } + + // FAIL + return false; +} + +/** + * Convert a host and port (network byte order) to printable representation. + * Worst case required buffer len is 48, eg. [1234:1234:1234:1234:1234:1234:1234:1234]:12345 (+ \0) + * Returns true on success, false on error + */ +bool host_to_string(const dnbd3_host_t *host, char *target, size_t targetlen) +{ + // Worst case: Port 5 chars, ':' to separate ip and port 1 char, terminating null 1 char = 7, [] for IPv6 + if ( targetlen < 10 ) return false; + if ( host->type == HOST_IP6 ) { + *target++ = '['; + inet_ntop( AF_INET6, host->addr, target, (socklen_t)targetlen - 10 ); + target += strlen( target ); + *target++ = ']'; + } else if ( host->type == HOST_IP4 ) { + inet_ntop( AF_INET, host->addr, target, (socklen_t)targetlen - 8 ); + target += strlen( target ); + } else { + snprintf( target, targetlen, "<?addrtype=%d>", (int)host->type ); + return false; + } + *target = '\0'; + if ( host->port != 0 ) { + // There are still at least 7 bytes left in the buffer, port is at most 5 bytes + ':' + '\0' = 7 + snprintf( target, 7, ":%d", (int)ntohs( host->port ) ); + } + return true; +} + +void remove_trailing_slash(char *string) +{ + char *ptr = string + strlen( string ) - 1; + while ( ptr >= string && *ptr == '/' ) + *ptr-- = '\0'; +} + +void trim_right(char * const string) +{ + char *end = string + strlen( string ) - 1; + while ( end >= string && (*end == '\r' || *end == '\n' || *end == ' ' || *end == '\t') ) + *end-- = '\0'; +} + +void setThreadName(const char *name) +{ + char newName[16]; + if ( strlen( name ) > 15 ) { + snprintf( newName, sizeof(newName), "%s", name ); + newName[15] = '\0'; + name = newName; + } +#ifdef HAVE_THREAD_NAMES + prctl( PR_SET_NAME, (unsigned long)name, 0, 0, 0 ); +#endif + //TODO: On FreeBSD set threadname with pthread_setname_np +} + +void blockNoncriticalSignals() +{ + sigset_t sigmask; + sigemptyset( &sigmask ); + sigaddset( &sigmask, SIGUSR1 ); + sigaddset( &sigmask, SIGUSR2 ); + sigaddset( &sigmask, SIGHUP ); + sigaddset( &sigmask, SIGPIPE ); + pthread_sigmask( SIG_BLOCK, &sigmask, NULL ); +} + |