Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide minimal support for Windows (fix #146) #198

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@ env:
- VALAC=valac-0.28
- VALAC=valac-0.30
- VALAC=valac VALAFLAGS=--fatal-warnings
- VALAC=valac CROSS=mingw-w64-i686
- VALAC=valac CROSS=mingw-w64-x86-64

before_install:
- sudo add-apt-repository --yes ppa:vala-team
- sudo add-apt-repository --yes ppa:wine/wine-builds
- sudo apt-get update --quiet
- sudo apt-get install --yes --force-yes ${VALAC} libglib2.0-bin
libglib2.0-dev libsoup2.4-dev libfcgi-dev python3-pip gcovr libgee-0.8-dev
libctpl-dev libjson-glib-dev libmemcached-dev libmarkdown2-dev
liblua5.2-dev valgrind
liblua5.2-dev valgrind $([[ -n ${CROSS} ]] && echo gcc-${CROSS} wine-staging)
- pip3 install meson sphinx sphinx_rtd_theme PyYAML
- wget https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-linux.zip
- unzip ninja-linux.zip -d ${HOME}/.local/bin

before_script:
- mkdir build
- meson -D b_coverage=true -D enable_examples=true . build
- meson -D b_coverage=true -D enable_examples=true $([[ -n ${CROSS} ]] && echo cross/${CROSS}.txt) . build
- ninja -C build -v
- ninja -C build -v docs/en

Expand Down
12 changes: 12 additions & 0 deletions cross/mingw-w64-i686.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[binaries]
exe_wrapper = 'wine'
c = '/usr/bin/i686-w64-mingw32-gcc'
strip = '/usr/bin/i686-w64-mingw32-strip'
pkgconfig = '/usr/bin/i686-w64-mingw32-pkg-config'
ar = '/usr/bin/i686-w64-mingw32-ar'

[host_machine]
system = 'windows'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'
12 changes: 12 additions & 0 deletions cross/mingw-w64-x86-64.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[binaries]
exe_wrapper = 'wine'
c = '/usr/bin/x86_64-w64-mingw32-gcc'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
ar = '/usr/bin/x86_64-w64-mingw32-ar'

[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
2 changes: 1 addition & 1 deletion docs/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ if valadoc.found()
'--package-version', meson.project_version(), '--pkg=glib-2.0',
'--pkg=gio-2.0', '--pkg=gio-unix-2.0',
'--pkg=gmodule-2.0', '--pkg=libsoup-2.4', '--pkg=posix',
'--target-glib=2.40', '--force'] + vala_defines + [ '--directory', '@OUTPUT@', '@INPUT@']
'--target-glib=2.40', '--force', '--directory', '@OUTPUT@', '@INPUT@']
custom_target('API documentation', command: valadoc_command + ['--doclet=html'],
input: vsgi_sources + valum_sources,
output: 'api',
Expand Down
25 changes: 19 additions & 6 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,37 @@ add_project_arguments(['--enable-experimental',
glib = dependency('glib-2.0', version: '>=2.40')
gobject = dependency('gobject-2.0', version: '>=2.40')
gio = dependency('gio-2.0', version: '>=2.40')
gio_unix = dependency('gio-unix-2.0', version: '>=2.40')
gio_unix = dependency('gio-unix-2.0', version: '>=2.40', required: false)
gio_windows = dependency('gio-windows-2.0', version: '>=2.40', required: false)
gmodule = dependency('gmodule-2.0', version: '>=2.40')
soup = dependency('libsoup-2.4', version: '>=2.44')

vala_defines = []

# provide 'OutputStream.write_all_async' and 'SimpleIOStream'
if gio.version().version_compare('>=2.44')
vala_defines += '--define=GIO_2_44'
add_project_arguments('--define=GIO_2_44', language: 'vala')
endif

# provide 'UnixInputStream', 'UnixOutputStream' and 'UnixSocketAddress'
if gio_unix.found()
add_project_arguments('--define=GIO_UNIX', language: 'vala')
endif

# provide 'Win32InputStream' and 'Win32OutputStream'
if gio_windows.found()
add_project_arguments('--define=GIO_WINDOWS', language: 'vala')
endif

# new 'Soup.Server' API
if soup.version().version_compare('>=2.48')
vala_defines += '--define=SOUP_2_48'
add_project_arguments('--define=SOUP_2_48', language: 'vala')
endif

if meson.get_compiler('c').links('void main (void) { fork (); }')
add_project_arguments('--define=HAVE_FORK', language: 'vala')
endif

if meson.get_compiler('c').has_function('memmem')
vala_defines += '--define=HAVE_MEMMEM'
add_project_arguments('--define=HAVE_MEMMEM', language: 'vala')
endif

subdir('src')
Expand Down
1 change: 0 additions & 1 deletion src/valum/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ valum_sources = files(
'valum-subdomain.vala')
valum_lib = library('valum-' + api_version, valum_sources,
dependencies: [glib, gobject, gio, soup, vsgi],
vala_args: vala_defines,
vala_header: 'valum.h',
install: true)

Expand Down
16 changes: 13 additions & 3 deletions src/vsgi/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ vsgi_sources = files(
'vsgi-socket-server.vala',
'vsgi-tee-output-stream.vala')
vsgi_lib = library('vsgi-' + api_version, vsgi_sources,
dependencies: [glib, gobject, gio, gio_unix, gmodule, soup],
vala_args: ['--pkg=posix'] + vala_defines,
dependencies: [glib, gobject, gio, gio_unix, gio_windows, gmodule, soup],
vala_args: ['--pkg=posix'],
vala_header: 'vsgi.h',
install: true,
install_rpath: '$ORIGIN/vsgi-@0@/servers'.format(api_version))
Expand All @@ -31,9 +31,19 @@ vsgi = declare_dependency(include_directories: include_directories('.'),

meson.add_install_script('install.sh')

vsgi_requires_private = ['gmodule-2.0']

if gio_unix.found ()
vsgi_requires_private += 'gio-unix-2.0'
endif

if gio_windows.found()
vsgi_requires_private += 'gio-windows-2.0'
endif

pkgconfig = import('pkgconfig')
pkgconfig.generate(requires: 'glib-2.0 gobject-2.0 gio-2.0 libsoup-2.4',
requires_private: 'gio-unix-2.0 gmodule-2.0',
requires_private: vsgi_requires_private,
libraries: vsgi_lib,
version: meson.project_version(),
name: 'VSGI',
Expand Down
8 changes: 2 additions & 6 deletions src/vsgi/servers/meson.build
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
shared_library('vsgi-http', ['vsgi-http.vala'],
dependencies: [glib, gobject, gio, soup, vsgi],
vala_args: vala_defines,
install: true,
install_dir: '@0@/vsgi-@1@/servers'.format(get_option('libdir'), api_version))

shared_library('vsgi-cgi', 'vsgi-cgi.vala',
dependencies: [glib, gobject, gio, gio_unix, soup, vsgi],
vala_args: vala_defines,
dependencies: [glib, gobject, gio, gio_unix, gio_windows, soup, vsgi],
install: true,
install_dir: '@0@/vsgi-@1@/servers'.format(get_option('libdir'), api_version))

fcgi = meson.get_compiler('c').find_library('fcgi', required: false)
if fcgi.found()
fcgi_vapi = meson.get_compiler('vala').find_library('fcgi', dirs: meson.current_source_dir())
shared_library('vsgi-fastcgi', 'vsgi-fastcgi.vala',
dependencies: [glib, gobject, gio, gio_unix, soup, vsgi, fcgi, fcgi_vapi],
vala_args: vala_defines,
dependencies: [glib, gobject, gio, gio_unix, gio_windows, soup, vsgi, fcgi, fcgi_vapi],
install: true,
install_dir: '@0@/vsgi-@1@/servers'.format(get_option('libdir'), api_version))
endif

shared_library('vsgi-scgi', 'vsgi-scgi.vala',
dependencies: [glib, gobject, gio, soup, vsgi],
vala_args: vala_defines,
install: true,
install_dir: '@0@/vsgi-@1@/servers'.format(get_option('libdir'), api_version))
14 changes: 14 additions & 0 deletions src/vsgi/servers/vsgi-cgi.vala
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,25 @@ namespace VSGI.CGI {
}

#if GIO_2_44
#if GIO_UNIX
var connection = new SimpleIOStream (new UnixInputStream (stdin.fileno (), true),
new UnixOutputStream (stdout.fileno (), true));
#elif GIO_WINDOWS
var connection = new SimpleIOStream (new Win32InputStream (stdin, true),
new Win32OutputStream (stdout, true));
#else
throw new IOError.NOT_SUPPORTED ("Support for system-dependant I/O stream is missing.");
#endif
#else
#if GIO_UNIX
var connection = new Connection (new UnixInputStream (stdin.fileno (), true),
new UnixOutputStream (stdout.fileno (), true));
#elif GIO_WINDOWS
var connection = new Connection (new Win32InputStream (stdin, true),
new Win32OutputStream (stdout, true));
#else
throw new IOError.NOT_SUPPORTED ("Support for system-dependant I/O stream is missing.");
#endif
#endif

var req = new Request.from_cgi_environment (connection, Environ.@get ());
Expand Down
62 changes: 56 additions & 6 deletions src/vsgi/servers/vsgi-fastcgi.vala
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,31 @@ namespace VSGI.FastCGI {
return "Unknown error code '%d'".printf (error);
}

private class StreamInputStream : UnixInputStream {
private class StreamInputStream :
#if GIO_UNIX
UnixInputStream
#elif GIO_WINDOWS
Win32InputStream
#else
InputStream
#endif
{

public unowned global::FastCGI.Stream @in { construct; get; }

#if GIO_UNIX
public StreamInputStream (int fd, global::FastCGI.Stream @in) {
Object (fd: fd, close_fd: false, @in: @in);
}
#elif GIO_WINDOWS
public StreamInputStream (void* handle, global::FastCGI.Stream @in) {
Object (handle: handle, close_handle: false, @in: @in);
}
#else
public StreamInputStream (global::FastCGI.Stream @in) {
Object (@in: @in);
}
#endif

public override ssize_t read (uint8[] buffer, Cancellable? cancellable = null) throws IOError {
var read = this.in.read (buffer);
Expand All @@ -80,15 +98,33 @@ namespace VSGI.FastCGI {
}
}

private class StreamOutputStream : UnixOutputStream {
private class StreamOutputStream :
#if GIO_UNIX
UnixOutputStream
#elif GIO_WINDOWS
Win32OutputStream
#else
OutputStream
#endif
{

public unowned global::FastCGI.Stream @out { construct; get; }

public unowned global::FastCGI.Stream err { construct; get; }

#if GIO_UNIX
public StreamOutputStream (int fd, global::FastCGI.Stream @out, global::FastCGI.Stream err) {
Object (fd: fd, close_fd: false, @out: @out, err: err);
}
#elif GIO_WINDOWS
public StreamOutputStream (void* handle, global::FastCGI.Stream @out, global::FastCGI.Stream err) {
Object (handle: handle, close_handle: false, @out: @out, err: err);
}
#else
public StreamOutputStream (global::FastCGI.Stream @out, global::FastCGI.Stream err) {
Object (@out: @out, err: err);
}
#endif

public override ssize_t write (uint8[] buffer, Cancellable? cancellable = null) throws IOError {
var written = this.out.put_str (buffer);
Expand Down Expand Up @@ -165,7 +201,10 @@ namespace VSGI.FastCGI {
if (address == null) {
fd = global::FastCGI.LISTENSOCK_FILENO;
_uris.append (new Soup.URI ("fcgi+fd://%d/".printf (fd)));
} else if (address is UnixSocketAddress) {
}

#if GIO_UNIX
else if (address is UnixSocketAddress) {
var socket_address = address as UnixSocketAddress;

fd = global::FastCGI.open_socket (socket_address.path, backlog);
Expand All @@ -175,7 +214,10 @@ namespace VSGI.FastCGI {
}

_uris.append (new Soup.URI ("fcgi+unix://%s/".printf (socket_address.path)));
} else if (address is InetSocketAddress) {
}
#endif

else if (address is InetSocketAddress) {
var inet_address = address as InetSocketAddress;

if (inet_address.get_family () == SocketFamily.IPV6) {
Expand Down Expand Up @@ -287,8 +329,16 @@ namespace VSGI.FastCGI {

yield;

this._input_stream = new StreamInputStream (fd, request.in);
this._output_stream = new StreamOutputStream (fd, request.out, request.err);
#if GIO_UNIX
_input_stream = new StreamInputStream (fd, request.in);
_output_stream = new StreamOutputStream (fd, request.out, request.err);
#elif GIO_WINDOWS
_input_stream = new StreamInputStream ((void*) fd, request.in);
_output_stream = new StreamOutputStream ((void*) fd, request.out, request.err);
#else
_input_stream = new StreamInputStream (request.in);
_output_stream = new StreamOutputStream (request.out, request.err);
#endif

return true;
}
Expand Down
15 changes: 14 additions & 1 deletion src/vsgi/vsgi-application.vala
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ public class VSGI.Application : GLib.Application {
{"any", 'A', 0, OptionArg.NONE, null, "Listen on any address instead of only from the loopback interface"},
{"ipv4-only", '4', 0, OptionArg.NONE, null, "Listen only to IPv4 interfaces"},
{"ipv6-only", '6', 0, OptionArg.NONE, null, "Listen only to IPv6 interfaces"},
#if GIO_UNIX
// socket
{"socket", 's', 0, OptionArg.FILENAME_ARRAY, null, "Listen on each UNIX socket paths", "[]"},
#endif
// file descriptor
{"file-descriptor", 'f', 0, OptionArg.STRING_ARRAY, null, "Listen on each file descriptors", "[]"},
{null}
Expand Down Expand Up @@ -91,7 +93,9 @@ public class VSGI.Application : GLib.Application {
var any = options.lookup_value ("any", VariantType.BOOLEAN);
var ipv4_only = options.lookup_value ("ipv4-only", VariantType.BOOLEAN);
var ipv6_only = options.lookup_value ("ipv6-only", VariantType.BOOLEAN);
#if GIO_UNIX
var sockets = options.lookup_value ("socket", VariantType.BYTESTRING_ARRAY);
#endif
var fds = options.lookup_value ("file-descriptor", VariantType.STRING_ARRAY);

if (addresses != null) {
Expand Down Expand Up @@ -144,12 +148,14 @@ public class VSGI.Application : GLib.Application {
}
}

#if GIO_UNIX
// socket path
if (sockets != null) {
foreach (var socket in sockets.get_bytestring_array ()) {
server.listen (new UnixSocketAddress (socket));
}
}
#endif

// file descriptor
if (fds != null) {
Expand All @@ -164,7 +170,12 @@ public class VSGI.Application : GLib.Application {
}

// default listening interface
if (addresses == null && ports == null && sockets == null && fds == null) {
if (addresses == null &&
ports == null &&
#if GIO_UNIX
sockets == null &&
#endif
fds == null) {
server.listen ();
}

Expand Down Expand Up @@ -205,12 +216,14 @@ public class VSGI.Application : GLib.Application {
// keep the process (and workers) alive
hold ();

#if GIO_UNIX
// release on 'SIGTERM'
Unix.signal_add (ProcessSignal.TERM, () => {
release ();
server.stop ();
return false;
}, Priority.LOW);
#endif

return 0;
}
Expand Down
4 changes: 4 additions & 0 deletions src/vsgi/vsgi-server.vala
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,15 @@ namespace VSGI {
*/
[Version (since = "0.3", experimental = true)]
public virtual Pid fork () throws Error {
#if HAVE_FORK
var pid = Posix.fork ();
if (pid == -1) {
throw new SpawnError.FORK (strerror (errno));
}
return pid;
#else
return 0;
#endif
}

/**
Expand Down
Loading