diff --git a/cross/i686-w64-mingw32.txt b/cross/i686-w64-mingw32.txt new file mode 100644 index 000000000..4aa9bcdb1 --- /dev/null +++ b/cross/i686-w64-mingw32.txt @@ -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' diff --git a/cross/x86_64-w64-mingw32.txt b/cross/x86_64-w64-mingw32.txt new file mode 100644 index 000000000..5f7444dae --- /dev/null +++ b/cross/x86_64-w64-mingw32.txt @@ -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' diff --git a/meson.build b/meson.build index ce21ab558..9699b0bde 100644 --- a/meson.build +++ b/meson.build @@ -22,7 +22,8 @@ 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') @@ -33,6 +34,14 @@ 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' diff --git a/src/vsgi/meson.build b/src/vsgi/meson.build index 2ce4df252..5beb64c79 100644 --- a/src/vsgi/meson.build +++ b/src/vsgi/meson.build @@ -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, @@ -33,9 +33,19 @@ install_headers(meson.current_build_dir() + '/vsgi-@0@.h'.format(api_version), s install_data(meson.current_build_dir() + '/vsgi-@0@.vapi'.format(api_version), install_dir: 'share/vala/vapi') install_data('vsgi-@0@.deps'.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', diff --git a/src/vsgi/servers/meson.build b/src/vsgi/servers/meson.build index ba1a38762..f4eaafd13 100644 --- a/src/vsgi/servers/meson.build +++ b/src/vsgi/servers/meson.build @@ -5,7 +5,7 @@ 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)) @@ -13,7 +13,7 @@ shared_library('vsgi-cgi', 'vsgi-cgi.vala', 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)) diff --git a/src/vsgi/servers/vsgi-cgi.vala b/src/vsgi/servers/vsgi-cgi.vala index 5f2f65010..5d5a86aaa 100644 --- a/src/vsgi/servers/vsgi-cgi.vala +++ b/src/vsgi/servers/vsgi-cgi.vala @@ -39,8 +39,18 @@ namespace VSGI.CGI { public override OutputStream output_stream { get { return this._output_stream; } } - public Connection (Server server, InputStream input_stream, OutputStream output_stream) { + public Connection (Server server) { Object (server: server); +#if GIO_UNIX + _input_stream = new UnixInputStream (stdin.fileno (), true); + _output_stream = new UnixOutputStream (stdout.fileno (), true); +#elif GIO_WINDOWS + _input_stream = new Win32InputStream (stdin, true); + _output_stream = new Win32OutputStream (stdout, true); +#else + // TODO: find an alternative +#endif + this._input_stream = input_stream; this._output_stream = output_stream; } @@ -70,11 +80,7 @@ namespace VSGI.CGI { } Idle.add (() => { - var connection = new Connection (this, - new UnixInputStream (stdin.fileno (), true), - new UnixOutputStream (stdout.fileno (), true)); - - var req = new Request (connection, Environ.@get ()); + var req = new Request (new Connection (this), Environ.@get ()); var res = new Response (req); // handle a single request and quit @@ -103,12 +109,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; - } } } diff --git a/src/vsgi/servers/vsgi-fastcgi.vala b/src/vsgi/servers/vsgi-fastcgi.vala index 425d9b7b3..93639c01b 100644 --- a/src/vsgi/servers/vsgi-fastcgi.vala +++ b/src/vsgi/servers/vsgi-fastcgi.vala @@ -55,13 +55,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); @@ -84,15 +102,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); @@ -191,7 +227,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); @@ -201,7 +240,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) { @@ -311,8 +353,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; } diff --git a/src/vsgi/vsgi-application.vala b/src/vsgi/vsgi-application.vala index 41ae1d4d1..1999fe28d 100644 --- a/src/vsgi/vsgi-application.vala +++ b/src/vsgi/vsgi-application.vala @@ -40,8 +40,6 @@ public class VSGI.Application : GLib.Application { ApplicationFlags.SEND_ENVIRONMENT | ApplicationFlags.NON_UNIQUE; const OptionEntry[] entries = { - // general options - {"forks", 0, 0, OptionArg.INT, null, "Number of forks to create", "0"}, // address {"address", 'a', 0, OptionArg.STRING_ARRAY, null, "Listen on each addresses", "[]"}, // port @@ -49,8 +47,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} @@ -91,7 +91,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) { @@ -144,12 +146,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) { @@ -164,7 +168,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 (); } @@ -173,31 +182,6 @@ 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)[0:-uri.path.length]); } @@ -205,12 +189,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; } diff --git a/src/vsgi/vsgi-server.vala b/src/vsgi/vsgi-server.vala index 161d79c5f..f0bf4376e 100644 --- a/src/vsgi/vsgi-server.vala +++ b/src/vsgi/vsgi-server.vala @@ -123,30 +123,6 @@ namespace VSGI { [Version (since = "0.3")] public abstract void stop (); - /** - * Fork the execution. - * - * This is typically called after {@link VSGI.Server.listen} such that - * workers can share listening interfaces and descriptors. - * - * The default implementation wraps {@link Posix.fork} and check its - * return value. To disable forking, simply override this and return - * '0'. - * - * @throws GLib.SpawnError.FORK if the {@link Posix.fork} call fails - * - * @return the process pid if this is the parent process, - * otherwise '0' - */ - [Version (since = "0.3")] - public virtual Pid fork () throws Error { - var pid = Posix.fork (); - if (pid == -1) { - throw new SpawnError.FORK (strerror (errno)); - } - return pid; - } - /** * Dispatch the request to the application callback. * diff --git a/src/vsgi/vsgi-socket-server.vala b/src/vsgi/vsgi-socket-server.vala index bb5d983ee..2d2e77fe3 100644 --- a/src/vsgi/vsgi-socket-server.vala +++ b/src/vsgi/vsgi-socket-server.vala @@ -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 } } diff --git a/tests/server-test.vala b/tests/server-test.vala index 142da57fa..d43eb7d67 100644 --- a/tests/server-test.vala +++ b/tests/server-test.vala @@ -36,15 +36,5 @@ public int main (string[] args) { assert ("VSGIMockServer" == server.get_type ().name ()); }); - Test.add_func ("/server/fork", () => { - var server = Server.@new ("mock"); - Pid pid; - try { - pid = server.fork (); - } catch (Error err) { - assert_not_reached (); - } - }); - return Test.run (); } diff --git a/tests/socket-server-test.vala b/tests/socket-server-test.vala index e52c862f3..5dc7f9624 100644 --- a/tests/socket-server-test.vala +++ b/tests/socket-server-test.vala @@ -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 { @@ -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 { @@ -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 ();