From 1c198e88d1a0c74676f8d6fade99b2531ba815b8 Mon Sep 17 00:00:00 2001 From: David Wragg Date: Sun, 30 May 2010 23:31:40 +0100 Subject: A Windows port, using MinGW/MSYS --- README.windows | 77 ++++++++++++++++ configure.ac | 27 +++++- etc/install-mingw.sh | 69 ++++++++++++++ librabbitmq/Makefile.am | 8 +- librabbitmq/amqp_api.c | 6 +- librabbitmq/amqp_connection.c | 20 ++--- librabbitmq/amqp_mem.c | 1 - librabbitmq/amqp_private.h | 5 +- librabbitmq/amqp_socket.c | 36 ++++---- librabbitmq/amqp_table.c | 2 +- librabbitmq/codegen.py | 1 + librabbitmq/unix/socket.c | 85 ++++++++++++++++++ librabbitmq/unix/socket.h | 80 +++++++++++++++++ librabbitmq/windows/socket.c | 88 ++++++++++++++++++ librabbitmq/windows/socket.h | 92 +++++++++++++++++++ tests/Makefile.am | 2 +- tools/Makefile.am | 16 ++-- tools/common.c | 59 +----------- tools/common.h | 8 -- tools/consume.c | 1 + tools/unix/process.c | 100 +++++++++++++++++++++ tools/unix/process.h | 57 ++++++++++++ tools/windows/compat.c | 73 +++++++++++++++ tools/windows/compat.h | 51 +++++++++++ tools/windows/process.c | 204 ++++++++++++++++++++++++++++++++++++++++++ tools/windows/process.h | 59 ++++++++++++ 26 files changed, 1113 insertions(+), 114 deletions(-) create mode 100644 README.windows create mode 100755 etc/install-mingw.sh create mode 100644 librabbitmq/unix/socket.c create mode 100644 librabbitmq/unix/socket.h create mode 100644 librabbitmq/windows/socket.c create mode 100644 librabbitmq/windows/socket.h create mode 100644 tools/unix/process.c create mode 100644 tools/unix/process.h create mode 100644 tools/windows/compat.c create mode 100644 tools/windows/compat.h create mode 100644 tools/windows/process.c create mode 100644 tools/windows/process.h diff --git a/README.windows b/README.windows new file mode 100644 index 0000000..1a20c00 --- /dev/null +++ b/README.windows @@ -0,0 +1,77 @@ +# rabbitmq-c and Windows + +rabbitmq-c can now be built on Windows using the MinGW/MSYS ports of +the GNU toolchain and miscellaneous utilities. This includes the +example programs and tools. + +The results are native Windows DLLs and EXEs, and can be used without +having MinGW installed. But the librabbitmq header files currently +use GCC extensions, and for this reason it is still not possible to +use Microsoft's C/C++ to build applications against the librabbitmq +DLL. Hopefully this will get fixed before long. + + +# Building rabbitmq-c + +rabbitmq-c is built on Windows using MinGW and MSYS. In brief, MinGW +is a native port of the GNU toolchain to Windows; MSYS is a set of +ports of common GNU utilities to run under Windows, so that typical +autotools-based builds will work there. MinGW/MSYS can be used to +build native Windows applications and DLLs, which do not depend on +MinGW/MSYS to run. + +So to build rabbitmq-c on Windows, you need to download and install +the relevant parts of MinGW/MSYS. This can be a fairly time consuming +process - there are about 20 files to be downloaded and unpacked. To +make it easier, we provide a bash script that automates this process, +in rabbitmq-c/etc/install-mingw.sh. You can run this cygwin, or under +Linux and copy the results over or put them on a shared drive. Some +MinGW packages are .tar.lzma files, so it requires a system with xz +and a tar that supports the -J option, which probably rules out OSX. + +Run install-mingw.sh specifying the destination directory, e.g. + + $ etc/install-mingw.sh /tmp/mingw + +Python is needed for the rabbitmq-c build, so you will also need to +install python under Windows. The Windows installer from python.org +will do fine. + +You will need to get the rabbitmq-c and rabbitmq-codegen source code. +If you are getting it from Mercurial, you will need to run "autoreconf +-i" within rabbitmq-c somewhere other than under MinGW first (perhaps +this can be done under MinGW/MSYS, but the packages installed by +install-mingw.sh are not sufficient). + +Open a cmd window, and ensure that both the MinGW bin directory and the python install directory are in the path, e.g. + + C:\>set PATH=%PATH%;C:\mingw\bin;C:\Python26 + +Then start bash, and run the following mount command (substituting the +Windows path of your MinGW install): + + C:\>bash + bash-3.1$ mount 'C:\mingw' /mingw + +Then go to the rabbitmq-c directory, and configure and make as normal: + + bash-3.1$ ./configure && make + [...] + + +# Running the tools without mingw + +You can run the resulting tools EXEs without the rest of MinGW. To do +this, copy the following files into a directory: + +- rabbitmq-c/tools/.libs/*.exe + +- rabbitmq-c/librabbitmq/.libs/librabbitmq-0.dll + +- /lib/libpopt-0.dll + +- /lib/libiconv-2.dll + +- /lib/libintl-8.dll + + diff --git a/configure.ac b/configure.ac index 13d1b4b..f7cfb74 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ AC_GNU_SOURCE AC_PROG_CC dnl Library checks +AC_LIBTOOL_WIN32_DLL AM_PROG_LIBTOOL dnl Header-file checks @@ -21,6 +22,26 @@ if test "x$GCC" = "xyes"; then fi fi +dnl Detect the kind of host we're building for +AC_CANONICAL_HOST +windows=no +case "${host}" in +*-*-mingw*) + windows=yes + ;; +esac +AM_CONDITIONAL(WINDOWS, test "x$windows" = xyes) +AS_IF([test "x$windows" = xyes], + [AC_DEFINE([WINDOWS], [1], [Define to 1 if on Windows.])] +) + +dnl Decide which API abstraction layer to use +PLATFORM_DIR=unix +if test "x$windows" = xyes ; then + PLATFORM_DIR=windows +fi +AC_SUBST(PLATFORM_DIR) + dnl Enable -m64 if we were asked to do so AC_ARG_ENABLE(64-bit, [ --enable-64-bit produce 64-bit library], @@ -65,8 +86,12 @@ AC_SUBST(AMQP_CODEGEN_DIR) AC_SUBST(AMQP_SPEC_JSON_PATH) AC_SUBST(PYTHON) -# Check for libpopt, which we need to build the tools +dnl Decide which extra win32 libs we need +EXTRA_LIBS= +AS_IF([test "x$windows" = xyes], [EXTRA_LIBS="-lws2_32 $EXTRA_LIBS"]) +AC_SUBST(EXTRA_LIBS) +dnl Check for libpopt, which we need to build the tools AC_ARG_WITH([popt], [AS_HELP_STRING([--with-popt], [use the popt library. Needed for tools.])], [], diff --git a/etc/install-mingw.sh b/etc/install-mingw.sh new file mode 100755 index 0000000..de953d4 --- /dev/null +++ b/etc/install-mingw.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +if [ $# -ne 1 ] ; then + echo "usage: install-mingw.sh " 1>&2 + exit 1 +fi + +unpack_dir=$1 + +if [ -eb "$unpack_dir" ] ; then + echo "Destination directory already exists; please delete it if you are sure" 1>&2 + exit 1 +fi + +set -e + +download_dir=/tmp/install-mingw.$$ +mkdir -p $download_dir $unpack_dir + +while read f ; do + wget -P $download_dir -N http://switch.dl.sourceforge.net/project/mingw/$f +done <&2 + exit 1 + ;; + esac +done + +rm -rf $download_dir diff --git a/librabbitmq/Makefile.am b/librabbitmq/Makefile.am index b4c8843..9211c8f 100644 --- a/librabbitmq/Makefile.am +++ b/librabbitmq/Makefile.am @@ -1,15 +1,19 @@ lib_LTLIBRARIES = librabbitmq.la -librabbitmq_la_SOURCES = amqp_mem.c amqp_table.c amqp_connection.c amqp_socket.c amqp_debug.c amqp_api.c +AM_CFLAGS = -I$(PLATFORM_DIR) +librabbitmq_la_SOURCES = amqp_mem.c amqp_table.c amqp_connection.c amqp_socket.c amqp_debug.c amqp_api.c $(PLATFORM_DIR)/socket.c +librabbitmq_la_LDFLAGS = -no-undefined nodist_librabbitmq_la_SOURCES = amqp_framing.c include_HEADERS = amqp_framing.h amqp.h -noinst_HEADERS = amqp_private.h +noinst_HEADERS = amqp_private.h $(PLATFORM_DIR)/socket.h BUILT_SOURCES = amqp_framing.h amqp_framing.c CLEANFILES = amqp_framing.h amqp_framing.c EXTRA_DIST = codegen.py CODEGEN_PY=$(srcdir)/codegen.py +LDADD=$(EXTRA_LIBS) + amqp_framing.h: $(AMQP_SPEC_JSON_PATH) $(CODEGEN_PY) PYTHONPATH=$(AMQP_CODEGEN_DIR) $(PYTHON) $(CODEGEN_PY) header $< $@ diff --git a/librabbitmq/amqp_api.c b/librabbitmq/amqp_api.c index 3a4440f..9918819 100644 --- a/librabbitmq/amqp_api.c +++ b/librabbitmq/amqp_api.c @@ -52,7 +52,6 @@ #include #include #include -#include #include "amqp.h" #include "amqp_framing.h" @@ -85,9 +84,8 @@ const char *amqp_error_string(int err) break; case ERROR_CATEGORY_OS: - str = strerror(err); - break; - + return amqp_os_error_string(err); + default: str = "(undefined error category)"; } diff --git a/librabbitmq/amqp_connection.c b/librabbitmq/amqp_connection.c index a264ad3..63af96a 100644 --- a/librabbitmq/amqp_connection.c +++ b/librabbitmq/amqp_connection.c @@ -52,17 +52,13 @@ #include #include #include -#include - -#include -#include -#include +#include #include "amqp.h" #include "amqp_framing.h" #include "amqp_private.h" -#include +#include "socket.h" #define INITIAL_FRAME_POOL_PAGE_SIZE 65536 #define INITIAL_DECODING_POOL_PAGE_SIZE 131072 @@ -173,8 +169,8 @@ void amqp_destroy_connection(amqp_connection_state_t state) { int amqp_end_connection(amqp_connection_state_t state) { int s = state->sockfd; amqp_destroy_connection(state); - if (close(s) < 0) - return -encoded_errno(); + if (socket_close(s) < 0) + return -encoded_socket_errno(); else return 0; } @@ -433,8 +429,8 @@ int amqp_send_frame(amqp_connection_state_t state, res = inner_send_frame(state, frame, &encoded, &payload_len); switch (res) { case 0: - res = write(state->sockfd, state->outbound_buffer.bytes, - payload_len + (HEADER_SIZE + FOOTER_SIZE)); + res = socket_write(state->sockfd, state->outbound_buffer.bytes, + payload_len + (HEADER_SIZE + FOOTER_SIZE)); break; case 1: { @@ -447,7 +443,7 @@ int amqp_send_frame(amqp_connection_state_t state, iov[2].iov_base = &frame_end_byte; assert(FOOTER_SIZE == 1); iov[2].iov_len = FOOTER_SIZE; - res = writev(state->sockfd, &iov[0], 3); + res = socket_writev(state->sockfd, &iov[0], 3); break; } @@ -456,7 +452,7 @@ int amqp_send_frame(amqp_connection_state_t state, } if (res < 0) - return -encoded_errno(); + return -encoded_socket_errno(); else return 0; } diff --git a/librabbitmq/amqp_mem.c b/librabbitmq/amqp_mem.c index 7783cbb..021151a 100644 --- a/librabbitmq/amqp_mem.c +++ b/librabbitmq/amqp_mem.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include "amqp.h" diff --git a/librabbitmq/amqp_private.h b/librabbitmq/amqp_private.h index f922933..7206ae5 100644 --- a/librabbitmq/amqp_private.h +++ b/librabbitmq/amqp_private.h @@ -55,8 +55,6 @@ extern "C" { #endif -#include /* ntohl, htonl, ntohs, htons */ - /* Error numbering: Because of differences in error numbering on * different platforms, we want to keep error numbers opaque for * client code. Internally, we encode the category of an error @@ -78,8 +76,7 @@ extern "C" { #define ERROR_CONNECTION_CLOSED 7 #define ERROR_MAX 7 -/* Get the encoded form of errno */ -#define encoded_errno() (errno | ERROR_CATEGORY_OS) +extern const char *amqp_os_error_string(int err); /* * Connection states: diff --git a/librabbitmq/amqp_socket.c b/librabbitmq/amqp_socket.c index 8f3f05b..6425c34 100644 --- a/librabbitmq/amqp_socket.c +++ b/librabbitmq/amqp_socket.c @@ -52,29 +52,27 @@ #include #include #include -#include #include +#include #include "amqp.h" #include "amqp_framing.h" #include "amqp_private.h" -#include -#include -#include -#include -#include -#include +#include "socket.h" -#include int amqp_open_socket(char const *hostname, int portnumber) { - int sockfd; + int sockfd, res; struct sockaddr_in addr; struct hostent *he; + res = socket_init(); + if (res) + return res; + he = gethostbyname(hostname); if (he == NULL) return -ERROR_HOST_NOT_FOUND; @@ -83,11 +81,11 @@ int amqp_open_socket(char const *hostname, addr.sin_port = htons(portnumber); addr.sin_addr.s_addr = * (uint32_t *) he->h_addr_list[0]; - sockfd = socket(PF_INET, SOCK_STREAM, 0); - if (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - int result = -encoded_errno(); - close(sockfd); - return result; + sockfd = socket_socket(PF_INET, SOCK_STREAM, 0); + if (socket_connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + res = -encoded_socket_errno(); + socket_close(sockfd); + return res; } return sockfd; @@ -107,7 +105,7 @@ static char *header() { } int amqp_send_header(amqp_connection_state_t state) { - return write(state->sockfd, header(), 8); + return socket_write(state->sockfd, header(), 8); } int amqp_send_header_to(amqp_connection_state_t state, @@ -190,14 +188,14 @@ static int wait_frame_inner(amqp_connection_state_t state, assert(result != 0); } - result = read(state->sockfd, - state->sock_inbound_buffer.bytes, - state->sock_inbound_buffer.len); + result = socket_read(state->sockfd, + state->sock_inbound_buffer.bytes, + state->sock_inbound_buffer.len); if (result <= 0) { if (result == 0) return -ERROR_CONNECTION_CLOSED; else - return -encoded_errno(); + return -encoded_socket_errno(); } state->sock_inbound_limit = result; diff --git a/librabbitmq/amqp_table.c b/librabbitmq/amqp_table.c index db45588..3f5eb61 100644 --- a/librabbitmq/amqp_table.c +++ b/librabbitmq/amqp_table.c @@ -52,10 +52,10 @@ #include #include #include -#include #include "amqp.h" #include "amqp_private.h" +#include "socket.h" #include diff --git a/librabbitmq/codegen.py b/librabbitmq/codegen.py index 9a82fbe..6b38666 100644 --- a/librabbitmq/codegen.py +++ b/librabbitmq/codegen.py @@ -265,6 +265,7 @@ def genErl(spec): print '#include "amqp.h"' print '#include "amqp_framing.h"' print '#include "amqp_private.h"' + print '#include "socket.h"' print """ char const *amqp_constant_name(int constantNumber) { diff --git a/librabbitmq/unix/socket.c b/librabbitmq/unix/socket.c new file mode 100644 index 0000000..51db413 --- /dev/null +++ b/librabbitmq/unix/socket.c @@ -0,0 +1,85 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include + +#include "amqp.h" +#include "amqp_private.h" +#include "socket.h" + +int socket_socket(int domain, int type, int proto) +{ + int flags; + + int s = socket(domain, type, proto); + if (s < 0) + return s; + + /* Always enable CLOEXEC on the socket */ + flags = fcntl(s, F_GETFD); + if (flags == -1 + || fcntl(s, F_SETFD, (long)(flags | FD_CLOEXEC)) == -1) { + int e = errno; + close(s); + errno = e; + return -1; + } + + return s; +} + +const char *amqp_os_error_string(int err) +{ + return strdup(strerror(err)); +} diff --git a/librabbitmq/unix/socket.h b/librabbitmq/unix/socket.h new file mode 100644 index 0000000..d7295c3 --- /dev/null +++ b/librabbitmq/unix/socket.h @@ -0,0 +1,80 @@ +#ifndef librabbitmq_unix_socket_h +#define librabbitmq_unix_socket_h + +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include +#include +#include + +static inline int socket_init(void) +{ + return 0; +} + +extern int socket_socket(int domain, int type, int proto); + +#define socket_connect connect +#define socket_close close +#define socket_read read +#define socket_write write +#define socket_writev writev + +static inline int encoded_socket_errno() +{ + return errno | ERROR_CATEGORY_OS; +} + +#endif diff --git a/librabbitmq/windows/socket.c b/librabbitmq/windows/socket.c new file mode 100644 index 0000000..f809f62 --- /dev/null +++ b/librabbitmq/windows/socket.c @@ -0,0 +1,88 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include + +#include "amqp.h" +#include "amqp_private.h" +#include "socket.h" + +static int called_wsastartup; + +int socket_init(void) +{ + if (!called_wsastartup) { + WSADATA data; + int res = WSAStartup(0x0202, &data); + if (res) + return -res; + + called_wsastartup = 1; + } + + return 0; +} + +const char *amqp_os_error_string(int err) +{ + char *msg, *copy; + + if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&msg, 0, NULL)) + return strdup("(error retrieving Windows error message)"); + + copy = strdup(msg); + LocalFree(msg); + return copy; +} diff --git a/librabbitmq/windows/socket.h b/librabbitmq/windows/socket.h new file mode 100644 index 0000000..bff6efc --- /dev/null +++ b/librabbitmq/windows/socket.h @@ -0,0 +1,92 @@ +#ifndef librabbitmq_windows_socket_h +#define librabbitmq_windows_socket_h + +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include + +extern int socket_init(void); + +#define socket_socket socket +#define socket_connect connect +#define socket_close closesocket + +static inline int socket_read(int sock, void *buf, size_t count) +{ + return recv(sock, buf, count, 0); +} + +static inline int socket_write(int sock, void *buf, size_t count) +{ + return send(sock, buf, count, 0); +} + +/* same as WSABUF */ +struct iovec { + u_long iov_len; + char *iov_base; +}; + +static inline int socket_writev(int sock, struct iovec *iov, int nvecs) +{ + DWORD ret; + if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) + return ret; + else + return -1; +} + +static inline int encoded_socket_errno() +{ + return WSAGetLastError() | ERROR_CATEGORY_OS; +} + +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 1ac6faf..7c8a4fe 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ noinst_PROGRAMS = test_tables -AM_CFLAGS = -I$(top_srcdir)/librabbitmq +AM_CFLAGS = -I$(top_srcdir)/librabbitmq -I$(top_srcdir)/librabbitmq/$(PLATFORM_DIR) AM_LDFLAGS = $(top_builddir)/librabbitmq/librabbitmq.la diff --git a/tools/Makefile.am b/tools/Makefile.am index 307fbd2..3f9fd6a 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,15 +1,21 @@ bin_PROGRAMS = amqp-publish amqp-get amqp-consume -AM_CFLAGS = -I$(top_srcdir)/librabbitmq +AM_CFLAGS = -I$(top_srcdir)/librabbitmq -I$(PLATFORM_DIR) AM_LDFLAGS = $(top_builddir)/librabbitmq/librabbitmq.la LDADD=$(LIBPOPT) -noinst_HEADERS = common.h +noinst_HEADERS = common.h $(PLATFORM_DIR)/process.h -amqp_publish_SOURCES = publish.c common.c -amqp_get_SOURCES = get.c common.c -amqp_consume_SOURCES = consume.c common.c +COMMON_SOURCES = common.c + +if WINDOWS +COMMON_SOURCES += windows/compat.c +endif + +amqp_publish_SOURCES = publish.c $(COMMON_SOURCES) +amqp_get_SOURCES = get.c $(COMMON_SOURCES) +amqp_consume_SOURCES = consume.c $(PLATFORM_DIR)/process.c $(COMMON_SOURCES) if TOOLS_DOC man_MANS = doc/amqp-publish.1 doc/amqp-consume.1 doc/amqp-get.1 doc/librabbitmq-tools.7 diff --git a/tools/common.c b/tools/common.c index ec24085..39099c1 100644 --- a/tools/common.c +++ b/tools/common.c @@ -58,12 +58,12 @@ #include #include #include -#include -#include #include "common.h" -extern char **environ; +#ifdef WINDOWS +#include "compat.h" +#endif void die(const char *fmt, ...) { @@ -169,16 +169,6 @@ void die_rpc(amqp_rpc_reply_t r, const char *fmt, ...) exit(1); } -void set_cloexec(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFD); - if (flags == -1 - || fcntl(fd, F_SETFD, (long)(flags | FD_CLOEXEC)) == -1) - die_errno(errno, "set_cloexec"); -} - static char *amqp_server = "localhost"; static char *amqp_vhost = "/"; static char *amqp_username = "guest"; @@ -224,8 +214,6 @@ amqp_connection_state_t make_connection(void) s = amqp_open_socket(host, port ? port : 5672); die_amqp_error(-s, "opening socket to %s", amqp_server); - set_cloexec(s); - conn = amqp_new_connection(); amqp_set_sockfd(conn, s); @@ -318,47 +306,6 @@ void copy_body(amqp_connection_state_t conn, int fd) } } -void pipeline(const char * const *argv, struct pipeline *pl) -{ - posix_spawn_file_actions_t file_acts; - - int pipefds[2]; - if (pipe(pipefds)) - die_errno(errno, "pipe"); - - die_errno(posix_spawn_file_actions_init(&file_acts), - "posix_spawn_file_actions_init"); - die_errno(posix_spawn_file_actions_adddup2(&file_acts, pipefds[0], 0), - "posix_spawn_file_actions_adddup2"); - die_errno(posix_spawn_file_actions_addclose(&file_acts, pipefds[0]), - "posix_spawn_file_actions_addclose"); - die_errno(posix_spawn_file_actions_addclose(&file_acts, pipefds[1]), - "posix_spawn_file_actions_addclose"); - - die_errno(posix_spawnp(&pl->pid, argv[0], &file_acts, NULL, - (char * const *)argv, environ), - "posix_spawnp: %s", argv[0]); - - die_errno(posix_spawn_file_actions_destroy(&file_acts), - "posix_spawn_file_actions_destroy"); - - if (close(pipefds[0])) - die_errno(errno, "close"); - - pl->infd = pipefds[1]; -} - -int finish_pipeline(struct pipeline *pl) -{ - int status; - - if (close(pl->infd)) - die_errno(errno, "close"); - if (waitpid(pl->pid, &status, 0) < 0) - die_errno(errno, "waitpid"); - return WIFEXITED(status) && WEXITSTATUS(status) == 0; -} - poptContext process_options(int argc, const char **argv, struct poptOption *options, const char *help) diff --git a/tools/common.h b/tools/common.h index b3d8ab9..0caee98 100644 --- a/tools/common.h +++ b/tools/common.h @@ -77,14 +77,6 @@ extern void write_all(int fd, amqp_bytes_t data); extern void copy_body(amqp_connection_state_t conn, int fd); -struct pipeline { - int pid; - int infd; -}; - -extern void pipeline(const char * const *argv, struct pipeline *pl); -extern int finish_pipeline(struct pipeline *pl); - #define INCLUDE_OPTIONS(options) \ {NULL, 0, POPT_ARG_INCLUDE_TABLE, options, 0, options ## _title, NULL} diff --git a/tools/consume.c b/tools/consume.c index 9999960..2117bba 100644 --- a/tools/consume.c +++ b/tools/consume.c @@ -54,6 +54,7 @@ #include #include "common.h" +#include "process.h" /* Convert a amqp_bytes_t to an escaped string form for printing. We use the same escaping conventions as rabbitmqctl. */ diff --git a/tools/unix/process.c b/tools/unix/process.c new file mode 100644 index 0000000..8a02afb --- /dev/null +++ b/tools/unix/process.c @@ -0,0 +1,100 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "common.h" +#include "process.h" + +extern char **environ; + +void pipeline(const char *const *argv, struct pipeline *pl) +{ + posix_spawn_file_actions_t file_acts; + + int pipefds[2]; + if (pipe(pipefds)) + die_errno(errno, "pipe"); + + die_errno(posix_spawn_file_actions_init(&file_acts), + "posix_spawn_file_actions_init"); + die_errno(posix_spawn_file_actions_adddup2(&file_acts, pipefds[0], 0), + "posix_spawn_file_actions_adddup2"); + die_errno(posix_spawn_file_actions_addclose(&file_acts, pipefds[0]), + "posix_spawn_file_actions_addclose"); + die_errno(posix_spawn_file_actions_addclose(&file_acts, pipefds[1]), + "posix_spawn_file_actions_addclose"); + + die_errno(posix_spawnp(&pl->pid, argv[0], &file_acts, NULL, + (char * const *)argv, environ), + "posix_spawnp: %s", argv[0]); + + die_errno(posix_spawn_file_actions_destroy(&file_acts), + "posix_spawn_file_actions_destroy"); + + if (close(pipefds[0])) + die_errno(errno, "close"); + + pl->infd = pipefds[1]; +} + +int finish_pipeline(struct pipeline *pl) +{ + int status; + + if (close(pl->infd)) + die_errno(errno, "close"); + if (waitpid(pl->pid, &status, 0) < 0) + die_errno(errno, "waitpid"); + return WIFEXITED(status) && WEXITSTATUS(status) == 0; +} diff --git a/tools/unix/process.h b/tools/unix/process.h new file mode 100644 index 0000000..ac2939d --- /dev/null +++ b/tools/unix/process.h @@ -0,0 +1,57 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +struct pipeline { + int pid; + int infd; +}; + +extern void pipeline(const char *const *argv, struct pipeline *pl); +extern int finish_pipeline(struct pipeline *pl); diff --git a/tools/windows/compat.c b/tools/windows/compat.c new file mode 100644 index 0000000..f0508b2 --- /dev/null +++ b/tools/windows/compat.c @@ -0,0 +1,73 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "compat.h" + +int asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = _vscprintf(fmt, ap); + *strp = malloc(len+1); + if (!*strp) + return -1; + + len = vsprintf(*strp, fmt, ap); + *strp[len] = 0; + + va_end(ap); + return len; +} diff --git a/tools/windows/compat.h b/tools/windows/compat.h new file mode 100644 index 0000000..8211b37 --- /dev/null +++ b/tools/windows/compat.h @@ -0,0 +1,51 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +extern int asprintf(char **strp, const char *fmt, ...); diff --git a/tools/windows/process.c b/tools/windows/process.c new file mode 100644 index 0000000..9a0b893 --- /dev/null +++ b/tools/windows/process.c @@ -0,0 +1,204 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "common.h" +#include "process.h" + +void die_windows_error(const char *fmt, ...) +{ + char *msg; + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&msg, 0, NULL)) + msg = "(failed to retrieving Windows error message)"; + + fprintf(stderr, ": %s\n", msg); + exit(1); +} + +static char *make_command_line(const char *const *argv) +{ + int i; + size_t len = 1; /* initial quotes */ + char *buf; + char *dest; + + /* calculate the length of the required buffer, making worst + case assumptions for simplicity */ + for (i = 0;;) { + len += strlen(argv[i]) * 2; + + if (!argv[++i]) + break; + + len += 3; /* quotes, space, quotes */ + } + + len += 2; /* final quotes and the terminating zero */ + + dest = buf = malloc(len); + if (!buf) + die("allocating memory for subprocess command line"); + + *dest++ = '\"'; + + for (i = 0;;) { + const char *src = argv[i]; + for (;;) { + switch (*src) { + case 0: + goto done; + + case '\"': + case '\\': + *dest++ = '\\'; + /* fall through */ + + default: + *dest++ = *src++; + break; + } + } + done: + + if (!argv[++i]) + break; + + *dest++ = '\"'; + *dest++ = ' '; + *dest++ = '\"'; + } + + *dest++ = '\"'; + *dest++ = 0; + return buf; +} + +void pipeline(const char *const *argv, struct pipeline *pl) +{ + HANDLE in_read_handle, in_write_handle; + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION proc_info; + STARTUPINFO start_info; + char *cmdline = make_command_line(argv); + + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = TRUE; + sec_attr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&in_read_handle, &in_write_handle, &sec_attr, 0)) + die_windows_error("CreatePipe"); + + if (!SetHandleInformation(in_write_handle, HANDLE_FLAG_INHERIT, 0)) + die_windows_error("SetHandleInformation"); + + /* when in Rome... */ + ZeroMemory(&proc_info, sizeof proc_info); + ZeroMemory(&start_info, sizeof start_info); + + start_info.cb = sizeof start_info; + start_info.dwFlags |= STARTF_USESTDHANDLES; + + if ((start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE)) + == INVALID_HANDLE_VALUE + || (start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)) + == INVALID_HANDLE_VALUE) + die_windows_error("GetStdHandle"); + + start_info.hStdInput = in_read_handle; + + if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, + NULL, NULL, &start_info, &proc_info)) + die_windows_error("CreateProcess"); + + if (!CloseHandle(proc_info.hThread)) + die_windows_error("CloseHandle for thread"); + if (!CloseHandle(in_read_handle)) + die_windows_error("CloseHandle"); + + pl->proc_handle = proc_info.hProcess; + pl->infd = _open_osfhandle((intptr_t)in_write_handle, 0); +} + +int finish_pipeline(struct pipeline *pl) +{ + DWORD code; + + if (close(pl->infd)) + die_errno(errno, "close"); + + for (;;) { + if (!GetExitCodeProcess(pl->proc_handle, &code)) + die_windows_error("GetExitCodeProcess"); + if (code != STILL_ACTIVE) + break; + + if (WaitForSingleObject(pl->proc_handle, INFINITE) + == WAIT_FAILED) + die_windows_error("WaitForSingleObject"); + } + + if (!CloseHandle(pl->proc_handle)) + die_windows_error("CloseHandle for process"); + + return code; +} diff --git a/tools/windows/process.h b/tools/windows/process.h new file mode 100644 index 0000000..df276a7 --- /dev/null +++ b/tools/windows/process.h @@ -0,0 +1,59 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is librabbitmq. + * + * The Initial Developers of the Original Code are LShift Ltd, Cohesive + * Financial Technologies LLC, and Rabbit Technologies Ltd. Portions + * created before 22-Nov-2008 00:00:00 GMT by LShift Ltd, Cohesive + * Financial Technologies LLC, or Rabbit Technologies Ltd are Copyright + * (C) 2007-2008 LShift Ltd, Cohesive Financial Technologies LLC, and + * Rabbit Technologies Ltd. + * + * Portions created by LShift Ltd are Copyright (C) 2007-2010 LShift + * Ltd. Portions created by Cohesive Financial Technologies LLC are + * Copyright (C) 2007-2010 Cohesive Financial Technologies + * LLC. Portions created by Rabbit Technologies Ltd are Copyright (C) + * 2007-2010 Rabbit Technologies Ltd. + * + * Portions created by Tony Garnock-Jones are Copyright (C) 2009-2010 + * LShift Ltd and Tony Garnock-Jones. + * + * All Rights Reserved. + * + * Contributor(s): ______________________________________. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2 or later (the "GPL"), in + * which case the provisions of the GPL are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the GPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the + * notice and other provisions required by the GPL. If you do not + * delete the provisions above, a recipient may use your version of + * this file under the terms of any one of the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include + +struct pipeline { + HANDLE proc_handle; + int infd; +}; + +extern void pipeline(const char *const *argv, struct pipeline *pl); +extern int finish_pipeline(struct pipeline *pl); -- cgit v1.2.1