Skip to content

Commit a3fb0ec

Browse files
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.
1 parent 0cf71bf commit a3fb0ec

File tree

10 files changed

+86
-40
lines changed

10 files changed

+86
-40
lines changed

configure.ac

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@ if test x"$samedirectory" = x"no"; then
5353
fi
5454
fi
5555

56+
case "$host" in
57+
*-mingw*)
58+
NETWORK_HEADER="winsock2.h"
59+
REGEX_LIBS="-lregex -no-undefined"
60+
;;
61+
*-cygwin*)
62+
NETWORK_HEADER="winsock2.h"
63+
REGEX_LIBS="-lregex -no-undefined"
64+
;;
65+
*)
66+
NETWORK_HEADER="arpa/inet.h"
67+
REGEX_LIBS=""
68+
;;
69+
esac
70+
5671
# Checks for header files.
5772
AC_HEADER_STDC
5873
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")])
7388
AC_CHECK_HEADER([regex.h],[],[AC_MSG_ERROR("regex.h not found")])
7489
AC_CHECK_HEADER([sys/stat.h],[],[AC_MSG_ERROR("sys/stat.h not found")])
7590
AC_CHECK_HEADER([sys/types.h],[],[AC_MSG_ERROR("sys/types.h not found")])
76-
AC_CHECK_HEADER([arpa/inet.h],[],[AC_MSG_ERROR("arpa/inet.h not found")])
91+
AC_CHECK_HEADER([$NETWORK_HEADER],[],[AC_MSG_ERROR("$NETWORK_HEADER not found")])
7792
AC_CHECK_HEADER([signal.h],[],[AC_MSG_ERROR("signal.h not found")])
7893

7994
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
8499
#AC_CHECK_LIB([microhttpd],[MHD_start_daemon],[],[AC_MSG_ERROR("Microhttpd header files not found. Please use a version >= 0.9.9.")])
85100

86101
CXXFLAGS="-DHTTPSERVER_COMPILATION -D_REENTRANT $LIBMICROHTTPD_CFLAGS $CXXFLAGS"
87-
LDFLAGS="$LIBMICROHTTPD_LIBS $LD_FLAGS"
102+
LDFLAGS="$LIBMICROHTTPD_LIBS $REGEX_LIBS $LD_FLAGS"
88103

89104
m4_pattern_allow([AC_TYPE_SIZE_T])
90105
m4_pattern_allow([AC_TYPE_UINT16_T])

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ AM_CXXFLAGS += -fPIC -Wall
2626
libhttpserver_la_LIBADD = -lmicrohttpd
2727
libhttpserver_la_LDFLAGS =
2828

29-
install-exec-hook:
29+
install-data-hook:
3030
(mkdir -p $(DESTDIR)$(includedir) && cd $(DESTDIR)$(includedir) && $(LN_S) -f httpserver.hpp httpserverpp)
3131

3232
uninstall-hook:

src/details/comet_manager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <errno.h>
2222
#include <iostream>
2323
#include "details/comet_manager.hpp"
24+
#include <sys/time.h>
2425

2526
using namespace std;
2627

@@ -140,7 +141,7 @@ size_t comet_manager::get_topic_consumers(
140141
{
141142
consumers.insert((*it));
142143
}
143-
int size = consumers.size();
144+
std::set<httpserver::http::httpserver_ska>::size_type size = consumers.size();
144145
pthread_rwlock_unlock(&comet_guard);
145146
return size;
146147
}

