fix #503 recv errors in httpd.c; define CLOSESOCKET, IOCTLSOCKET

This commit is contained in:
F. Duncanh
2026-02-15 19:45:23 -05:00
parent 60d6f73a81
commit 8eabfcc780
6 changed files with 52 additions and 45 deletions

View File

@@ -39,7 +39,6 @@ static const char *typename[] = {
struct http_connection_s { struct http_connection_s {
int connected; int connected;
int socket_fd; int socket_fd;
void *user_data; void *user_data;
connection_type_t type; connection_type_t type;
@@ -50,7 +49,6 @@ typedef struct http_connection_s http_connection_t;
struct httpd_s { struct httpd_s {
logger_t *logger; logger_t *logger;
httpd_callbacks_t callbacks; httpd_callbacks_t callbacks;
int max_connections; int max_connections;
int open_connections; int open_connections;
http_connection_t *connections; http_connection_t *connections;
@@ -192,17 +190,20 @@ httpd_destroy(httpd_t *httpd)
{ {
if (httpd) { if (httpd) {
httpd_stop(httpd); httpd_stop(httpd);
free(httpd->connections); free(httpd->connections);
free(httpd); free(httpd);
} }
} }
static void static void
httpd_remove_connection(httpd_t *httpd, http_connection_t *connection) httpd_remove_connection(httpd_t *httpd, http_connection_t *connection, int sock_err)
{ {
int socket_fd = connection->socket_fd; int socket_fd = connection->socket_fd;
connection->socket_fd = 0; connection->socket_fd = 0;
if (sock_err) {
logger_log(httpd->logger, LOGGER_INFO, "httpd: recv error %d on socket %d: %s",
sock_err, socket_fd, SOCKET_ERROR_STRING(sock_err));
}
if (connection->request) { if (connection->request) {
http_request_destroy(connection->request); http_request_destroy(connection->request);
connection->request = NULL; connection->request = NULL;
@@ -214,10 +215,12 @@ httpd_remove_connection(httpd_t *httpd, http_connection_t *connection)
connection->user_data = NULL; connection->user_data = NULL;
} }
if (socket_fd) { if (socket_fd) {
shutdown(socket_fd, SHUT_WR); if (!sock_err) {
int ret = closesocket(socket_fd); shutdown(socket_fd, SHUT_WR);
}
int ret = CLOSESOCKET(socket_fd);
if (ret == -1) { if (ret == -1) {
logger_log(httpd->logger, LOGGER_ERR, "httpd error in closesocket (close): %d %s", errno, strerror(errno)); logger_log(httpd->logger, LOGGER_ERR, "httpd error in CLOSESOCKET: %d %s", errno, SOCKET_ERROR_STRING(errno));
} else { } else {
logger_log(httpd->logger, LOGGER_INFO, "Connection closed on socket %d", socket_fd); logger_log(httpd->logger, LOGGER_INFO, "Connection closed on socket %d", socket_fd);
} }
@@ -284,7 +287,7 @@ httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6)
ret = getsockname(fd, (struct sockaddr *)&local_saddr, &local_saddrlen); ret = getsockname(fd, (struct sockaddr *)&local_saddr, &local_saddrlen);
if (ret == -1) { if (ret == -1) {
shutdown(fd, SHUT_RDWR); shutdown(fd, SHUT_RDWR);
closesocket(fd); CLOSESOCKET(fd);
return 0; return 0;
} }
@@ -303,7 +306,7 @@ httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6)
ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len, local_zone_id); ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len, local_zone_id);
if (ret == -1) { if (ret == -1) {
shutdown(fd, SHUT_RDWR); shutdown(fd, SHUT_RDWR);
closesocket(fd); CLOSESOCKET(fd);
return 0; return 0;
} }
return 1; return 1;
@@ -321,7 +324,7 @@ httpd_remove_known_connections(httpd_t *httpd) {
if (!connection->connected || connection->type == CONNECTION_TYPE_UNKNOWN) { if (!connection->connected || connection->type == CONNECTION_TYPE_UNKNOWN) {
continue; continue;
} }
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
} }
} }
@@ -332,7 +335,7 @@ httpd_remove_connections_by_type(httpd_t *httpd, connection_type_t type) {
if (!connection->connected || connection->type != type) { if (!connection->connected || connection->type != type) {
continue; continue;
} }
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
} }
} }
@@ -478,18 +481,16 @@ httpd_thread(void *arg)
if (!connection->socket_fd) { if (!connection->socket_fd) {
break; break;
} }
ret = recv(connection->socket_fd, buffer + readstart, sizeof(buffer) - 1 - readstart, 0); ret = recv(connection->socket_fd, buffer + readstart, sizeof(buffer) - readstart, 0);
if (ret == 0) { if (ret == 0) {
logger_log(httpd->logger, LOGGER_DEBUG, "client closed connection on socket %d", logger_log(httpd->logger, LOGGER_DEBUG, "client closed connection on socket %d",
connection->socket_fd); connection->socket_fd);
break; break;
} else if (ret == -1) { } else if (ret == -1) {
if (errno == EAGAIN) { if (errno == SOCKET_ERRORNAME(EAGAIN) || errno == SOCKET_ERRORNAME(EWOULDBLOCK) || errno == SOCKET_ERRORNAME(EINTR)) {
continue; continue;
} else { } else {
int sock_err = SOCKET_GET_ERROR(); httpd_remove_connection(httpd, connection, SOCKET_GET_ERROR());
logger_log(httpd->logger, LOGGER_ERR, "httpd: recv error %d on socket %d: %s",
sock_err, connection->socket_fd, SOCKET_ERROR_STRING(sock_err));
break; break;
} }
} else { } else {
@@ -506,10 +507,17 @@ httpd_thread(void *arg)
} }
} else { } else {
if (connection->socket_fd) { if (connection->socket_fd) {
ret = recv(connection->socket_fd, buffer, sizeof(buffer) - 1, 0); ret = recv(connection->socket_fd, buffer, sizeof(buffer), 0);
if (ret == 0) { if (ret == 0) {
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
continue; continue;
} else if (ret == -1) {
if (errno == SOCKET_ERRORNAME(EAGAIN) || errno == SOCKET_ERRORNAME(EWOULDBLOCK) || errno == SOCKET_ERRORNAME(EINTR)) {
continue;
} else {
httpd_remove_connection(httpd, connection, SOCKET_GET_ERROR());
break;
}
} }
} else { } else {
/* connection was recently removed */ /* connection was recently removed */
@@ -526,7 +534,7 @@ httpd_thread(void *arg)
" on socket %d:\n%s\n", connection->socket_fd, buffer); " on socket %d:\n%s\n", connection->socket_fd, buffer);
} }
if (ret == 0) { if (ret == 0) {
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
} }
continue; continue;
} }
@@ -540,7 +548,7 @@ httpd_thread(void *arg)
http_request_get_error_description(connection->request), http_request_get_error_description(connection->request),
data); data);
free (data); free (data);
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
continue; continue;
} }
@@ -581,7 +589,7 @@ httpd_thread(void *arg)
if (http_response_get_disconnect(response)) { if (http_response_get_disconnect(response)) {
logger_log(httpd->logger, LOGGER_INFO, "Disconnecting on software request"); logger_log(httpd->logger, LOGGER_INFO, "Disconnecting on software request");
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
} }
} else { } else {
logger_log(httpd->logger, LOGGER_WARNING, "httpd didn't get response"); logger_log(httpd->logger, LOGGER_WARNING, "httpd didn't get response");
@@ -601,18 +609,18 @@ httpd_thread(void *arg)
continue; continue;
} }
logger_log(httpd->logger, LOGGER_INFO, "Removing connection for socket %d", connection->socket_fd); logger_log(httpd->logger, LOGGER_INFO, "Removing connection for socket %d", connection->socket_fd);
httpd_remove_connection(httpd, connection); httpd_remove_connection(httpd, connection, 0);
} }
/* Close server sockets since they are not used any more */ /* Close server sockets since they are not used any more */
if (httpd->server_fd4 != -1) { if (httpd->server_fd4 != -1) {
shutdown(httpd->server_fd4, SHUT_RDWR); shutdown(httpd->server_fd4, SHUT_RDWR);
closesocket(httpd->server_fd4); CLOSESOCKET(httpd->server_fd4);
httpd->server_fd4 = -1; httpd->server_fd4 = -1;
} }
if (httpd->server_fd6 != -1) { if (httpd->server_fd6 != -1) {
shutdown(httpd->server_fd6, SHUT_RDWR); shutdown(httpd->server_fd6, SHUT_RDWR);
closesocket(httpd->server_fd6); CLOSESOCKET(httpd->server_fd6);
httpd->server_fd6 = -1; httpd->server_fd6 = -1;
} }
@@ -655,15 +663,15 @@ httpd_start(httpd_t *httpd, unsigned short *port)
if (httpd->server_fd4 != -1 && listen(httpd->server_fd4, backlog) == -1) { if (httpd->server_fd4 != -1 && listen(httpd->server_fd4, backlog) == -1) {
logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv4 socket"); logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv4 socket");
closesocket(httpd->server_fd4); CLOSESOCKET(httpd->server_fd4);
closesocket(httpd->server_fd6); CLOSESOCKET(httpd->server_fd6);
MUTEX_UNLOCK(httpd->run_mutex); MUTEX_UNLOCK(httpd->run_mutex);
return -2; return -2;
} }
if (httpd->server_fd6 != -1 && listen(httpd->server_fd6, backlog) == -1) { if (httpd->server_fd6 != -1 && listen(httpd->server_fd6, backlog) == -1) {
logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv6 socket"); logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv6 socket");
closesocket(httpd->server_fd4); CLOSESOCKET(httpd->server_fd4);
closesocket(httpd->server_fd6); CLOSESOCKET(httpd->server_fd6);
MUTEX_UNLOCK(httpd->run_mutex); MUTEX_UNLOCK(httpd->run_mutex);
return -2; return -2;
} }

