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.

For FastCGI, gracefully fallback with no fd-based async I/O.

Add basic cross files to target 32 and 64 bit targets.
  • Loading branch information
arteymix committed Oct 27, 2016
1 parent b4edfb9 commit 141d2bb
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 10 deletions.
10 changes: 10 additions & 0 deletions cross/i686-w64-mingw32.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[binaries]
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'
10 changes: 10 additions & 0 deletions cross/x86_64-w64-mingw32.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[binaries]
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'
cpu = 'x86_64'
endian = 'little'
15 changes: 14 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,30 @@ endif
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 = []

if meson.get_compiler('c').has_function('fork')
vala_defines += '--define=HAVE_FORK'
endif

# provide 'OutputStream.write_all_async'
if gio.version().version_compare('>=2.44')
vala_defines += '--define=GIO_2_44'
endif

if gio_unix.found()
vala_defines += '--define=GIO_UNIX'
endif

if gio_windows.found()
vala_defines += '--define=GIO_WINDOWS'
endif

# new 'Soup.Server' API
if soup.version().version_compare('>=2.48')
vala_defines += '--define=SOUP_2_48'
Expand Down
14 changes: 12 additions & 2 deletions src/vsgi/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ 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],
dependencies: [glib, gobject, gio, gio_unix, gio_windows, gmodule, soup],
vala_args: ['--pkg=posix'] + vala_defines,
link_args: '-Wl,-rpath,$$ORIGIN/servers',
install: true,
Expand All @@ -33,9 +33,19 @@ install_headers(meson.current_build_dir() + '/vsgi-@[email protected]'.format(api_version), s
install_data(meson.current_build_dir() + '/vsgi-@[email protected]'.format(api_version), install_dir: 'share/vala/vapi')
install_data('vsgi-@[email protected]'.format(api_version), install_dir: 'share/vala/vapi')

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
4 changes: 2 additions & 2 deletions src/vsgi/servers/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ shared_library('vsgi-http', ['vsgi-http.vala'],
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],
dependencies: [glib, gobject, gio, gio_unix, gio_windows, soup, vsgi],
vala_args: vala_defines,
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()
shared_library('vsgi-fastcgi', 'vsgi-fastcgi.vala',
dependencies: [glib, gobject, gio, gio_unix, soup, vsgi, fcgi],
dependencies: [glib, gobject, gio, gio_unix, gio_windows, soup, vsgi, fcgi],
vala_args: ['--pkg=fcgi', '--vapidir=' + meson.current_source_dir()] + vala_defines,
install: true,
install_dir: '@0@/vsgi-@1@/servers'.format(get_option('libdir'), api_version))
Expand Down
9 changes: 9 additions & 0 deletions src/vsgi/servers/vsgi-cgi.vala
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,18 @@ namespace VSGI.CGI {
}

Idle.add (() => {
#if GIO_UNIX
var connection = new Connection (this,
new UnixInputStream (stdin.fileno (), true),
new UnixOutputStream (stdout.fileno (), true));
#elif GIO_WINDOWS
// TODO: obtain I/O handles
var connection = new Connection (this,
new Win32InputStream (null, true),
new Win32OutputStream (null, true));
#else
// TODO: find an alternative
#endif

var req = new Request (connection, Environ.@get ());
var res = new Response (req);
Expand Down
43 changes: 39 additions & 4 deletions src/vsgi/servers/vsgi-fastcgi.vala
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,25 @@ namespace VSGI.FastCGI {
return "Unknown error code '%d'".printf (error);
}

private class StreamInputStream : UnixInputStream {
private class StreamInputStream :
#if GIO_UNIX
UnixInputStream
#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);
}
#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 @@ -84,15 +96,27 @@ namespace VSGI.FastCGI {
}
}

private class StreamOutputStream : UnixOutputStream {
private class StreamOutputStream :
#if GIO_UNIX
UnixOutputStream
#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);
}
#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 @@ -191,7 +215,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 @@ -201,7 +228,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 @@ -311,8 +341,13 @@ namespace VSGI.FastCGI {

yield;

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

return true;
}
Expand Down
8 changes: 8 additions & 0 deletions src/vsgi/vsgi-application.vala
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ public class VSGI.Application : GLib.Application {
// socket path
if (sockets != null) {
foreach (var socket in sockets.get_bytestring_array ()) {
#if GIO_UNIX
server.listen (new UnixSocketAddress (socket));
#elif GIO_WINDOWS
// TODO: find an alternative
#endif
}
}

Expand Down Expand Up @@ -205,12 +209,16 @@ 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);
#elif GIO_WINDOWS
// TODO: find an alternative
#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 @@ -140,11 +140,15 @@ namespace VSGI {
*/
[Version (since = "0.3")]
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
6 changes: 5 additions & 1 deletion src/vsgi/vsgi-socket-server.vala
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ public abstract class VSGI.SocketServer : Server {
effective_inet_address.get_address ().to_string (),
effective_inet_address.get_port ())));
}
} else if (effective_address is UnixSocketAddress) {
}

#if GIO_UNIX
else if (effective_address is UnixSocketAddress) {
var effective_unix_address = effective_address as UnixSocketAddress;
_uris.append (new Soup.URI ("%s+unix://%s/".printf (scheme, effective_unix_address.get_path ())));
}
#endif
}
}

Expand Down
8 changes: 8 additions & 0 deletions tests/socket-server-test.vala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public int main (string[] args) {
});

Test.add_func ("/socket_server/listen/unix_socket", () => {
#if GIO_UNIX
var server = new MockedSocketServer ();

try {
Expand All @@ -70,9 +71,13 @@ public int main (string[] args) {
}

assert ("mock+unix://some-socket.sock/" == server.uris.data.to_string (false));
#else
Test.skip ("This test require 'gio-unix-2.0' installed.");
#endif
});

Test.add_func ("/socket_server/listen_socket", () => {
#if GIO_UNIX
var server = new MockedSocketServer ();

try {
Expand All @@ -84,6 +89,9 @@ public int main (string[] args) {
} finally {
FileUtils.unlink ("some-socket.sock");
}
#else
Test.skip ("This test require 'gio-unix-2.0' installed.");
#endif
});

return Test.run ();
Expand Down

0 comments on commit 141d2bb

Please sign in to comment.