diff --git a/lib/compat.c b/lib/compat.c new file mode 100644 index 0000000..cba80fc --- /dev/null +++ b/lib/compat.c @@ -0,0 +1,36 @@ + +/* + * Copyright (c) 2024 F. Duncanh, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + *================================================================== + */ + +#ifdef _WIN32 +#include +#include +#include "compat.h" + +#define MAX_SOCKET_ERROR_MESSAGE_LENGTH 256 + +/* Windows (winsock2) socket error message text */ +char *wsa_strerror(int errnum) { + static char message[MAX_SOCKET_ERROR_MESSAGE_LENGTH] = { 0 }; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + 0, errnum, 0, message, sizeof(message), 0); + char *nl = strchr(message, '\n'); + if (nl) { + *nl = 0; /* remove any trailing newline, or truncate to one line */ + } + return message; +} +#endif diff --git a/lib/raop_ntp.c b/lib/raop_ntp.c index 3f18027..1a932e4 100644 --- a/lib/raop_ntp.c +++ b/lib/raop_ntp.c @@ -214,10 +214,14 @@ raop_ntp_init_socket(raop_ntp_t *raop_ntp, int use_ipv6) } // We're calling recvfrom without knowing whether there is any data, so we need a timeout - + uint32_t recv_timeout_msec = 300; +#ifdef _WIN32 + DWORD tv = recv_timeout_msec; +#else struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 300000; + tv.tv_sec = recv_timeout_msec / (uint32_t) 1000; + tv.tv_usec = ((uint32_t) 1000) * (recv_timeout_msec % (uint32_t) 1000); +#endif if (setsockopt(tsock, SOL_SOCKET, SO_RCVTIMEO, CAST &tv, sizeof(tv)) < 0) { goto sockets_cleanup; } @@ -299,7 +303,7 @@ raop_ntp_thread(void *arg) if (send_len < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp error sending request. Error %d:%s", - sock_err, strerror(sock_err)); + sock_err, SOCKET_ERROR_STRING(sock_err)); } else { // Read response response_len = recvfrom(raop_ntp->tsock, (char *)response, sizeof(response), 0, NULL, NULL); diff --git a/lib/raop_rtp_mirror.c b/lib/raop_rtp_mirror.c index a39cbee..e97f66f 100644 --- a/lib/raop_rtp_mirror.c +++ b/lib/raop_rtp_mirror.c @@ -245,8 +245,9 @@ raop_rtp_mirror_thread(void *arg) saddrlen = sizeof(saddr); stream_fd = accept(raop_rtp_mirror->mirror_data_sock, (struct sockaddr *)&saddr, &saddrlen); if (stream_fd == -1) { + int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_ERR, - "raop_rtp_mirror error in accept %d %s", errno, strerror(errno)); + "raop_rtp_mirror error in accept %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); break; } @@ -255,31 +256,36 @@ raop_rtp_mirror_thread(void *arg) tv.tv_sec = 0; tv.tv_usec = 5000; if (setsockopt(stream_fd, SOL_SOCKET, SO_RCVTIMEO, CAST &tv, sizeof(tv)) < 0) { + int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_ERR, - "raop_rtp_mirror could not set stream socket timeout %d %s", errno, strerror(errno)); + "raop_rtp_mirror could not set stream socket timeout %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); break; } int option; option = 1; if (setsockopt(stream_fd, SOL_SOCKET, SO_KEEPALIVE, CAST &option, sizeof(option)) < 0) { + int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, - "raop_rtp_mirror could not set stream socket keepalive %d %s", errno, strerror(errno)); + "raop_rtp_mirror could not set stream socket keepalive %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } option = 60; if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPIDLE, CAST &option, sizeof(option)) < 0) { + int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, - "raop_rtp_mirror could not set stream socket keepalive time %d %s", errno, strerror(errno)); + "raop_rtp_mirror could not set stream socket keepalive time %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } option = 10; if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPINTVL, CAST &option, sizeof(option)) < 0) { + int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, - "raop_rtp_mirror could not set stream socket keepalive interval %d %s", errno, strerror(errno)); + "raop_rtp_mirror could not set stream socket keepalive interval %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } option = 6; if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPCNT, CAST &option, sizeof(option)) < 0) { + int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, - "raop_rtp_mirror could not set stream socket keepalive probes %d %s", errno, strerror(errno)); + "raop_rtp_mirror could not set stream socket keepalive probes %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } readstart = 0; } @@ -301,10 +307,11 @@ raop_rtp_mirror_thread(void *arg) stream_fd = -1; continue; } else if (payload == NULL && ret == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) continue; // Timeouts can happen even if the connection is fine + int sock_err = SOCKET_GET_ERROR(); + if (sock_err == SOCKET_ERRORNAME(EAGAIN) || sock_err == SOCKET_ERRORNAME(EWOULDBLOCK)) continue; // Timeouts can happen even if the connection is fine logger_log(raop_rtp_mirror->logger, LOGGER_ERR, - "raop_rtp_mirror error in header recv: %d %s", errno, strerror(errno)); - if (errno == ECONNRESET) conn_reset = true;; + "raop_rtp_mirror error in header recv: %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); + if (sock_err == SOCKET_ERRORNAME(ECONNRESET)) conn_reset = true;; break; } @@ -364,9 +371,10 @@ raop_rtp_mirror_thread(void *arg) logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror tcp socket was closed by client (recv returned 0)"); break; } else if (ret == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) continue; // Timeouts can happen even if the connection is fine - logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in recv: %d %s", errno, strerror(errno)); - if (errno == ECONNRESET) conn_reset = true; + int sock_err = SOCKET_GET_ERROR(); + if (sock_err == SOCKET_ERRORNAME(EAGAIN) || sock_err == SOCKET_ERRORNAME(EWOULDBLOCK)) continue; // Timeouts can happen even if the connection is fine + logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in recv: %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); + if (errno == SOCKET_ERRORNAME(ECONNRESET)) conn_reset = true; break; } diff --git a/lib/sockets.h b/lib/sockets.h index ece6d68..7fb2585 100644 --- a/lib/sockets.h +++ b/lib/sockets.h @@ -16,6 +16,9 @@ #define SOCKETS_H #if defined(WIN32) + +char *wsa_strerror(int errnum); + typedef int socklen_t; #ifndef SHUT_RD @@ -31,6 +34,7 @@ typedef int socklen_t; #define SOCKET_GET_ERROR() WSAGetLastError() #define SOCKET_SET_ERROR(value) WSASetLastError(value) #define SOCKET_ERRORNAME(name) WSA##name +#define SOCKET_ERROR_STRING(errnum) wsa_strerror(errnum) #define WSAEAGAIN WSAEWOULDBLOCK #define WSAENOMEM WSA_NOT_ENOUGH_MEMORY @@ -43,7 +47,7 @@ typedef int socklen_t; #define SOCKET_GET_ERROR() (errno) #define SOCKET_SET_ERROR(value) (errno = (value)) #define SOCKET_ERRORNAME(name) name - +#define SOCKET_ERROR_STRING(errnum) strerror(errnum) #endif #endif