From 0cf71bf99a62ec6fa4f3f88d4dd59d29ebde4817 Mon Sep 17 00:00:00 2001 From: Shane Peelar Date: Sun, 15 Jun 2014 16:52:29 -0400 Subject: [PATCH 1/4] Added subdir-objects to configure.ac so automake 1.4 doesn't complain about forward compatibility --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6130202f..bd19a09e 100644 --- a/configure.ac +++ b/configure.ac @@ -26,7 +26,7 @@ m4_define([libhttpserver_REVISION],[2])dnl m4_define([libhttpserver_PKG_VERSION],[libhttpserver_MAJOR_VERSION.libhttpserver_MINOR_VERSION.libhttpserver_REVISION])dnl m4_define([libhttpserver_LDF_VERSION],[libhttpserver_MAJOR_VERSION:libhttpserver_MINOR_VERSION:libhttpserver_REVISION])dnl AC_INIT([libhttpserver], libhttpserver_PKG_VERSION, [electrictwister2000@gmail.com]) -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) From a3fb0ecee3cf607acea7902355b8716161ddd325 Mon Sep 17 00:00:00 2001 From: Shane Peelar Date: Mon, 16 Jun 2014 03:59:10 -0400 Subject: [PATCH 2/4] Introduce support for building on MinGW/Cygwin systems This patch modifies the build to properly handle MinGW/Cygwin hosts and adds support for Windows sockets in the source. This was achieved by using MHD_socket as the socket datatype where necessary, which is guaranteed to resolve to SOCKET on windows and int on unix systems, preserving old functionality while adding new. Some internal functions were modified to accomodate the change, namely those that implictly converted sockets to ints (which would have caused problems on x86_64 windows, as those are 8 byte unsigned) All test cases pass with MSYS2/MinGW compiler. --- configure.ac | 19 ++++++++- src/Makefile.am | 2 +- src/details/comet_manager.cpp | 3 +- src/details/http_endpoint.cpp | 6 +-- src/http_response.cpp | 4 +- src/http_utils.cpp | 8 ++++ src/httpserver/create_webserver.hpp | 6 +-- src/httpserver/http_utils.hpp | 10 ++--- src/httpserver/webserver.hpp | 6 ++- src/webserver.cpp | 62 +++++++++++++++++++---------- 10 files changed, 86 insertions(+), 40 deletions(-) diff --git a/configure.ac b/configure.ac index bd19a09e..c3333227 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,21 @@ if test x"$samedirectory" = x"no"; then fi fi +case "$host" in + *-mingw*) + NETWORK_HEADER="winsock2.h" + REGEX_LIBS="-lregex -no-undefined" + ;; + *-cygwin*) + NETWORK_HEADER="winsock2.h" + REGEX_LIBS="-lregex -no-undefined" + ;; + *) + NETWORK_HEADER="arpa/inet.h" + REGEX_LIBS="" + ;; +esac + # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADER([string],[],[AC_MSG_ERROR("C++ strings not found")]) @@ -73,7 +88,7 @@ AC_CHECK_HEADER([ctype.h],[],[AC_MSG_ERROR("cctype not found")]) AC_CHECK_HEADER([regex.h],[],[AC_MSG_ERROR("regex.h not found")]) AC_CHECK_HEADER([sys/stat.h],[],[AC_MSG_ERROR("sys/stat.h not found")]) AC_CHECK_HEADER([sys/types.h],[],[AC_MSG_ERROR("sys/types.h not found")]) -AC_CHECK_HEADER([arpa/inet.h],[],[AC_MSG_ERROR("arpa/inet.h not found")]) +AC_CHECK_HEADER([$NETWORK_HEADER],[],[AC_MSG_ERROR("$NETWORK_HEADER not found")]) AC_CHECK_HEADER([signal.h],[],[AC_MSG_ERROR("signal.h not found")]) AC_CHECK_HEADER([gnutls/gnutls.h],[have_gnutls="yes"],[AC_MSG_WARN("gnutls/gnutls.h not found. TLS will be disabled"); have_gnutls="no"]) @@ -84,7 +99,7 @@ PKG_CHECK_MODULES([LIBMICROHTTPD],[libmicrohttpd >= 0.9.7],[],[AC_MSG_ERROR("lib #AC_CHECK_LIB([microhttpd],[MHD_start_daemon],[],[AC_MSG_ERROR("Microhttpd header files not found. Please use a version >= 0.9.9.")]) CXXFLAGS="-DHTTPSERVER_COMPILATION -D_REENTRANT $LIBMICROHTTPD_CFLAGS $CXXFLAGS" -LDFLAGS="$LIBMICROHTTPD_LIBS $LD_FLAGS" +LDFLAGS="$LIBMICROHTTPD_LIBS $REGEX_LIBS $LD_FLAGS" m4_pattern_allow([AC_TYPE_SIZE_T]) m4_pattern_allow([AC_TYPE_UINT16_T]) diff --git a/src/Makefile.am b/src/Makefile.am index c7681d3f..c88305f1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ AM_CXXFLAGS += -fPIC -Wall libhttpserver_la_LIBADD = -lmicrohttpd libhttpserver_la_LDFLAGS = -install-exec-hook: +install-data-hook: (mkdir -p $(DESTDIR)$(includedir) && cd $(DESTDIR)$(includedir) && $(LN_S) -f httpserver.hpp httpserverpp) uninstall-hook: diff --git a/src/details/comet_manager.cpp b/src/details/comet_manager.cpp index c3b42640..d9d13adf 100644 --- a/src/details/comet_manager.cpp +++ b/src/details/comet_manager.cpp @@ -21,6 +21,7 @@ #include #include #include "details/comet_manager.hpp" +#include using namespace std; @@ -140,7 +141,7 @@ size_t comet_manager::get_topic_consumers( { consumers.insert((*it)); } - int size = consumers.size(); + std::set::size_type size = consumers.size(); pthread_rwlock_unlock(&comet_guard); return size; } diff --git a/src/details/http_endpoint.cpp b/src/details/http_endpoint.cpp index 59afa375..1fa7e059 100644 --- a/src/details/http_endpoint.cpp +++ b/src/details/http_endpoint.cpp @@ -99,8 +99,8 @@ http_endpoint::http_endpoint (parts[i][parts[i].size() - 1] == '}') ) { - int bar = parts[i].find_first_of('|'); - if(bar != (int)string::npos) + std::string::size_type bar = parts[i].find_first_of('|'); + if(bar != string::npos) { this->url_pars.push_back(parts[i].substr(1, bar - 1)); if(first) @@ -201,7 +201,7 @@ http_endpoint& http_endpoint::operator =(const http_endpoint& h) bool http_endpoint::operator <(const http_endpoint& b) const { - COMPARATOR(this->url_modded, b.url_modded, toupper); + COMPARATOR(this->url_modded, b.url_modded, std::toupper); } bool http_endpoint::match(const http_endpoint& url) const diff --git a/src/http_response.cpp b/src/http_response.cpp index d2eaf1be..d086e15e 100644 --- a/src/http_response.cpp +++ b/src/http_response.cpp @@ -207,7 +207,7 @@ namespace details ssize_t cb(void* cls, uint64_t pos, char* buf, size_t max) { - int val = static_cast(cls)->cycle_callback(buf); + ssize_t val = static_cast(cls)->cycle_callback(buf); if(val == -1) static_cast(cls)->completed = true; return val; @@ -272,7 +272,7 @@ ssize_t http_response::data_generator( if(_this->ws->pop_signaled(_this->connection_id)) { string message; - int size = _this->ws->read_message(_this->connection_id, message); + size_t size = _this->ws->read_message(_this->connection_id, message); memcpy(buf, message.c_str(), size); return size; } diff --git a/src/http_utils.cpp b/src/http_utils.cpp index 74d00629..96c05df0 100644 --- a/src/http_utils.cpp +++ b/src/http_utils.cpp @@ -21,7 +21,15 @@ #include #include #include +#if defined(__MINGW32__) || defined(__CYGWIN32__) +#define _WINDOWS +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x600 +#include +#include +#else #include +#endif #include #include #include diff --git a/src/httpserver/create_webserver.hpp b/src/httpserver/create_webserver.hpp index 0c6582b3..262a02e4 100644 --- a/src/httpserver/create_webserver.hpp +++ b/src/httpserver/create_webserver.hpp @@ -85,7 +85,7 @@ class create_webserver { } - explicit create_webserver(int port): + explicit create_webserver(uint16_t port): _port(port), _start_method(http::http_utils::INTERNAL_SELECT), _max_threads(0), @@ -125,7 +125,7 @@ class create_webserver { } - create_webserver& port(int port) { _port = port; return *this; } + create_webserver& port(uint16_t port) { _port = port; return *this; } create_webserver& start_method( const http::http_utils::start_method_T& start_method ) @@ -317,7 +317,7 @@ class create_webserver } private: - int _port; + uint16_t _port; http::http_utils::start_method_T _start_method; int _max_threads; int _max_connections; diff --git a/src/httpserver/http_utils.hpp b/src/httpserver/http_utils.hpp index deccc180..9707aca9 100644 --- a/src/httpserver/http_utils.hpp +++ b/src/httpserver/http_utils.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -238,8 +238,8 @@ class http_utils \ for (size_t n = 0; n < l1; n++)\ {\ - char xc = op((x)[n]);\ - char yc = op((y)[n]);\ + int xc = op((x)[n]);\ + int yc = op((y)[n]);\ if (xc < yc) return true;\ if (xc > yc) return false;\ }\ @@ -255,7 +255,7 @@ class header_comparator { **/ bool operator()(const std::string& x,const std::string& y) const { - COMPARATOR(x, y, toupper); + COMPARATOR(x, y, std::toupper); } }; @@ -274,7 +274,7 @@ class arg_comparator { bool operator()(const std::string& x,const std::string& y) const { #ifdef CASE_INSENSITIVE - COMPARATOR(x, y, toupper); + COMPARATOR(x, y, std::toupper); #else COMPARATOR(x, y, ); #endif diff --git a/src/httpserver/webserver.hpp b/src/httpserver/webserver.hpp index 305cf0d9..55591524 100644 --- a/src/httpserver/webserver.hpp +++ b/src/httpserver/webserver.hpp @@ -188,7 +188,7 @@ class webserver webserver& operator=(const webserver& other); private: - const int port; + const uint16_t port; http::http_utils::start_method_T start_method; const int max_threads; const int max_connections; @@ -200,7 +200,9 @@ class webserver validator_ptr validator; unescaper_ptr unescaper; const struct sockaddr* bind_address; - int bind_socket; + /* Changed type to MHD_socket because this type will always reflect the + platform's actual socket type (e.g. SOCKET on windows, int on unixes)*/ + MHD_socket bind_socket; const int max_thread_stack_size; const bool use_ssl; const bool use_ipv6; diff --git a/src/webserver.cpp b/src/webserver.cpp index 669338fa..50ea3196 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -27,7 +27,15 @@ #include #include #include +#include + +#if defined(__MINGW32__) || defined(__CYGWIN32__) +#include +#define _WINDOWS +#else #include +#endif + #include #include #include @@ -115,12 +123,16 @@ struct compare_value } }; +#ifndef __MINGW32__ static void catcher (int sig) { } +#endif static void ignore_sigpipe () { +//Mingw doesn't implement SIGPIPE +#ifndef __MINGW32__ struct sigaction oldsig; struct sigaction sig; @@ -136,6 +148,7 @@ static void ignore_sigpipe () gettext("Failed to install SIGPIPE handler: %s\n"), strerror (errno) ); +#endif } //WEBSERVER @@ -259,7 +272,7 @@ void* webserver::select(void* self) fd_set es; struct timeval timeout_value; details::daemon_item* di = static_cast(self); - int max; + MHD_socket max; while (di->ws->is_running()) { max = 0; @@ -298,7 +311,7 @@ void* webserver::select(void* self) int local_max; (*it).second.supply_events(&rs, &ws, &es, &local_max); - if(local_max > max) + if((MHD_socket) local_max > max) max = local_max; struct timeval t = (*it).second.get_timeout(); @@ -321,7 +334,9 @@ void* webserver::select(void* self) timeout_value.tv_sec = timeout_secs; timeout_value.tv_usec = timeout_microsecs; - ::select (max + 1, &rs, &ws, &es, &timeout_value); + /*On unix, MHD_socket will be an int anyway. + On windows, the cast is safe because winsock ignores first argument to select*/ + ::select ((int) max + 1, &rs, &ws, &es, &timeout_value); MHD_run (di->daemon); //EVENT SUPPLIERS DISPATCHING @@ -338,24 +353,25 @@ void* webserver::select(void* self) return 0x0; } -int create_socket (int domain, int type, int protocol) +MHD_socket create_socket (int domain, int type, int protocol) { int sock_cloexec = SOCK_CLOEXEC; int ctype = SOCK_STREAM | sock_cloexec; - int fd; - - /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo + + /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo * implementations do not set ai_socktype, e.g. RHL6.2. */ - fd = socket(domain, ctype, protocol); + MHD_socket fd = socket(domain, ctype, protocol); + +#ifdef _WINDOWS + if (fd == INVALID_SOCKET) +#else if ((fd == -1) && (errno == EINVAL || errno == EPROTONOSUPPORT) && (sock_cloexec != 0) ) +#endif { - sock_cloexec = 0; fd = socket(domain, type, protocol); } - if (-1 == fd) - return -1; return fd; } @@ -488,7 +504,7 @@ bool webserver::start(bool blocking) setsockopt (bind_socket, SOL_SOCKET, SO_REUSEADDR, - &on, sizeof (on)); + (const char*) &on, sizeof (on)); if(use_ipv6) { @@ -496,16 +512,21 @@ bool webserver::start(bool blocking) #ifdef IPV6_V6ONLY setsockopt (bind_socket, IPPROTO_IPV6, IPV6_V6ONLY, - &on, sizeof (on) + (const char*) &on, sizeof (on) ); #endif #endif } bind(bind_socket, servaddr, addrlen); } +#ifdef _WINDOWS + unsigned long ioarg = 1; + ioctlsocket(bind_socket, FIONBIO, &ioarg); +#else int flags = fcntl (bind_socket, F_GETFL); flags |= O_NONBLOCK; fcntl (bind_socket, F_SETFL, flags); +#endif if(!bind_settled) listen(bind_socket, 1); iov.push_back(gen(MHD_OPTION_LISTEN_SOCKET, bind_socket)); @@ -730,7 +751,7 @@ int webserver::build_request_args ( mr->dhr->querystring += string(buf); } } - int size = internal_unescaper((void*) mr->ws, value); + size_t size = internal_unescaper((void*) mr->ws, value); mr->dhr->set_arg(key, string(value, size)); return MHD_YES; } @@ -1046,18 +1067,17 @@ int webserver::finalize_answer( details::http_resource_mirror >::iterator it; - int len = -1; - int tot_len = -1; + size_t len = 0; + size_t tot_len = 0; for( it=registered_resources.begin(); it!=registered_resources.end(); ++it ) { - int endpoint_pieces_len = (*it).first.get_url_pieces_num(); - int endpoint_tot_len = (*it).first.get_url_complete_size(); - if(tot_len == -1 || - len == -1 || + size_t endpoint_pieces_len = (*it).first.get_url_pieces_num(); + size_t endpoint_tot_len = (*it).first.get_url_complete_size(); + if(!found || endpoint_pieces_len > len || ( endpoint_pieces_len == len && @@ -1078,7 +1098,7 @@ int webserver::finalize_answer( { vector url_pars; - unsigned int pars_size = + size_t pars_size = found_endpoint->first.get_url_pars(url_pars); vector url_pieces; From 1ac799d3b9ce8019c85c72634f2b13c030402b37 Mon Sep 17 00:00:00 2001 From: Shane Peelar Date: Tue, 17 Jun 2014 20:39:19 -0400 Subject: [PATCH 3/4] Updated Travis to use libmicrohttpd-0.9.37 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc067d77..71a01ec0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,9 @@ compiler: # Change this to your needs before_install: - sudo apt-get install texinfo - - wget http://199.231.187.83/resources/libmicrohttpd-0.9.26.tar.gz - - tar -xvzf libmicrohttpd-0.9.26.tar.gz - - cd libmicrohttpd-0.9.26 + - wget ftp://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.37.tar.gz + - tar -xvzf libmicrohttpd-0.9.37.tar.gz + - cd libmicrohttpd-0.9.37 - ./configure --prefix=/usr - make - sudo make install From 9d8c006e6ab8594409f16ef3d5ea364b8973c47d Mon Sep 17 00:00:00 2001 From: Shane Peelar Date: Wed, 18 Jun 2014 12:07:42 -0400 Subject: [PATCH 4/4] Modified one last area where int was used as socket type instead of MHD_socket, this time being in the API. MHD_socket is int on unix systems, so this change shouldn't break any existing code --- README.md | 4 ++++ src/httpserver/details/event_tuple.hpp | 2 +- src/httpserver/event_supplier.hpp | 2 +- src/webserver.cpp | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 278e70cd..0a1ad396 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,10 @@ Requirements * libmicrohttpd >= 0.9.7 * doxygen (if you want to build code reference) +Additionally, for MinGW on windows you will need: +* libwinpthread (For MinGW-w64, if you use thread model posix then you have this) +* libgnurx >= 2.5.1 + Compilation =========== libhttpserver uses the standard system where the usual build process diff --git a/src/httpserver/details/event_tuple.hpp b/src/httpserver/details/event_tuple.hpp index ec289120..a81ca7b9 100644 --- a/src/httpserver/details/event_tuple.hpp +++ b/src/httpserver/details/event_tuple.hpp @@ -42,7 +42,7 @@ namespace details fd_set*, fd_set*, fd_set*, - int* + MHD_socket* ); typedef struct timeval(*get_timeout_ptr)(); diff --git a/src/httpserver/event_supplier.hpp b/src/httpserver/event_supplier.hpp index 6835050e..9c7e223b 100644 --- a/src/httpserver/event_supplier.hpp +++ b/src/httpserver/event_supplier.hpp @@ -43,7 +43,7 @@ class event_supplier fd_set* read_fdset, fd_set* write_fdset, fd_set* exc_fdset, - int* max + MHD_socket* max ) const { static_cast(this)->supply_events( diff --git a/src/webserver.cpp b/src/webserver.cpp index 50ea3196..e5122cd0 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -308,10 +308,10 @@ void* webserver::select(void* self) ++it ) { - int local_max; + MHD_socket local_max; (*it).second.supply_events(&rs, &ws, &es, &local_max); - if((MHD_socket) local_max > max) + if(local_max > max) max = local_max; struct timeval t = (*it).second.get_timeout();