Skip to content

Commit

Permalink
Provide minimal support for Windows (fix #146)
Browse files Browse the repository at this point in the history
Make both platform-dependant 'gio-unix-2.0' and 'gio-windows-2.0'
dependencies optional and use features accordingly via 'GIO_UNIX' and
'GIO_WINDOWS' definitions.

Use 'add_project_arguments' instead of 'vala_defines'

Disable '--socket' option if 'gio-unix-2.0' is not available.

For FastCGI, use 'GLib.Win32InputStream' and 'GLib.Win32OutputStream'
and gracefully fallback with basic I/O wrapper.

Add basic cross files to target 32 and 64 bit targets with MinGW.
  • Loading branch information
arteymix committed Mar 20, 2017
1 parent 5563d1f commit 65faeb7
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 56 deletions.
11 changes: 11 additions & 0 deletions cross/i686-w64-mingw32.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[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'

[host_machine]
system = 'windows'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'
11 changes: 11 additions & 0 deletions cross/x86_64-w64-mingw32.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[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'

[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
23 changes: 18 additions & 5 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,33 @@ 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').has_function('fork')
add_project_arguments('--define=HAVE_FORK', language: 'vala')
endif

if meson.get_compiler('c').has_function('memmem')
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))
21 changes: 14 additions & 7 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 All @@ -100,12 +114,5 @@ namespace VSGI.CGI {
public override void stop () {
// CGI handle a single connection
}

/**
* Forking does not make sense for CGI.
*/
public override Pid fork () {
return 0;
}
}
}
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
40 changes: 14 additions & 26 deletions 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 All @@ -173,44 +184,21 @@ public class VSGI.Application : GLib.Application {
return 1;
}

if (options.lookup_value ("forks", VariantType.INT32) != null) {
var forks = options.lookup_value ("forks", VariantType.INT32).get_int32 ();
try {
for (var i = 0; i < forks; i++) {
var pid = server.fork ();

// worker
if (pid == 0) {
break;
}

// parent
else {
// monitor child process
ChildWatch.add (pid, (pid, status) => {
warning ("Worker %d exited with status '%d'.", pid, status);
});
}
}
} catch (Error err) {
critical ("%s (%s, %d)", err.message, err.domain.to_string (), err.code);
return 1;
}
}

foreach (var uri in server.uris) {
message ("Listening on '%s'.", uri.to_string (false));
}

// 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
Loading

0 comments on commit 65faeb7

Please sign in to comment.