src/details/http_endpoint.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ http_endpoint::http_endpoint
9999
(parts[i][parts[i].size() - 1] == '}')
100100
)
101101
{
102-
int bar = parts[i].find_first_of('|');
103-
if(bar != (int)string::npos)
102+
std::string::size_type bar = parts[i].find_first_of('|');
103+
if(bar != string::npos)
104104
{
105105
this->url_pars.push_back(parts[i].substr(1, bar - 1));
106106
if(first)
@@ -201,7 +201,7 @@ http_endpoint& http_endpoint::operator =(const http_endpoint& h)
201201

202202
bool http_endpoint::operator <(const http_endpoint& b) const
203203
{
204-
COMPARATOR(this->url_modded, b.url_modded, toupper);
204+
COMPARATOR(this->url_modded, b.url_modded, std::toupper);
205205
}
206206

207207
bool http_endpoint::match(const http_endpoint& url) const

src/http_response.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ namespace details
207207

208208
ssize_t cb(void* cls, uint64_t pos, char* buf, size_t max)
209209
{
210-
int val = static_cast<http_response*>(cls)->cycle_callback(buf);
210+
ssize_t val = static_cast<http_response*>(cls)->cycle_callback(buf);
211211
if(val == -1)
212212
static_cast<http_response*>(cls)->completed = true;
213213
return val;
@@ -272,7 +272,7 @@ ssize_t http_response::data_generator(
272272
if(_this->ws->pop_signaled(_this->connection_id))
273273
{
274274
string message;
275-
int size = _this->ws->read_message(_this->connection_id, message);
275+
size_t size = _this->ws->read_message(_this->connection_id, message);
276276
memcpy(buf, message.c_str(), size);
277277
return size;
278278
}

src/http_utils.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@
2121
#include <stdio.h>
2222
#include <stdlib.h>
2323
#include <string.h>
24+
#if defined(__MINGW32__) || defined(__CYGWIN32__)
25+
#define _WINDOWS
26+
#undef _WIN32_WINNT
27+
#define _WIN32_WINNT 0x600
28+
#include <winsock2.h>
29+
#include <ws2tcpip.h>
30+
#else
2431
#include <arpa/inet.h>
32+
#endif
2533
#include <sstream>
2634
#include <iomanip>
2735
#include <fstream>

src/httpserver/create_webserver.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class create_webserver
8585
{
8686
}
8787

88-
explicit create_webserver(int port):
88+
explicit create_webserver(uint16_t port):
8989
_port(port),
9090
_start_method(http::http_utils::INTERNAL_SELECT),
9191
_max_threads(0),
@@ -125,7 +125,7 @@ class create_webserver
125125
{
126126
}
127127

128-
create_webserver& port(int port) { _port = port; return *this; }
128+
create_webserver& port(uint16_t port) { _port = port; return *this; }
129129
create_webserver& start_method(
130130
const http::http_utils::start_method_T& start_method
131131
)
@@ -317,7 +317,7 @@ class create_webserver
317317
}
318318

319319
private:
320-
int _port;
320+
uint16_t _port;
321321
http::http_utils::start_method_T _start_method;
322322
int _max_threads;
323323
int _max_connections;

src/httpserver/http_utils.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
#include <microhttpd.h>
2929
#include <string>
30-
#include <ctype.h>
30+
#include <cctype>
3131
#include <vector>
3232
#include <algorithm>
3333
#include <exception>
@@ -238,8 +238,8 @@ class http_utils
238238
\
239239
for (size_t n = 0; n < l1; n++)\
240240
{\
241-
char xc = op((x)[n]);\
242-
char yc = op((y)[n]);\
241+
int xc = op((x)[n]);\
242+
int yc = op((y)[n]);\
243243
if (xc < yc) return true;\
244244
if (xc > yc) return false;\
245245
}\
@@ -255,7 +255,7 @@ class header_comparator {
255255
**/
256256
bool operator()(const std::string& x,const std::string& y) const
257257
{
258-
COMPARATOR(x, y, toupper);
258+
COMPARATOR(x, y, std::toupper);
259259
}
260260
};
261261

@@ -274,7 +274,7 @@ class arg_comparator {
274274
bool operator()(const std::string& x,const std::string& y) const
275275
{
276276
#ifdef CASE_INSENSITIVE
277-
COMPARATOR(x, y, toupper);
277+
COMPARATOR(x, y, std::toupper);
278278
#else
279279
COMPARATOR(x, y, );
280280
#endif

src/httpserver/webserver.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ class webserver
188188
webserver& operator=(const webserver& other);
189189

190190
private:
191-
const int port;
191+
const uint16_t port;
192192
http::http_utils::start_method_T start_method;
193193
const int max_threads;
194194
const int max_connections;
@@ -200,7 +200,9 @@ class webserver
200200
validator_ptr validator;
201201
unescaper_ptr unescaper;
202202
const struct sockaddr* bind_address;
203-
int bind_socket;
203+
/* Changed type to MHD_socket because this type will always reflect the
204+
platform's actual socket type (e.g. SOCKET on windows, int on unixes)*/
205+
MHD_socket bind_socket;
204206
const int max_thread_stack_size;
205207
const bool use_ssl;
206208
const bool use_ipv6;

src/webserver.cpp

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@
2727
#include <unistd.h>
2828
#include <sys/stat.h>
2929
#include <sys/types.h>
30+
#include <sys/time.h>
31+
32+
#if defined(__MINGW32__) || defined(__CYGWIN32__)
33+
#include <winsock2.h>
34+
#define _WINDOWS
35+
#else
3036
#include <netinet/ip.h>
37+
#endif
38+
3139
#include <signal.h>
3240
#include <fcntl.h>
3341
#include <algorithm>
@@ -115,12 +123,16 @@ struct compare_value
115123
}
116124
};
117125

126+
#ifndef __MINGW32__
118127
static void catcher (int sig)
119128
{
120129
}
130+
#endif
121131

122132
static void ignore_sigpipe ()
123133
{
134+
//Mingw doesn't implement SIGPIPE
135+
#ifndef __MINGW32__
124136
struct sigaction oldsig;
125137
struct sigaction sig;
126138

@@ -136,6 +148,7 @@ static void ignore_sigpipe ()
136148
gettext("Failed to install SIGPIPE handler: %s\n"),
137149
strerror (errno)
138150
);
151+
#endif
139152
}
140153

141154
//WEBSERVER
@@ -259,7 +272,7 @@ void* webserver::select(void* self)
259272
fd_set es;
260273
struct timeval timeout_value;
261274
details::daemon_item* di = static_cast<details::daemon_item*>(self);
262-
int max;
275+
MHD_socket max;
263276
while (di->ws->is_running())
264277
{
265278
max = 0;
@@ -298,7 +311,7 @@ void* webserver::select(void* self)
298311
int local_max;
299312
(*it).second.supply_events(&rs, &ws, &es, &local_max);
300313

301-
if(local_max > max)
314+
if((MHD_socket) local_max > max)
302315
max = local_max;
303316

304317
struct timeval t = (*it).second.get_timeout();
@@ -321,7 +334,9 @@ void* webserver::select(void* self)
321334
timeout_value.tv_sec = timeout_secs;
322335
timeout_value.tv_usec = timeout_microsecs;
323336

324-
::select (max + 1, &rs, &ws, &es, &timeout_value);
337+
/*On unix, MHD_socket will be an int anyway.
338+
On windows, the cast is safe because winsock ignores first argument to select*/
339+
::select ((int) max + 1, &rs, &ws, &es, &timeout_value);
325340
MHD_run (di->daemon);
326341

327342
//EVENT SUPPLIERS DISPATCHING
@@ -338,24 +353,25 @@ void* webserver::select(void* self)
338353
return 0x0;
339354
}
340355

341-
int create_socket (int domain, int type, int protocol)
356+
MHD_socket create_socket (int domain, int type, int protocol)
342357
{
343358
int sock_cloexec = SOCK_CLOEXEC;
344359
int ctype = SOCK_STREAM | sock_cloexec;
345-
int fd;
346-
347-
/* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
360+
361+
/* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
348362
* implementations do not set ai_socktype, e.g. RHL6.2. */
349-
fd = socket(domain, ctype, protocol);
363+
MHD_socket fd = socket(domain, ctype, protocol);
364+
365+
#ifdef _WINDOWS
366+
if (fd == INVALID_SOCKET)
367+
#else
350368
if ((fd == -1) &&
351369
(errno == EINVAL || errno == EPROTONOSUPPORT) && (sock_cloexec != 0)
352370
)
371+
#endif
353372
{
354-
sock_cloexec = 0;
355373
fd = socket(domain, type, protocol);
356374
}
357-
if (-1 == fd)
358-
return -1;
359375
return fd;
360376
}
361377

@@ -488,24 +504,29 @@ bool webserver::start(bool blocking)
488504
setsockopt (bind_socket,
489505
SOL_SOCKET,
490506
SO_REUSEADDR,
491-
&on, sizeof (on));
507+
(const char*) &on, sizeof (on));
492508

493509
if(use_ipv6)
494510
{
495511
#ifdef IPPROTO_IPV6
496512
#ifdef IPV6_V6ONLY
497513
setsockopt (bind_socket,
498514
IPPROTO_IPV6, IPV6_V6ONLY,
499-
&on, sizeof (on)
515+
(const char*) &on, sizeof (on)
500516
);
501517
#endif
502518
#endif
503519
}
504520
bind(bind_socket, servaddr, addrlen);
505521
}
522+
#ifdef _WINDOWS
523+
unsigned long ioarg = 1;
524+
ioctlsocket(bind_socket, FIONBIO, &ioarg);
525+
#else
506526
int flags = fcntl (bind_socket, F_GETFL);
507527
flags |= O_NONBLOCK;
508528
fcntl (bind_socket, F_SETFL, flags);
529+
#endif
509530
if(!bind_settled)
510531
listen(bind_socket, 1);
511532
iov.push_back(gen(MHD_OPTION_LISTEN_SOCKET, bind_socket));
@@ -730,7 +751,7 @@ int webserver::build_request_args (
730751
mr->dhr->querystring += string(buf);
731752
}
732753
}
733-
int size = internal_unescaper((void*) mr->ws, value);
754+
size_t size = internal_unescaper((void*) mr->ws, value);
734755
mr->dhr->set_arg(key, string(value, size));
735756
return MHD_YES;
736757
}
@@ -1046,18 +1067,17 @@ int webserver::finalize_answer(
10461067
details::http_resource_mirror
10471068
>::iterator it;
10481069

1049-
int len = -1;
1050-
int tot_len = -1;
1070+
size_t len = 0;
1071+
size_t tot_len = 0;
10511072
for(
10521073
it=registered_resources.begin();
10531074
it!=registered_resources.end();
10541075
++it
10551076
)
10561077
{
1057-
int endpoint_pieces_len = (*it).first.get_url_pieces_num();
1058-
int endpoint_tot_len = (*it).first.get_url_complete_size();
1059-
if(tot_len == -1 ||
1060-
len == -1 ||
1078+
size_t endpoint_pieces_len = (*it).first.get_url_pieces_num();
1079+
size_t endpoint_tot_len = (*it).first.get_url_complete_size();
1080+
if(!found ||
10611081
endpoint_pieces_len > len ||
10621082
(
10631083
endpoint_pieces_len == len &&
@@ -1078,7 +1098,7 @@ int webserver::finalize_answer(
10781098
{
10791099
vector<string> url_pars;
10801100

1081-
unsigned int pars_size =
1101+
size_t pars_size =
10821102
found_endpoint->first.get_url_pars(url_pars);
10831103

10841104
vector<string> url_pieces;

0 commit comments

Comments
 (0)