libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit c443fe60fdc66641d60b875a347ae6302fcac5f7
parent 4e0abfce9e307db0c6d5a1c253603600d3ba0ced
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Tue, 18 Feb 2014 18:38:21 +0000

add platform abstraction for errno and strerror, check EWOULDBLOCK additionally to EAGAIN

Diffstat:
Msrc/microhttpd/Makefile.am | 6+++++-
Msrc/microhttpd/connection.c | 23++++++++++++++---------
Msrc/microhttpd/daemon.c | 100++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/microhttpd/internal.h | 1+
Msrc/platform/platform_interface.h | 33+++++++++++++++++++++++++++++++++
Asrc/platform/w32functions.c | 543+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/platform/w32functions.h | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/testcurl/Makefile.am | 11++++++++++-
Msrc/testcurl/test_get_sendfile.c | 3++-
9 files changed, 834 insertions(+), 62 deletions(-)

diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am @@ -2,6 +2,10 @@ if USE_PRIVATE_PLIBC_H PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc endif +if HAVE_W32 + W32FUNC_SRC = ../platform/w32functions.c ../platform/w32functions.h +endif + AM_CPPFLAGS = \ $(PLIBC_INCLUDE) \ -I$(top_srcdir)/src/include \ @@ -22,7 +26,7 @@ libmicrohttpd_la_SOURCES = \ internal.c internal.h \ memorypool.c memorypool.h \ response.c response.h \ - ../platform/platform_interface.h + ../platform/platform_interface.h $(W32FUNC_SRC) libmicrohttpd_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -DBUILDING_MHD_LIB=1 diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -1583,7 +1583,9 @@ do_read (struct MHD_Connection *connection) connection->read_buffer_offset); if (bytes_read < 0) { - if ((EINTR == errno) || (EAGAIN == errno) || (ECONNRESET == errno)) + const int err = MHD_socket_errno_; + if ((EINTR == err) || (EAGAIN == err) || (ECONNRESET == err) + || (EWOULDBLOCK == err)) return MHD_NO; #if HAVE_MESSAGES #if HTTPS_SUPPORT @@ -1595,7 +1597,7 @@ do_read (struct MHD_Connection *connection) #endif MHD_DLOG (connection->daemon, "Failed to receive data: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif CONNECTION_CLOSE_ERROR (connection, NULL); return MHD_YES; @@ -1636,7 +1638,8 @@ do_write (struct MHD_Connection *connection) if (ret < 0) { - if ((EINTR == errno) || (EAGAIN == errno)) + const int err = MHD_socket_errno_; + if ((EINTR == err) || (EAGAIN == err) || (EWOULDBLOCK == err)) return MHD_NO; #if HAVE_MESSAGES #if HTTPS_SUPPORT @@ -1647,7 +1650,7 @@ do_write (struct MHD_Connection *connection) else #endif MHD_DLOG (connection->daemon, - "Failed to send data: %s\n", STRERROR (errno)); + "Failed to send data: %s\n", MHD_socket_last_strerr_ ()); #endif CONNECTION_CLOSE_ERROR (connection, NULL); return MHD_YES; @@ -2022,12 +2025,13 @@ MHD_connection_handle_write (struct MHD_Connection *connection) connection->continue_message_write_offset); if (ret < 0) { - if ((errno == EINTR) || (errno == EAGAIN)) + const int err = MHD_socket_errno_; + if ((err == EINTR) || (err == EAGAIN) || (EWOULDBLOCK == err)) break; #if HAVE_MESSAGES MHD_DLOG (connection->daemon, "Failed to send data: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif CONNECTION_CLOSE_ERROR (connection, NULL); return MHD_YES; @@ -2068,6 +2072,7 @@ MHD_connection_handle_write (struct MHD_Connection *connection) response->data_size - (connection->response_write_position - response->data_start)); + const int err = MHD_socket_errno_; #if DEBUG_SEND_DATA if (ret > 0) FPRINTF (stderr, @@ -2080,12 +2085,12 @@ MHD_connection_handle_write (struct MHD_Connection *connection) pthread_mutex_unlock (&response->mutex); if (ret < 0) { - if ((errno == EINTR) || (errno == EAGAIN)) + if ((err == EINTR) || (err == EAGAIN) || (EWOULDBLOCK == err)) return MHD_YES; #if HAVE_MESSAGES MHD_DLOG (connection->daemon, "Failed to send data: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif CONNECTION_CLOSE_ERROR (connection, NULL); return MHD_YES; @@ -2658,7 +2663,7 @@ MHD_connection_epoll_update_ (struct MHD_Connection *connection) if (0 != (daemon->options & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to epoll_ctl failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif connection->state = MHD_CONNECTION_CLOSED; cleanup_connection (connection); diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -25,7 +25,6 @@ * @author Christian Grothoff */ #include "platform.h" -#include "platform_interface.h" #include "internal.h" #include "response.h" #include "connection.h" @@ -409,7 +408,7 @@ recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i) if ( (GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED == res) ) { - errno = EINTR; + MHD_set_socket_errno_ (EINTR); #if EPOLL_SUPPORT connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; #endif @@ -420,7 +419,7 @@ recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i) /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication disrupted); set errno to something caller will interpret correctly as a hard error */ - errno = EPIPE; + MHD_set_socket_errno_ (ECONNRESET); return res; } if (res == i) @@ -450,7 +449,7 @@ send_tls_adapter (struct MHD_Connection *connection, if ( (GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED == res) ) { - errno = EINTR; + MHD_set_socket_errno_ (EINTR); #if EPOLL_SUPPORT connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; #endif @@ -732,13 +731,13 @@ MHD_handle_connection (void *data) num_ready = SELECT (max + 1, &rs, &ws, NULL, tvp); if (num_ready < 0) { - if (EINTR == errno) + if (EINTR == MHD_socket_errno_) continue; #if HAVE_MESSAGES MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", max, - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif break; } @@ -784,11 +783,11 @@ MHD_handle_connection (void *data) if (poll (p, 1, (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0) { - if (EINTR == errno) + if (EINTR == MHD_socket_errno_) continue; #if HAVE_MESSAGES MHD_DLOG (con->daemon, "Error during poll: `%s'\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif break; } @@ -848,7 +847,7 @@ recv_param_adapter (struct MHD_Connection *connection, if ( (MHD_INVALID_SOCKET == connection->socket_fd) || (MHD_CONNECTION_CLOSED == connection->state) ) { - errno = ENOTCONN; + MHD_set_socket_errno_ (ENOTCONN); return -1; } ret = RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); @@ -886,7 +885,7 @@ send_param_adapter (struct MHD_Connection *connection, if ( (MHD_INVALID_SOCKET == connection->socket_fd) || (MHD_CONNECTION_CLOSED == connection->state) ) { - errno = ENOTCONN; + MHD_set_socket_errno_ (ENOTCONN); return -1; } if (0 != (connection->daemon->options & MHD_USE_SSL)) @@ -916,9 +915,10 @@ send_param_adapter (struct MHD_Connection *connection, #endif return ret; } - if ( (EINTR == errno) || (EAGAIN == errno) ) + const int err = MHD_socket_errno_; + if ( (EINTR == err) || (EAGAIN == err) || (EWOULDBLOCK == err) ) return 0; - if ( (EINVAL == errno) || (EBADF == errno) ) + if ( (EINVAL == err) || (EBADF == err) ) return -1; /* None of the 'usual' sendfile errors occurred, so we should try to fall back to 'SEND'; see also this thread for info on @@ -1137,7 +1137,7 @@ internal_add_connection (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Error allocating memory: %s\n", - STRERROR (errno)); + MHD_strerror_ (errno)); #endif if (0 != MHD_socket_close_ (client_socket)) MHD_PANIC ("close failed\n"); @@ -1152,7 +1152,7 @@ internal_add_connection (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Error allocating memory: %s\n", - STRERROR (errno)); + MHD_strerror_ (errno)); #endif if (0 != MHD_socket_close_ (client_socket)) MHD_PANIC ("close failed\n"); @@ -1171,7 +1171,7 @@ internal_add_connection (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Error allocating memory: %s\n", - STRERROR (errno)); + MHD_strerror_ (errno)); #endif if (0 != MHD_socket_close_ (client_socket)) MHD_PANIC ("close failed\n"); @@ -1211,7 +1211,7 @@ internal_add_connection (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to make socket non-blocking: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif } #else @@ -1221,7 +1221,7 @@ internal_add_connection (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to make socket non-blocking: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif } #endif @@ -1299,7 +1299,7 @@ internal_add_connection (struct MHD_Daemon *daemon, eno = errno; #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create a thread: %s\n", - STRERROR (res_thread_create)); + MHD_strerror_ (res_thread_create)); #endif goto cleanup; } @@ -1332,7 +1332,7 @@ internal_add_connection (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Call to epoll_ctl failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif goto cleanup; } @@ -1584,7 +1584,7 @@ make_nonblocking_noninheritable (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to make socket non-blocking: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif } if (!GetHandleInformation ((HANDLE) sock, &dwFlags) || @@ -1592,10 +1592,9 @@ make_nonblocking_noninheritable (struct MHD_Daemon *daemon, !SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, 0))) { #if HAVE_MESSAGES - SetErrnoFromWinError (GetLastError ()); MHD_DLOG (daemon, - "Failed to make socket non-inheritable: %s\n", - STRERROR (errno)); + "Failed to make socket non-inheritable: %u\n", + (unsigned int) GetLastError ()); #endif } #else @@ -1615,7 +1614,7 @@ make_nonblocking_noninheritable (struct MHD_Daemon *daemon, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to make socket non-inheritable: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif } #endif @@ -1713,11 +1712,12 @@ MHD_accept_connection (struct MHD_Daemon *daemon) if ((MHD_INVALID_SOCKET == s) || (addrlen <= 0)) { #if HAVE_MESSAGES + const int err = MHD_socket_errno_; /* This could be a common occurance with multiple worker threads */ - if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) + if ((EAGAIN != err) && (EWOULDBLOCK != err)) MHD_DLOG (daemon, "Error accepting connection: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif if (MHD_INVALID_SOCKET != s) { @@ -2094,10 +2094,10 @@ MHD_select (struct MHD_Daemon *daemon, return MHD_NO; if (num_ready < 0) { - if (EINTR == errno) + if (EINTR == MHD_socket_errno_) return MHD_YES; #if HAVE_MESSAGES - MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno)); + MHD_DLOG (daemon, "select failed: %s\n", MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -2193,12 +2193,12 @@ MHD_poll_all (struct MHD_Daemon *daemon, return MHD_YES; if (poll (p, poll_server + num_connections, timeout) < 0) { - if (EINTR == errno) + if (EINTR == MHD_socket_errno_) return MHD_YES; #if HAVE_MESSAGES MHD_DLOG (daemon, "poll failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -2299,10 +2299,10 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon, return MHD_YES; if (poll (p, poll_count, timeout) < 0) { - if (EINTR == errno) + if (EINTR == MHD_socket_errno_) return MHD_YES; #if HAVE_MESSAGES - MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno)); + MHD_DLOG (daemon, "poll failed: %s\n", MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -2396,7 +2396,7 @@ MHD_epoll (struct MHD_Daemon *daemon, if (0 != (daemon->options & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to epoll_ctl failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -2442,13 +2442,13 @@ MHD_epoll (struct MHD_Daemon *daemon, events, MAX_EVENTS, timeout_ms); if (-1 == num_events) { - if (EINTR == errno) + if (EINTR == MHD_socket_errno_) return MHD_YES; #if HAVE_MESSAGES if (0 != (daemon->options & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to epoll_wait failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -3083,7 +3083,7 @@ create_socket (struct MHD_Daemon *daemon, /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo * implementations do not set ai_socktype, e.g. RHL6.2. */ fd = SOCKET (domain, ctype, protocol); - if ( (MHD_INVALID_SOCKET == fd) && (EINVAL == errno) && (0 != SOCK_CLOEXEC) ) + if ( (MHD_INVALID_SOCKET == fd) && (EINVAL == MHD_socket_errno_) && (0 != SOCK_CLOEXEC) ) { ctype = type; fd = SOCKET(domain, type, protocol); @@ -3116,7 +3116,7 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon) if (0 != (daemon->options & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to epoll_create1 failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -3136,7 +3136,7 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon) if (0 != (daemon->options & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to epoll_ctl failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -3155,7 +3155,7 @@ setup_epoll_to_listen (struct MHD_Daemon *daemon) if (0 != (daemon->options & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to epoll_ctl failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif return MHD_NO; } @@ -3274,7 +3274,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create control pipe: %s\n", - STRERROR (errno)); + MHD_strerror_ (errno)); #endif free (daemon); return NULL; @@ -3342,7 +3342,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to allocate memory for nonce-nc map: %s\n", - STRERROR (errno)); + MHD_strerror_ (errno)); #endif #if HTTPS_SUPPORT if (0 != (flags & MHD_USE_SSL)) @@ -3442,7 +3442,7 @@ MHD_start_daemon_va (unsigned int flags, if (0 != (flags & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Call to socket failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif goto free_and_fail; } @@ -3455,7 +3455,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "setsockopt failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif } @@ -3515,7 +3515,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "setsockopt failed: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif } #endif @@ -3528,7 +3528,7 @@ MHD_start_daemon_va (unsigned int flags, MHD_DLOG (daemon, "Failed to bind to port %u: %s\n", (unsigned int) port, - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif if (0 != MHD_socket_close_ (socket_fd)) MHD_PANIC ("close failed\n"); @@ -3543,7 +3543,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to make listen socket non-blocking: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif if (0 != MHD_socket_close_ (socket_fd)) MHD_PANIC ("close failed\n"); @@ -3557,7 +3557,7 @@ MHD_start_daemon_va (unsigned int flags, if (0 != (flags & MHD_USE_DEBUG)) MHD_DLOG (daemon, "Failed to listen for connections: %s\n", - STRERROR (errno)); + MHD_socket_last_strerr_ ()); #endif if (0 != MHD_socket_close_ (socket_fd)) MHD_PANIC ("close failed\n"); @@ -3635,7 +3635,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create listen thread: %s\n", - STRERROR (res_thread_create)); + MHD_strerror_ (res_thread_create)); #endif pthread_mutex_destroy (&daemon->cleanup_connection_mutex); pthread_mutex_destroy (&daemon->per_ip_connection_mutex); @@ -3715,7 +3715,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create worker control pipe: %s\n", - STRERROR (errno)); + MHD_strerror_ (errno)); #endif goto thread_failed; } @@ -3764,7 +3764,7 @@ MHD_start_daemon_va (unsigned int flags, #if HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create pool thread: %s\n", - STRERROR (res_thread_create)); + MHD_strerror_ (res_thread_create)); #endif /* Free memory for this worker; cleanup below handles * all previously-created workers. */ diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h @@ -29,6 +29,7 @@ #include "platform.h" #include "microhttpd.h" +#include "platform_interface.h" #if HTTPS_SUPPORT #include <gnutls/gnutls.h> #if GNUTLS_VERSION_MAJOR >= 3 diff --git a/src/platform/platform_interface.h b/src/platform/platform_interface.h @@ -26,6 +26,10 @@ #ifndef MHD_PLATFORM_INTERFACE_H #define MHD_PLATFORM_INTERFACE_H +#if defined(_WIN32) && !defined(__CYGWIN__) +#include "w32functions.h" +#endif + /* MHD_socket_close_(fd) close any FDs (non-W32) / close only socket FDs (W32) */ #if !defined(_WIN32) || defined(__CYGWIN__) #define MHD_socket_close_(fd) close((fd)) @@ -33,4 +37,33 @@ #define MHD_socket_close_(fd) closesocket((fd)) #endif +/* MHD_socket_errno_ is errno of last function (non-W32) / errno of last socket function (W32) */ +#if !defined(_WIN32) || defined(__CYGWIN__) +#define MHD_socket_errno_ errno +#else +#define MHD_socket_errno_ MHD_W32_errno_from_winsock_() +#endif + +/* MHD_socket_last_strerr_ is description string of last errno (non-W32) / + * description string of last socket error (W32) */ +#if !defined(_WIN32) || defined(__CYGWIN__) +#define MHD_socket_last_strerr_() strerror(errno) +#else +#define MHD_socket_last_strerr_() MHD_W32_strerror_last_winsock_() +#endif + +/* MHD_strerror_ is strerror (both non-W32/W32) */ +#if !defined(_WIN32) || defined(__CYGWIN__) +#define MHD_strerror_(errnum) strerror((errnum)) +#else +#define MHD_strerror_(errnum) MHD_W32_strerror_((errnum)) +#endif + +/* MHD_set_socket_errno_ set errno to errnum (non-W32) / set socket last error to errnum (W32) */ +#if !defined(_WIN32) || defined(__CYGWIN__) +#define MHD_set_socket_errno_(errnum) errno=(errnum) +#else +#define MHD_set_socket_errno_(errnum) MHD_W32_set_last_winsock_error_((errnum)) +#endif + #endif // MHD_PLATFORM_INTERFACE_H diff --git a/src/platform/w32functions.c b/src/platform/w32functions.c @@ -0,0 +1,543 @@ +/* + This file is part of libmicrohttpd + (C) 2014 Karlson2k (Evgeny Grin) + + 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. + + You should have received a copy of the GNU Lesser General Public + License along with this library. + If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file platform/w32functions.h + * @brief internal functions for W32 systems + * @author Karlson2k (Evgeny Grin) + */ + +#include "w32functions.h" +#include <errno.h> +#include <winsock2.h> +#include <string.h> + +/** + * Return errno equivalent of last winsock error + * @return errno equivalent of last winsock error + */ +int MHD_W32_errno_from_winsock_(void) +{ + switch(WSAGetLastError()) + { + case 0: return 0; + case WSA_INVALID_HANDLE: return EBADF; + case WSA_NOT_ENOUGH_MEMORY: return ENOMEM; + case WSA_INVALID_PARAMETER: return EINVAL; + case WSAEINTR: return EINTR; + case WSAEWOULDBLOCK: return EWOULDBLOCK; + case WSAEINPROGRESS: return EINPROGRESS; + case WSAEALREADY: return EALREADY; + case WSAENOTSOCK: return ENOTSOCK; + case WSAEDESTADDRREQ: return EDESTADDRREQ; + case WSAEMSGSIZE: return EMSGSIZE; + case WSAEPROTOTYPE: return EPROTOTYPE; + case WSAENOPROTOOPT: return ENOPROTOOPT; + case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT; + case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT; + case WSAEOPNOTSUPP: return EOPNOTSUPP; + case WSAEPFNOSUPPORT: return EPFNOSUPPORT; + case WSAEAFNOSUPPORT: return EAFNOSUPPORT; + case WSAEADDRINUSE: return EADDRINUSE; + case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL; + case WSAENETDOWN: return ENETDOWN; + case WSAENETUNREACH: return ENETUNREACH; + case WSAENETRESET: return ENETRESET; + case WSAECONNABORTED: return ECONNABORTED; + case WSAECONNRESET: return ECONNRESET; + case WSAENOBUFS: return ENOBUFS; + case WSAEISCONN: return EISCONN; + case WSAENOTCONN: return ENOTCONN; + case WSAESHUTDOWN: return ESHUTDOWN; + case WSAETOOMANYREFS: return ETOOMANYREFS; + case WSAETIMEDOUT: return ETIMEDOUT; + case WSAECONNREFUSED: return ECONNREFUSED; + case WSAELOOP: return ELOOP; + case WSAENAMETOOLONG: return ENAMETOOLONG; + case WSAEHOSTDOWN: return EHOSTDOWN; + case WSAEHOSTUNREACH: return EHOSTUNREACH; + case WSAENOTEMPTY: return ENOTEMPTY; + case WSAEPROCLIM: return EPROCLIM; + case WSAEUSERS: return EUSERS; + case WSAEDQUOT: return EDQUOT; + case WSAESTALE: return ESTALE; + case WSAEREMOTE: return EREMOTE; + case WSAEINVAL: return EINVAL; + case WSAEFAULT: return EFAULT; + case WSANO_DATA: return ENODATA; + /* Rough equivalents */ + case WSAEDISCON: return ECONNRESET; + case WSAEINVALIDPROCTABLE: return EFAULT; + case WSASYSNOTREADY: + case WSANOTINITIALISED: + case WSASYSCALLFAILURE: return ENOBUFS; + case WSAVERNOTSUPPORTED: return EOPNOTSUPP; + case WSAEREFUSED: return EIO; + } + return EINVAL; +} + +/** + * Return pointer to string description of errnum error + * Works fine with both standard errno errnums + * and errnums from MHD_W32_errno_from_winsock_ + * @param errnum the errno or value from MHD_W32_errno_from_winsock_() + * @return pointer to string description of error + */ +const char* MHD_W32_strerror_(int errnum) +{ + switch(errnum) + { + case 0: + return "No error"; + case EWOULDBLOCK: + return "Operation would block"; + case EINPROGRESS: + return "Connection already in progress"; + case EALREADY: + return "Socket already connected"; + case ENOTSOCK: + return "Socket operation on non-socket"; + case EDESTADDRREQ: + return "Destination address required"; + case EMSGSIZE: + return "Message too long"; + case EPROTOTYPE: + return "Protocol wrong type for socket"; + case ENOPROTOOPT: + return "Protocol not available"; + case EPROTONOSUPPORT: + return "Unknown protocol"; + case ESOCKTNOSUPPORT: + return "Socket type not supported"; + case EOPNOTSUPP: + return "Operation not supported on socket"; + case EPFNOSUPPORT: + return "Protocol family not supported"; + case EAFNOSUPPORT: + return "Address family not supported by protocol family"; + case EADDRINUSE: + return "Address already in use"; + case EADDRNOTAVAIL: + return "Cannot assign requested address"; + case ENETDOWN: + return "Network is down"; + case ENETUNREACH: + return "Network is unreachable"; + case ENETRESET: + return "Network dropped connection on reset"; + case ECONNABORTED: + return "Software caused connection abort"; + case ECONNRESET: + return "Connection reset by peer"; + case ENOBUFS: + return "No system resources available"; + case EISCONN: + return "Socket is already connected"; + case ENOTCONN: + return "Socket is not connected"; + case ESHUTDOWN: + return "Can't send after socket shutdown"; + case ETOOMANYREFS: + return "Too many references: cannot splice"; + case ETIMEDOUT: + return "Connection timed out"; + case ECONNREFUSED: + return "Connection refused"; + case ELOOP: + return "Cannot translate name"; + case EHOSTDOWN: + return "Host is down"; + case EHOSTUNREACH: + return "Host is unreachable"; + case EPROCLIM: + return "Too many processes"; + case EUSERS: + return "Too many users"; + case EDQUOT: + return "Disk quota exceeded"; + case ESTALE: + return "Stale file handle reference"; + case EREMOTE: + return "Resource is remote"; + case ENODATA: + return "No data available"; + } + return strerror(errnum); +} + +/** + * Return pointer to string description of last winsock error + * @return pointer to string description of last winsock error + */ +const char* MHD_W32_strerror_last_winsock_(void) +{ + switch (WSAGetLastError()) + { + case 0: + return "No error"; + case WSA_INVALID_HANDLE: + return "Specified event object handle is invalid"; + case WSA_NOT_ENOUGH_MEMORY: + return "Insufficient memory available"; + case WSA_INVALID_PARAMETER: + return "One or more parameters are invalid"; + case WSA_OPERATION_ABORTED: + return "Overlapped operation aborted"; + case WSA_IO_INCOMPLETE: + return "Overlapped I/O event object not in signaled state"; + case WSA_IO_PENDING: + return "Overlapped operations will complete later"; + case WSAEINTR: + return "Interrupted function call"; + case WSAEBADF: + return "File handle is not valid"; + case WSAEACCES: + return "Permission denied"; + case WSAEFAULT: + return "Bad address"; + case WSAEINVAL: + return "Invalid argument"; + case WSAEMFILE: + return "Too many open files"; + case WSAEWOULDBLOCK: + return "Resource temporarily unavailable"; + case WSAEINPROGRESS: + return "Operation now in progress"; + case WSAEALREADY: + return "Operation already in progress"; + case WSAENOTSOCK: + return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: + return "Destination address required"; + case WSAEMSGSIZE: + return "Message too long"; + case WSAEPROTOTYPE: + return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: + return "Bad protocol option"; + case WSAEPROTONOSUPPORT: + return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: + return "Socket type not supported"; + case WSAEOPNOTSUPP: + return "Operation not supported"; + case WSAEPFNOSUPPORT: + return "Protocol family not supported"; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case WSAEADDRINUSE: + return "Address already in use"; + case WSAEADDRNOTAVAIL: + return "Cannot assign requested address"; + case WSAENETDOWN: + return "Network is down"; + case WSAENETUNREACH: + return "Network is unreachable"; + case WSAENETRESET: + return "Network dropped connection on reset"; + case WSAECONNABORTED: + return "Software caused connection abort"; + case WSAECONNRESET: + return "Connection reset by peer"; + case WSAENOBUFS: + return "No buffer space available"; + case WSAEISCONN: + return "Socket is already connected"; + case WSAENOTCONN: + return "Socket is not connected"; + case WSAESHUTDOWN: + return "Cannot send after socket shutdown"; + case WSAETOOMANYREFS: + return "Too many references"; + case WSAETIMEDOUT: + return "Connection timed out"; + case WSAECONNREFUSED: + return "Connection refused"; + case WSAELOOP: + return "Cannot translate name"; + case WSAENAMETOOLONG: + return "Name too long"; + case WSAEHOSTDOWN: + return "Host is down"; + case WSAEHOSTUNREACH: + return "No route to host"; + case WSAENOTEMPTY: + return "Directory not empty"; + case WSAEPROCLIM: + return "Too many processes"; + case WSAEUSERS: + return "User quota exceeded"; + case WSAEDQUOT: + return "Disk quota exceeded"; + case WSAESTALE: + return "Stale file handle reference"; + case WSAEREMOTE: + return "Item is remote"; + case WSASYSNOTREADY: + return "Network subsystem is unavailable"; + case WSAVERNOTSUPPORTED: + return "Winsock.dll version out of range"; + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performed"; + case WSAEDISCON: + return "Graceful shutdown in progress"; + case WSAENOMORE: + return "No more results"; + case WSAECANCELLED: + return "Call has been canceled"; + case WSAEINVALIDPROCTABLE: + return "Procedure call table is invalid"; + case WSAEINVALIDPROVIDER: + return "Service provider is invalid"; + case WSAEPROVIDERFAILEDINIT: + return "Service provider failed to initialize"; + case WSASYSCALLFAILURE: + return "System call failure"; + case WSASERVICE_NOT_FOUND: + return "Service not found"; + case WSATYPE_NOT_FOUND: + return "Class type not found"; + case WSA_E_NO_MORE: + return "No more results"; + case WSA_E_CANCELLED: + return "Call was canceled"; + case WSAEREFUSED: + return "Database query was refused"; + case WSAHOST_NOT_FOUND: + return "Host not found"; + case WSATRY_AGAIN: + return "Nonauthoritative host not found"; + case WSANO_RECOVERY: + return "This is a nonrecoverable error"; + case WSANO_DATA: + return "Valid name, no data record of requested type"; + case WSA_QOS_RECEIVERS: + return "QoS receivers"; + case WSA_QOS_SENDERS: + return "QoS senders"; + case WSA_QOS_NO_SENDERS: + return "No QoS senders"; + case WSA_QOS_NO_RECEIVERS: + return "QoS no receivers"; + case WSA_QOS_REQUEST_CONFIRMED: + return "QoS request confirmed"; + case WSA_QOS_ADMISSION_FAILURE: + return "QoS admission error"; + case WSA_QOS_POLICY_FAILURE: + return "QoS policy failure"; + case WSA_QOS_BAD_STYLE: + return "QoS bad style"; + case WSA_QOS_BAD_OBJECT: + return "QoS bad object"; + case WSA_QOS_TRAFFIC_CTRL_ERROR: + return "QoS traffic control error"; + case WSA_QOS_GENERIC_ERROR: + return "QoS generic error"; + case WSA_QOS_ESERVICETYPE: + return "QoS service type error"; + case WSA_QOS_EFLOWSPEC: + return "QoS flowspec error"; + case WSA_QOS_EPROVSPECBUF: + return "Invalid QoS provider buffer"; + case WSA_QOS_EFILTERSTYLE: + return "Invalid QoS filter style"; + case WSA_QOS_EFILTERTYPE: + return "Invalid QoS filter type"; + case WSA_QOS_EFILTERCOUNT: + return "Incorrect QoS filter count"; + case WSA_QOS_EOBJLENGTH: + return "Invalid QoS object length"; + case WSA_QOS_EFLOWCOUNT: + return "Incorrect QoS flow count"; + case WSA_QOS_EUNKOWNPSOBJ: + return "Unrecognized QoS object"; + case WSA_QOS_EPOLICYOBJ: + return "Invalid QoS policy object"; + case WSA_QOS_EFLOWDESC: + return "Invalid QoS flow descriptor"; + case WSA_QOS_EPSFLOWSPEC: + return "Invalid QoS provider-specific flowspec"; + case WSA_QOS_EPSFILTERSPEC: + return "Invalid QoS provider-specific filterspec"; + case WSA_QOS_ESDMODEOBJ: + return "Invalid QoS shape discard mode object"; + case WSA_QOS_ESHAPERATEOBJ: + return "Invalid QoS shaping rate object"; + case WSA_QOS_RESERVED_PETYPE: + return "Reserved policy QoS element type"; + } + return "Unknown winsock error"; +} + +/** + * Set last winsock error to equivalent of given errno value + * @param errnum the errno value to set + */ +void MHD_W32_set_last_winsock_error_(int errnum) +{ + switch (errnum) + { + case 0: + WSASetLastError(0); + break; + case EBADF: + WSASetLastError(WSA_INVALID_HANDLE); + break; + case ENOMEM: + WSASetLastError(WSA_NOT_ENOUGH_MEMORY); + break; + case EINVAL: + WSASetLastError(WSA_INVALID_PARAMETER); + break; + case EINTR: + WSASetLastError(WSAEINTR); + break; + case EWOULDBLOCK: + WSASetLastError(WSAEWOULDBLOCK); + break; + case EINPROGRESS: + WSASetLastError(WSAEINPROGRESS); + break; + case EALREADY: + WSASetLastError(WSAEALREADY); + break; + case ENOTSOCK: + WSASetLastError(WSAENOTSOCK); + break; + case EDESTADDRREQ: + WSASetLastError(WSAEDESTADDRREQ); + break; + case EMSGSIZE: + WSASetLastError(WSAEMSGSIZE); + break; + case EPROTOTYPE: + WSASetLastError(WSAEPROTOTYPE); + break; + case ENOPROTOOPT: + WSASetLastError(WSAENOPROTOOPT); + break; + case EPROTONOSUPPORT: + WSASetLastError(WSAEPROTONOSUPPORT); + break; + case ESOCKTNOSUPPORT: + WSASetLastError(WSAESOCKTNOSUPPORT); + break; + case EOPNOTSUPP: + WSASetLastError(WSAEOPNOTSUPP); + break; + case EPFNOSUPPORT: + WSASetLastError(WSAEPFNOSUPPORT); + break; + case EAFNOSUPPORT: + WSASetLastError(WSAEAFNOSUPPORT); + break; + case EADDRINUSE: + WSASetLastError(WSAEADDRINUSE); + break; + case EADDRNOTAVAIL: + WSASetLastError(WSAEADDRNOTAVAIL); + break; + case ENETDOWN: + WSASetLastError(WSAENETDOWN); + break; + case ENETUNREACH: + WSASetLastError(WSAENETUNREACH); + break; + case ENETRESET: + WSASetLastError(WSAENETRESET); + break; + case ECONNABORTED: + WSASetLastError(WSAECONNABORTED); + break; + case ECONNRESET: + WSASetLastError(WSAECONNRESET); + break; + case ENOBUFS: + WSASetLastError(WSAENOBUFS); + break; + case EISCONN: + WSASetLastError(WSAEISCONN); + break; + case ENOTCONN: + WSASetLastError(WSAENOTCONN); + break; + case ESHUTDOWN: + WSASetLastError(WSAESHUTDOWN); + break; + case ETOOMANYREFS: + WSASetLastError(WSAETOOMANYREFS); + break; + case ETIMEDOUT: + WSASetLastError(WSAETIMEDOUT); + break; + case ECONNREFUSED: + WSASetLastError(WSAECONNREFUSED); + break; + case ELOOP: + WSASetLastError(WSAELOOP); + break; + case ENAMETOOLONG: + WSASetLastError(WSAENAMETOOLONG); + break; + case EHOSTDOWN: + WSASetLastError(WSAEHOSTDOWN); + break; + case EHOSTUNREACH: + WSASetLastError(WSAEHOSTUNREACH); + break; + case ENOTEMPTY: + WSASetLastError(WSAENOTEMPTY); + break; + case EPROCLIM: + WSASetLastError(WSAEPROCLIM); + break; + case EUSERS: + WSASetLastError(WSAEUSERS); + break; + case EDQUOT: + WSASetLastError(WSAEDQUOT); + break; + case ESTALE: + WSASetLastError(WSAESTALE); + break; + case EREMOTE: + WSASetLastError(WSAEREMOTE); + break; + case EFAULT: + WSASetLastError(WSAEFAULT); + break; + case ENODATA: + WSASetLastError(WSANO_DATA); + break; +#if EAGAIN != EWOULDBLOCK + case EAGAIN: + WSASetLastError(WSAEWOULDBLOCK); + break; +#endif + /* Rough equivalent */ + case EIO: + WSASetLastError(WSAEREFUSED); + break; + + default: /* Unmapped errors */ + WSASetLastError(WSAENOBUFS); + break; + } +} diff --git a/src/platform/w32functions.h b/src/platform/w32functions.h @@ -0,0 +1,176 @@ +/* + This file is part of libmicrohttpd + (C) 2014 Karlson2k (Evgeny Grin) + + 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. + + You should have received a copy of the GNU Lesser General Public + License along with this library. + If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file platform/w32functions.h + * @brief internal functions for W32 systems + * @author Karlson2k (Evgeny Grin) + */ + +#ifndef MHD_W32FUNCTIONS_H +#define MHD_W32FUNCTIONS_H +#ifndef _WIN32 +#error w32functions.h is designed only for W32 systems +#endif + +#include <errno.h> +#include <winsock2.h> +#include "platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MHDW32ERRBASE 3300 + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK (MHDW32ERRBASE+1) +#endif +#ifndef EINPROGRESS +#define EINPROGRESS (MHDW32ERRBASE+2) +#endif +#ifndef EALREADY +#define EALREADY (MHDW32ERRBASE+3) +#endif +#ifndef ENOTSOCK +#define ENOTSOCK (MHDW32ERRBASE+4) +#endif +#ifndef EDESTADDRREQ +#define EDESTADDRREQ (MHDW32ERRBASE+5) +#endif +#ifndef EMSGSIZE +#define EMSGSIZE (MHDW32ERRBASE+6) +#endif +#ifndef EPROTOTYPE +#define EPROTOTYPE (MHDW32ERRBASE+7) +#endif +#ifndef ENOPROTOOPT +#define ENOPROTOOPT (MHDW32ERRBASE+8) +#endif +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT (MHDW32ERRBASE+9) +#endif +#ifndef EOPNOTSUPP +#define EOPNOTSUPP (MHDW32ERRBASE+10) +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT (MHDW32ERRBASE+11) +#endif +#ifndef EADDRINUSE +#define EADDRINUSE (MHDW32ERRBASE+12) +#endif +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL (MHDW32ERRBASE+13) +#endif +#ifndef ENETDOWN +#define ENETDOWN (MHDW32ERRBASE+14) +#endif +#ifndef ENETUNREACH +#define ENETUNREACH (MHDW32ERRBASE+15) +#endif +#ifndef ENETRESET +#define ENETRESET (MHDW32ERRBASE+16) +#endif +#ifndef ECONNABORTED +#define ECONNABORTED (MHDW32ERRBASE+17) +#endif +#ifndef ECONNRESET +#define ECONNRESET (MHDW32ERRBASE+18) +#endif +#ifndef ENOBUFS +#define ENOBUFS (MHDW32ERRBASE+19) +#endif +#ifndef EISCONN +#define EISCONN (MHDW32ERRBASE+20) +#endif +#ifndef ENOTCONN +#define ENOTCONN (MHDW32ERRBASE+21) +#endif +#ifndef ETOOMANYREFS +#define ETOOMANYREFS (MHDW32ERRBASE+22) +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED (MHDW32ERRBASE+23) +#endif +#ifndef ELOOP +#define ELOOP (MHDW32ERRBASE+24) +#endif +#ifndef EHOSTDOWN +#define EHOSTDOWN (MHDW32ERRBASE+25) +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH (MHDW32ERRBASE+26) +#endif +#ifndef EPROCLIM +#define EPROCLIM (MHDW32ERRBASE+27) +#endif +#ifndef EUSERS +#define EUSERS (MHDW32ERRBASE+28) +#endif +#ifndef EDQUOT +#define EDQUOT (MHDW32ERRBASE+29) +#endif +#ifndef ESTALE +#define ESTALE (MHDW32ERRBASE+30) +#endif +#ifndef EREMOTE +#define EREMOTE (MHDW32ERRBASE+31) +#endif +#ifndef ESOCKTNOSUPPORT +#define ESOCKTNOSUPPORT (MHDW32ERRBASE+32) +#endif +#ifndef EPFNOSUPPORT +#define EPFNOSUPPORT (MHDW32ERRBASE+33) +#endif +#ifndef ESHUTDOWN +#define ESHUTDOWN (MHDW32ERRBASE+34) +#endif +#ifndef ENODATA +#define ENODATA (MHDW32ERRBASE+35) +#endif + +/** + * Return errno equivalent of last winsock error + * @return errno equivalent of last winsock error + */ +int MHD_W32_errno_from_winsock_(void); +/** + * Return pointer to string description of errnum error + * Works fine with both standard errno errnums + * and errnums from MHD_W32_errno_from_winsock_ + * @param errnum the errno or value from MHD_W32_errno_from_winsock_() + * @return pointer to string description of error + */ +const char* MHD_W32_strerror_(int errnum); +/** + * Return pointer to string description of last winsock error + * @return pointer to string description of last winsock error + */ +const char* MHD_W32_strerror_last_winsock_(void); +/** + * Set last winsock error to equivalent of given errno value + * @param errnum the errno value to set + */ +void MHD_W32_set_last_winsock_error_(int errnum); + +#ifdef __cplusplus +} +#endif +#endif //MHD_W32FUNCTIONS_H diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am @@ -137,7 +137,12 @@ test_digestauth_with_arguments_LDADD = \ @LIBCURL@ @LIBGCRYPT_LIBS@ test_get_sendfile_SOURCES = \ - test_get_sendfile.c + test_get_sendfile.c \ + ../platform/platform_interface.h +if HAVE_W32 +test_get_sendfile_SOURCES += \ + ../platform/w32functions.h ../platform/w32functions.c +endif test_get_sendfile_LDADD = \ $(top_builddir)/src/microhttpd/libmicrohttpd.la \ @LIBCURL@ @@ -215,6 +220,10 @@ test_get11_LDADD = \ test_get_sendfile11_SOURCES = \ test_get_sendfile.c +if HAVE_W32 +test_get_sendfile11_SOURCES += \ + ../platform/w32functions.h ../platform/w32functions.c +endif test_get_sendfile11_LDADD = \ $(top_builddir)/src/microhttpd/libmicrohttpd.la \ @LIBCURL@ diff --git a/src/testcurl/test_get_sendfile.c b/src/testcurl/test_get_sendfile.c @@ -26,6 +26,7 @@ #include "MHD_config.h" #include "platform.h" +#include "platform_interface.h" #include <curl/curl.h> #include <microhttpd.h> #include <stdlib.h> @@ -93,7 +94,7 @@ ahc_echo (void *cls, { fprintf (stderr, "Failed to open `%s': %s\n", sourcefile, - STRERROR (errno)); + MHD_strerror_ (errno)); exit (1); } response = MHD_create_response_from_fd (strlen (TESTSTR), fd);