View File

@@ -171,7 +171,7 @@ netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp)
cleanup: cleanup:
ret = SOCKET_GET_ERROR(); ret = SOCKET_GET_ERROR();
if (server_fd != -1) { if (server_fd != -1) {
closesocket(server_fd); CLOSESOCKET(server_fd);
} }
SOCKET_SET_ERROR(ret); SOCKET_SET_ERROR(ret);
return -1; return -1;

View File

@@ -244,7 +244,7 @@ raop_ntp_init_socket(raop_ntp_t *raop_ntp, int use_ipv6)
return 0; return 0;
sockets_cleanup: sockets_cleanup:
if (tsock != -1) closesocket(tsock); if (tsock != -1) CLOSESOCKET(tsock);
return -1; return -1;
} }
@@ -252,13 +252,11 @@ static void
raop_ntp_flush_socket(int fd) raop_ntp_flush_socket(int fd)
{ {
#ifdef _WIN32 #ifdef _WIN32
#define IOCTL ioctlsocket
u_long bytes_available = 0; u_long bytes_available = 0;
#else #else
#define IOCTL ioctl
int bytes_available = 0; int bytes_available = 0;
#endif #endif
while (IOCTL(fd, FIONREAD, &bytes_available) == 0 && bytes_available > 0) while (IOCTLSOCKET(fd, FIONREAD, &bytes_available) == 0 && bytes_available > 0)
{ {
// We are guaranteed that we won't block, because bytes are available. // We are guaranteed that we won't block, because bytes are available.
// Read 1 byte. Extra bytes in the datagram will be discarded. // Read 1 byte. Extra bytes in the datagram will be discarded.
@@ -464,7 +462,7 @@ raop_ntp_stop(raop_ntp_t *raop_ntp)
THREAD_JOIN(raop_ntp->thread); THREAD_JOIN(raop_ntp->thread);
if (raop_ntp->tsock != -1) { if (raop_ntp->tsock != -1) {
closesocket(raop_ntp->tsock); CLOSESOCKET(raop_ntp->tsock);
raop_ntp->tsock = -1; raop_ntp->tsock = -1;
} }

View File

@@ -270,8 +270,8 @@ raop_rtp_init_sockets(raop_rtp_t *raop_rtp, int use_ipv6)
return 0; return 0;
sockets_cleanup: sockets_cleanup:
if (csock != -1) closesocket(csock); if (csock != -1) CLOSESOCKET(csock);
if (dsock != -1) closesocket(dsock); if (dsock != -1) CLOSESOCKET(dsock);
return -1; return -1;
} }
@@ -832,11 +832,11 @@ raop_rtp_stop(raop_rtp_t *raop_rtp)
THREAD_JOIN(raop_rtp->thread); THREAD_JOIN(raop_rtp->thread);
if (raop_rtp->csock != -1) { if (raop_rtp->csock != -1) {
closesocket(raop_rtp->csock); CLOSESOCKET(raop_rtp->csock);
raop_rtp->csock = -1; raop_rtp->csock = -1;
} }
if (raop_rtp->dsock != -1) { if (raop_rtp->dsock != -1) {
closesocket(raop_rtp->dsock); CLOSESOCKET(raop_rtp->dsock);
raop_rtp->dsock = -1; raop_rtp->dsock = -1;
} }

View File

@@ -840,7 +840,7 @@ raop_rtp_mirror_thread(void *arg)
} }
/* Close the stream file descriptor */ /* Close the stream file descriptor */
if (stream_fd != -1) { if (stream_fd != -1) {
closesocket(stream_fd); CLOSESOCKET(stream_fd);
} }
// Ensure running reflects the actual state // Ensure running reflects the actual state
@@ -854,7 +854,7 @@ raop_rtp_mirror_thread(void *arg)
} }
if (unsupported_codec) { if (unsupported_codec) {
closesocket(raop_rtp_mirror->mirror_data_sock); CLOSESOCKET(raop_rtp_mirror->mirror_data_sock);
raop_rtp_mirror_stop(raop_rtp_mirror); raop_rtp_mirror_stop(raop_rtp_mirror);
raop_rtp_mirror->callbacks.video_reset(raop_rtp_mirror->callbacks.cls, RESET_TYPE_RTP_SHUTDOWN); raop_rtp_mirror->callbacks.video_reset(raop_rtp_mirror->callbacks.cls, RESET_TYPE_RTP_SHUTDOWN);
} }
@@ -888,7 +888,7 @@ raop_rtp_mirror_init_socket(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6)
return 0; return 0;
sockets_cleanup: sockets_cleanup:
if (dsock != -1) closesocket(dsock); if (dsock != -1) CLOSESOCKET(dsock);
return -1; return -1;
} }
@@ -947,7 +947,7 @@ void raop_rtp_mirror_stop(raop_rtp_mirror_t *raop_rtp_mirror) {
THREAD_JOIN(raop_rtp_mirror->thread_mirror); THREAD_JOIN(raop_rtp_mirror->thread_mirror);
if (raop_rtp_mirror->mirror_data_sock != -1) { if (raop_rtp_mirror->mirror_data_sock != -1) {
closesocket(raop_rtp_mirror->mirror_data_sock); CLOSESOCKET(raop_rtp_mirror->mirror_data_sock);
raop_rtp_mirror->mirror_data_sock = -1; raop_rtp_mirror->mirror_data_sock = -1;
} }

View File

@@ -38,11 +38,12 @@ typedef int socklen_t;
#define WSAEAGAIN WSAEWOULDBLOCK #define WSAEAGAIN WSAEWOULDBLOCK
#define WSAENOMEM WSA_NOT_ENOUGH_MEMORY #define WSAENOMEM WSA_NOT_ENOUGH_MEMORY
#define CLOSESOCKET closesocket
#define IOCTLSOCKET ioctlsocket
#else #else
#define closesocket close #define CLOSESOCKET close
#define ioctlsocket ioctl #define IOCTLSOCKET ioctl
#define SOCKET_GET_ERROR() (errno) #define SOCKET_GET_ERROR() (errno)
#define SOCKET_SET_ERROR(value) (errno = (value)) #define SOCKET_SET_ERROR(value) (errno = (value))