Port to Windows. This is mostly glue layers for the poor POSIX support
authorPierre Ossman <ossman@cendio.se>
Thu, 5 Jan 2006 22:51:37 +0000 (22:51 +0000)
committerPierre Ossman <ossman@cendio.se>
Thu, 5 Jan 2006 22:51:37 +0000 (22:51 +0000)
on Windows. A few notes

 * Only sockets behave somewhat like file descriptors in UNIX.

 * There are no fixed paths. Closes thing is environment variables that point
   to system directories. We also figure out where the binary/dll is
   located and use that as configuration directory.

git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@418 fefdeb5f-60dc-0310-8127-8f9354f1896f

22 files changed:
configure.ac
polyp/Makefile.am
polyp/client-conf.c
polyp/daemon-conf.c
polyp/default.pa.win32 [new file with mode: 0644]
polyp/dllmain.c [new file with mode: 0644]
polyp/iochannel.c
polyp/main.c
polyp/mainloop-signal.c
polyp/mainloop.c
polyp/module-protocol-stub.c
polyp/pid.c
polyp/poll.c
polyp/polyplib-context.c
polyp/pstream.c
polyp/random.c
polyp/scache.c
polyp/socket-client.c
polyp/socket-server.c
polyp/socket-util.c
polyp/tagstruct.c
polyp/util.c

index 1899e92..5ff28a5 100644 (file)
@@ -138,7 +138,7 @@ AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0])
 AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"])
 
 # Windows
-AC_CHECK_HEADERS([winsock2.h ws2tcpip.h])
+AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h])
 
 # Other
 AC_CHECK_HEADERS([sys/ioctl.h])
index beac830..dcd3fc1 100644 (file)
@@ -298,6 +298,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \
                cdecl.h \
                client-conf.c client-conf.h \
                conf-parser.c conf-parser.h \
+               dllmain.c \
                dynarray.c dynarray.h \
                gcc-printf.h \
                idxset.c idxset.h \
@@ -432,6 +433,7 @@ libpolypcore_la_SOURCES = \
                cli-text.c cli-text.h \
                client.c client.h \
                core.c core.h \
+               dllmain.c \
                dynarray.c dynarray.h \
                endianmacros.h \
                g711.c g711.h \
@@ -562,7 +564,7 @@ libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la
 
 libiochannel_la_SOURCES = iochannel.c iochannel.h
 libiochannel_la_LDFLAGS = -avoid-version
-libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la
+libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS)
 
 libpacket_la_SOURCES = packet.c packet.h
 libpacket_la_LDFLAGS = -avoid-version
@@ -727,6 +729,11 @@ modlib_LTLIBRARIES += \
                module-mmkbd-evdev.la
 endif
 
+if OS_IS_WIN32
+modlib_LTLIBRARIES += \
+               module-waveout.la
+endif
+
 # These are generated by a M4 script
 
 SYMDEF_FILES = \
@@ -766,7 +773,8 @@ SYMDEF_FILES = \
                module-oss-symdef.h \
                module-oss-mmap-symdef.h \
                module-alsa-sink-symdef.h \
-               module-alsa-source-symdef.h
+               module-alsa-source-symdef.h \
+               module-waveout-symdef.h
 
 EXTRA_DIST += $(SYMDEF_FILES)
 BUILT_SOURCES += $(SYMDEF_FILES)
@@ -974,6 +982,13 @@ module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version
 module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD)
 module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS)
 
+# Windows waveout
+
+module_waveout_la_SOURCES = module-waveout.c
+module_waveout_la_LDFLAGS = -module -avoid-version
+module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm
+module_waveout_la_CFLAGS = $(AM_CFLAGS)
+
 ###################################
 #        Some minor stuff         #
 ###################################
@@ -990,8 +1005,13 @@ esdcompat.sh: esdcompat.sh.in Makefile
 client.conf: client.conf.in Makefile
        sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
 
+if OS_IS_WIN32    
+default.pa: default.pa.win32
+       cp $< $@
+else
 default.pa: default.pa.in Makefile
        sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
+endif
 
 daemon.conf: daemon.conf.in Makefile
        sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \
index 4906383..04c3d2e 100644 (file)
   USA.
 ***/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdlib.h>
 #include <assert.h>
 #include <unistd.h>
 #include "authkey.h"
 
 #ifndef DEFAULT_CONFIG_DIR
-#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# ifndef OS_IS_WIN32
+#  define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# else
+#  define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
+# endif
+#endif
+
+#ifndef OS_IS_WIN32
+# define PATH_SEP "/"
+#else
+# define PATH_SEP "\\"
 #endif
 
-#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf"
-#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf"
+#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf"
+#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf"
 
 #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG"
 #define ENV_DEFAULT_SINK "POLYP_SINK"
index a6afd05..780581b 100644 (file)
 #include "resampler.h"
 
 #ifndef DEFAULT_CONFIG_DIR
-#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# ifndef OS_IS_WIN32
+#  define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# else
+#  define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
+# endif
 #endif
 
-#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa"
-#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa"
-#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf"
-#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf"
+#ifndef OS_IS_WIN32
+# define PATH_SEP "/"
+#else
+# define PATH_SEP "\\"
+#endif
+
+#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
+#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa"
+#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
+#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf"
 
 #define ENV_SCRIPT_FILE "POLYP_SCRIPT"
 #define ENV_CONFIG_FILE "POLYP_CONFIG"
diff --git a/polyp/default.pa.win32 b/polyp/default.pa.win32
new file mode 100644 (file)
index 0000000..3478ada
--- /dev/null
@@ -0,0 +1,43 @@
+#\r
+# This file is part of polypaudio.\r
+#\r
+# polypaudio is free software; you can redistribute it and/or modify it\r
+# under the terms of the GNU Lesser General Public License as published by\r
+# the Free Software Foundation; either version 2 of the License, or\r
+# (at your option) any later version.\r
+#\r
+# polypaudio is distributed in the hope that it will be useful, but\r
+# WITHOUT ANY WARRANTY; without even the implied warranty of\r
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+# General Public License for more details.\r
+#\r
+# You should have received a copy of the GNU Lesser General Public License\r
+# along with polypaudio; if not, write to the Free Software Foundation,\r
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
+\r
+\r
+# Load audio drivers statically\r
+\r
+load-module module-waveout sink_name=output source_name=input\r
+load-module module-null-sink\r
+\r
+# Load audio drivers automatically on access\r
+\r
+#add-autoload-sink output module-waveout sink_name=output source_name=input\r
+#add-autoload-source input module-waveout sink_name=output source_name=input\r
+\r
+# Load several protocols\r
+#load-module module-esound-protocol-tcp\r
+#load-module module-native-protocol-tcp\r
+#load-module module-simple-protocol-tcp\r
+#load-module module-cli-protocol-tcp\r
+\r
+# Make some devices default\r
+set-default-sink output\r
+set-default-source input\r
+\r
+.nofail\r
+\r
+# Load something to the sample cache\r
+load-sample x11-bell %WINDIR%\Media\ding.wav\r
+load-sample-dir-lazy %WINDIR%\Media\*.wav\r
diff --git a/polyp/dllmain.c b/polyp/dllmain.c
new file mode 100644 (file)
index 0000000..34d0eed
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */
+
+/***
+  This file is part of polypaudio.
+
+  polypaudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  polypaudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef OS_IS_WIN32
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <windows.h>
+
+extern pa_set_root(HANDLE handle);
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
+    if (fdwReason != DLL_PROCESS_ATTACH)
+        return TRUE;
+
+    if (!pa_set_root(hinstDLL))
+        return FALSE;
+
+    return TRUE;
+}
+
+#endif /* OS_IS_WIN32 */
index 0e7e8db..08a4e36 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "iochannel.h"
 #include "util.h"
 #include "socket-util.h"
@@ -189,7 +193,19 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) {
     ssize_t r;
     assert(io && data && l && io->ofd >= 0);
 
-    if ((r = write(io->ofd, data, l)) >= 0) {
+#ifdef OS_IS_WIN32
+    r = send(io->ofd, data, l, 0);
+    if (r < 0) {
+        if (WSAGetLastError() != WSAENOTSOCK) {
+            errno = WSAGetLastError();
+            return r;
+        }
+    }
+
+    if (r < 0)
+#endif
+        r = write(io->ofd, data, l);
+    if (r >= 0) {
         io->writable = 0;
         enable_mainloop_sources(io);
     }
@@ -201,7 +217,19 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) {
     ssize_t r;
     assert(io && data && io->ifd >= 0);
     
-    if ((r = read(io->ifd, data, l)) >= 0) {
+#ifdef OS_IS_WIN32
+    r = recv(io->ifd, data, l, 0);
+    if (r < 0) {
+        if (WSAGetLastError() != WSAENOTSOCK) {
+            errno = WSAGetLastError();
+            return r;
+        }
+    }
+
+    if (r < 0)
+#endif
+        r = read(io->ifd, data, l);
+    if (r >= 0) {
         io->readable = 0;
         enable_mainloop_sources(io);
     }
index 3f9f359..437f0a4 100644 (file)
 #include <memblock.h>
 #include <limits.h>
 #include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
 
 #ifdef HAVE_LIBWRAP
 #include <syslog.h>
@@ -66,6 +75,23 @@ int allow_severity = LOG_INFO;
 int deny_severity = LOG_WARNING;
 #endif
 
+#ifdef OS_IS_WIN32
+
+static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) {
+    MSG msg;
+
+    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+        if (msg.message == WM_QUIT)
+            raise(SIGTERM);
+        else {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+    }
+}
+
+#endif
+
 static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
     pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig));
 
@@ -124,6 +150,10 @@ int main(int argc, char *argv[]) {
     gid_t gid = (gid_t) -1;
 #endif
 
+#ifdef OS_IS_WIN32
+    struct pa_defer_event *defer;
+#endif
+
     pa_limit_caps();
 
 #ifdef HAVE_GETUID
@@ -142,6 +172,13 @@ int main(int argc, char *argv[]) {
     r = lt_dlinit();
     assert(r == 0);
 
+#ifdef OS_IS_WIN32
+    {
+        WSADATA data;
+        WSAStartup(MAKEWORD(2, 0), &data);
+    }
+#endif
+
     pa_log_set_ident("polypaudio");
     
     conf = pa_daemon_conf_new();
@@ -230,6 +267,7 @@ int main(int argc, char *argv[]) {
             goto finish;
         }
 
+#ifdef HAVE_FORK
         if (pipe(daemon_pipe) < 0) {
             pa_log(__FILE__": failed to create pipe.\n");
             goto finish;
@@ -261,6 +299,7 @@ int main(int argc, char *argv[]) {
 
         close(daemon_pipe[0]);
         daemon_pipe[0] = -1;
+#endif
 
         if (conf->auto_log_target)
             pa_log_set_target(PA_LOG_SYSLOG, NULL);
@@ -271,7 +310,8 @@ int main(int argc, char *argv[]) {
 #ifdef HAVE_SETPGID
         setpgid(0,0);
 #endif
-        
+
+#ifndef OS_IS_WIN32
         close(0);
         close(1);
         close(2);
@@ -279,7 +319,10 @@ int main(int argc, char *argv[]) {
         open("/dev/null", O_RDONLY);
         open("/dev/null", O_WRONLY);
         open("/dev/null", O_WRONLY);
-        
+#else
+        FreeConsole();
+#endif
+
 #ifdef SIGTTOU
         signal(SIGTTOU, SIG_IGN);
 #endif
@@ -290,18 +333,23 @@ int main(int argc, char *argv[]) {
         signal(SIGTSTP, SIG_IGN);
 #endif
         
+#ifdef TIOCNOTTY
         if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
             ioctl(tty_fd, TIOCNOTTY, (char*) 0);
             close(tty_fd);
         }
+#endif
     }
 
     chdir("/");
     
     if (conf->use_pid_file) {
         if (pa_pid_file_create() < 0) {
+            pa_log(__FILE__": pa_pid_file_create() failed.\n");
+#ifdef HAVE_FORK
             if (conf->daemonize)
                 pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
             goto finish;
         }
 
@@ -322,9 +370,14 @@ int main(int argc, char *argv[]) {
     signal(SIGPIPE, SIG_IGN);
 #endif
 
+#ifdef OS_IS_WIN32
+    defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL);
+    assert(defer);
+#endif
+
     if (conf->daemonize)
         c->running_as_daemon = 1;
-    
+
 #ifdef SIGUSR1
     pa_signal_new(SIGUSR1, signal_callback, c);
 #endif
@@ -350,17 +403,23 @@ int main(int argc, char *argv[]) {
     
     if (r < 0 && conf->fail) {
         pa_log(__FILE__": failed to initialize daemon.\n");
+#ifdef HAVE_FORK
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
     } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
         pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
+#ifdef HAVE_FORK
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
     } else {
 
         retval = 0;
+#ifdef HAVE_FORK
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
 
         c->disallow_module_loading = conf->disallow_module_loading;
         c->exit_idle_time = conf->exit_idle_time;
@@ -378,7 +437,11 @@ int main(int argc, char *argv[]) {
             pa_log_info(__FILE__": Daemon shutdown initiated.\n");
         }
     }
-        
+
+#ifdef OS_IS_WIN32
+    pa_mainloop_get_api(mainloop)->defer_free(defer);
+#endif
+
     pa_core_free(c);
 
     pa_cpu_limit_done();
@@ -397,6 +460,10 @@ finish:
     
     close_pipe(daemon_pipe);
 
+#ifdef OS_IS_WIN32
+    WSACleanup();
+#endif
+
     lt_dlexit();
     
     return retval;
index eb3f5dd..432498a 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include "mainloop-signal.h"
 #include "util.h"
 #include "xmalloc.h"
@@ -53,19 +57,70 @@ struct pa_signal_event {
 static struct pa_mainloop_api *api = NULL;
 static int signal_pipe[2] = { -1, -1 };
 static struct pa_io_event* io_event = NULL;
+static struct pa_defer_event *defer_event = NULL;
 static struct pa_signal_event *signals = NULL;
 
+#ifdef OS_IS_WIN32
+static unsigned int waiting_signals = 0;
+static CRITICAL_SECTION crit;
+#endif
+
 static void signal_handler(int sig) {
 #ifndef HAVE_SIGACTION
     signal(sig, signal_handler);
 #endif
     write(signal_pipe[1], &sig, sizeof(sig));
+
+#ifdef OS_IS_WIN32
+    EnterCriticalSection(&crit);
+    waiting_signals++;
+    LeaveCriticalSection(&crit);
+#endif
+}
+
+static void dispatch(struct pa_mainloop_api*a, int sig) {
+    struct pa_signal_event*s;
+
+    for (s = signals; s; s = s->next) 
+        if (s->sig == sig) {
+            assert(s->callback);
+            s->callback(a, s, sig, s->userdata);
+            break;
+        }
+}
+
+static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) {
+    ssize_t r;
+    int sig;
+    unsigned int sigs;
+
+#ifdef OS_IS_WIN32
+    EnterCriticalSection(&crit);
+    sigs = waiting_signals;
+    waiting_signals = 0;
+    LeaveCriticalSection(&crit);
+#endif
+
+    while (sigs) {
+        if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
+            pa_log(__FILE__": read(): %s\n", strerror(errno));
+            return;
+        }
+        
+        if (r != sizeof(sig)) {
+            pa_log(__FILE__": short read()\n");
+            return;
+        }
+
+        dispatch(a, sig);
+
+        sigs--;
+    }
 }
 
 static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
     ssize_t r;
     int sig;
-    struct pa_signal_event*s;
     assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
 
         
@@ -81,19 +136,18 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu
         pa_log(__FILE__": short read()\n");
         return;
     }
-    
-    for (s = signals; s; s = s->next) 
-        if (s->sig == sig) {
-            assert(s->callback);
-            s->callback(a, s, sig, s->userdata);
-            break;
-        }
+
+    dispatch(a, sig);
 }
 
 int pa_signal_init(struct pa_mainloop_api *a) {
-    assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event);
-    
+    assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event);
+
+#ifdef OS_IS_WIN32
+    if (_pipe(signal_pipe, 200, _O_BINARY) < 0) {
+#else
     if (pipe(signal_pipe) < 0) {
+#endif
         pa_log(__FILE__": pipe() failed: %s\n", strerror(errno));
         return -1;
     }
@@ -104,20 +158,36 @@ int pa_signal_init(struct pa_mainloop_api *a) {
     pa_fd_set_cloexec(signal_pipe[1], 1);
 
     api = a;
+
+#ifndef OS_IS_WIN32
     io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
     assert(io_event);
+#else
+    defer_event = api->defer_new(api, defer, NULL);
+    assert(defer_event);
+
+    InitializeCriticalSection(&crit);
+#endif
+
     return 0;
 }
 
 void pa_signal_done(void) {
-    assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event);
+    assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event));
 
     while (signals)
         pa_signal_free(signals);
 
 
+#ifndef OS_IS_WIN32
     api->io_free(io_event);
     io_event = NULL;
+#else
+    api->defer_free(defer_event);
+    defer_event = NULL;
+
+    DeleteCriticalSection(&crit);
+#endif
 
     close(signal_pipe[0]);
     close(signal_pipe[1]);
index 90243bd..9cfd539 100644 (file)
 #include "poll.h"
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "mainloop.h"
 #include "util.h"
 #include "idxset.h"
@@ -108,6 +112,26 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu
     e->destroy_callback = NULL;
     e->pollfd = NULL;
 
+#ifdef OS_IS_WIN32
+    {
+        fd_set xset;
+        struct timeval tv;
+
+        tv.tv_sec = 0;
+        tv.tv_usec = 0;
+
+        FD_ZERO (&xset);
+        FD_SET (fd, &xset);
+
+        if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset,
+                    SELECT_TYPE_ARG5 &tv) == -1) &&
+             (WSAGetLastError() == WSAENOTSOCK)) {
+            pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n");
+            e->dead = 1;
+        }
+    }
+#endif
+
     pa_idxset_put(m->io_events, e, NULL);
     m->rebuild_pollfds = 1;
     return e;
index 7cd5ed3..8c06a61 100644 (file)
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #include "module.h"
 #include "socket-server.h"
 #include "socket-util.h"
index 2fac687..ae3dc7f 100644 (file)
 #include <limits.h>
 #include <signal.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include "pid.h"
 #include "util.h"
 #include "log.h"
@@ -130,6 +134,10 @@ int pa_pid_file_create(void) {
     pid_t pid;
     size_t l;
 
+#ifdef OS_IS_WIN32
+    HANDLE process;
+#endif
+
     pa_runtime_path("pid", fn, sizeof(fn));
 
     if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
@@ -138,7 +146,12 @@ int pa_pid_file_create(void) {
     if ((pid = read_pid(fn, fd)) == (pid_t) -1)
         pa_log(__FILE__": corrupt PID file, overwriting.\n");
     else if (pid > 0) {
+#ifdef OS_IS_WIN32
+        if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
+            CloseHandle(process);
+#else
         if (kill(pid, 0) >= 0 || errno != ESRCH) {
+#endif
             pa_log(__FILE__": daemon already running.\n");
             goto fail;
         }
@@ -198,6 +211,12 @@ int pa_pid_file_remove(void) {
         goto fail;
     }
 
+#ifdef OS_IS_WIN32
+    pa_lock_fd(fd, 0);
+    close(fd);
+    fd = -1;
+#endif
+
     if (unlink(fn) < 0) {
         pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno));
         goto fail;
@@ -223,6 +242,8 @@ int pa_pid_file_check_running(pid_t *pid) {
     return pa_pid_file_kill(0, pid);
 }
 
+#ifndef OS_IS_WIN32
+
 /* Kill a current running daemon. Return non-zero on success, -1
  * otherwise. If successful *pid contains the PID of the daemon
  * process. */
@@ -242,7 +263,7 @@ int pa_pid_file_kill(int sig, pid_t *pid) {
     
     if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
         goto fail;
-    
+
     ret = kill(*pid, sig);
     
 fail:
@@ -255,3 +276,11 @@ fail:
     return ret;
     
 }
+
+#else /* OS_IS_WIN32 */
+
+int pa_pid_file_kill(int sig, pid_t *pid) {
+    return -1;
+}
+
+#endif
index 82ea3d8..7c25f34 100644 (file)
 #include <sys/select.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+
+#define EBADF           WSAEBADF
+#define ESHUTDOWN       WSAESHUTDOWN
+#define ECONNRESET      WSAECONNRESET
+#define ECONNABORTED    WSAECONNABORTED
+#define ENETRESET       WSAENETRESET
+
+#endif /* HAVE_WINSOCK2_H */
+
 #ifndef HAVE_SYS_POLL_H
 
 #include "util.h"
@@ -59,7 +70,16 @@ int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
             return 0;
         }
 
+#ifdef OS_IS_WIN32
+        /*
+         * Windows does not support signals properly so waiting for them would
+         * mean a deadlock.
+         */
+        pa_msleep(100);
+        return 0;
+#else
         return select(0, NULL, NULL, NULL, NULL);
+#endif
     }
 
     for (f = fds; f < &fds[nfds]; ++f) {
@@ -138,6 +158,10 @@ int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
         }
     }
 
+#ifdef OS_IS_WIN32
+    errno = WSAGetLastError();
+#endif
+
     if (ready > 0) {
         ready = 0;
         for (f = fds; f < &fds[nfds]; ++f) {
index 1b9d7de..da91995 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <signal.h>
+#include <limits.h>
 
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define ETIMEDOUT       WSAETIMEDOUT
+#define ECONNREFUSED    WSAECONNREFUSED
+#define EHOSTUNREACH    WSAEHOSTUNREACH
+#endif
+
 #include "polyplib-internal.h"
 #include "polyplib-context.h"
 #include "native-common.h"
@@ -382,6 +390,8 @@ finish:
 
 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata);
 
+#ifndef OS_IS_WIN32
+
 static int context_connect_spawn(struct pa_context *c) {
     pid_t pid;
     int status, r;
@@ -495,6 +505,8 @@ fail:
     return -1;
 }
 
+#endif /* OS_IS_WIN32 */
+
 static int try_next_connection(struct pa_context *c) {
     char *u = NULL;
     int r = -1;
@@ -509,10 +521,12 @@ static int try_next_connection(struct pa_context *c) {
         
         if (!u) {
 
+#ifndef OS_IS_WIN32
             if (c->do_autospawn) {
                 r = context_connect_spawn(c);
                 goto finish;
             }
+#endif
             
             pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
             goto finish;
index a64856d..607b0c1 100644 (file)
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "pstream.h"
 #include "queue.h"
 #include "xmalloc.h"
index 456954a..12f27bf 100644 (file)
   USA.
 ***/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
 #include "util.h"
 #include "log.h"
 
+#ifndef OS_IS_WIN32
 #define RANDOM_DEVICE "/dev/urandom"
+#endif
 
 void pa_random(void *ret_data, size_t length) {
     int fd;
     ssize_t r = 0;
     assert(ret_data && length);
-    
+
+#ifdef RANDOM_DEVICE
     if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) {
 
         if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length)
@@ -45,17 +52,20 @@ void pa_random(void *ret_data, size_t length) {
 
         close(fd);
     }
+#endif
 
     if ((size_t) r != length) {
         uint8_t *p;
         size_t l;
-        
+
+#ifdef RANDOM_DEVICE        
         pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s"
                     ", falling back to unsecure pseudo RNG.\n", strerror(errno));
+#endif
 
-        srandom(time(NULL));
+        srand(time(NULL));
         
         for (p = ret_data, l = length; l > 0; p++, l--)
-            *p = (uint8_t) random();
+            *p = (uint8_t) rand();
     }
 }
index 0dec33c..2953145 100644 (file)
 #include <glob.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include "scache.h"
 #include "sink-input.h"
 #include "mainloop.h"
@@ -147,6 +151,13 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename
     struct pa_memchunk chunk;
     int r;
 
+#ifdef OS_IS_WIN32
+    char buf[MAX_PATH];
+
+    if (ExpandEnvironmentStrings(filename, buf, MAX_PATH))
+        filename = buf;
+#endif
+
     if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0)
         return -1;
         
@@ -158,6 +169,14 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename
 
 int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) {
     struct pa_scache_entry *e;
+
+#ifdef OS_IS_WIN32
+    char buf[MAX_PATH];
+
+    if (ExpandEnvironmentStrings(filename, buf, MAX_PATH))
+        filename = buf;
+#endif
+
     assert(c && name);
 
     if (!(e = scache_add_item(c, name)))
@@ -313,7 +332,9 @@ static void add_file(struct pa_core *c, const char *pathname) {
         return;
     }
 
+#if defined(S_ISREG) && defined(S_ISLNK)
     if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
+#endif
         pa_scache_add_file_lazy(c, e, pathname, NULL);
 }
 
index 0d712fa..6d8cb2a 100644 (file)
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define EINPROGRESS     WSAEINPROGRESS
+#define ETIMEDOUT       WSAETIMEDOUT
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #ifdef HAVE_LIBASYNCNS
 #include <asyncns.h>
 #endif
index 0cca4ae..b7e4fed 100644 (file)
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
 #endif
index 60f8d16..699b28c 100644 (file)
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define ETIMEDOUT       WSAETIMEDOUT
+#endif
+
 #include "socket-util.h"
 #include "util.h"
 #include "xmalloc.h"
@@ -72,6 +77,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
         return;
     }
 
+#ifndef OS_IS_WIN32
     if (S_ISSOCK(st.st_mode)) {
         union {
             struct sockaddr sa;
@@ -104,6 +110,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
         snprintf(c, l, "STDIN/STDOUT client");
         return;
     }
+#endif /* OS_IS_WIN32 */
 
     snprintf(c, l, "Unknown client");
 }
index a3bd7d9..59178bf 100644 (file)
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "tagstruct.h"
 #include "xmalloc.h"
 
index acfa031..0495896 100644 (file)
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <signal.h>
 #include <sys/time.h>
-#include <limits.h>
-#include <unistd.h>
 
 #ifdef HAVE_SCHED_H
 #include <sched.h>
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #include <samplerate.h>
 
 #ifdef HAVE_PWD_H
 #include "xmalloc.h"
 #include "log.h"
 
+#ifndef OS_IS_WIN32
 #define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-"
+#define PATH_SEP '/'
+#else
+#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-"
+#define PATH_SEP '\\'
+#endif
+
+#ifdef OS_IS_WIN32
+
+#define POLYP_ROOTENV "POLYP_ROOT"
+
+int pa_set_root(HANDLE handle) {
+    char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep;
+
+    strcpy(library_path, POLYP_ROOTENV "=");
+
+    if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH))
+        return 0;
+
+    sep = strrchr(library_path, '\\');
+    if (sep)
+        *sep = '\0';
+
+    if (_putenv(library_path) < 0)
+        return 0;
+
+    return 1;
+}
+
+#endif
 
 /** Make a file descriptor nonblock. Doesn't do any error checking */
 void pa_make_nonblock_fd(int fd) {
+#ifdef O_NONBLOCK
     int v;
     assert(fd >= 0);
 
     if ((v = fcntl(fd, F_GETFL)) >= 0)
         if (!(v & O_NONBLOCK))
             fcntl(fd, F_SETFL, v|O_NONBLOCK);
+#elif defined(OS_IS_WIN32)
+    u_long arg = 1;
+    if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
+        if (WSAGetLastError() == WSAENOTSOCK)
+            pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n");
+    }
+#else
+    pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n");
+#endif
 }
 
 /** Creates a directory securely */
@@ -85,15 +136,27 @@ int pa_make_secure_dir(const char* dir) {
     struct stat st;
     assert(dir);
 
-    if (mkdir(dir, 0700) < 0) 
+#ifdef OS_IS_WIN32
+    if (mkdir(dir) < 0)
+#else
+    if (mkdir(dir, 0700) < 0)
+#endif
         if (errno != EEXIST)
             return -1;
-    
-    if (lstat(dir, &st) < 0) 
+
+#ifdef OS_IS_WIN32
+    if (stat(dir, &st) < 0)
+#else
+    if (lstat(dir, &st) < 0)
+#endif
         goto fail;
-    
+
+#ifndef OS_IS_WIN32
     if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700))
         goto fail;
+#else
+    fprintf(stderr, "FIXME: pa_make_secure_dir()\n");
+#endif
     
     return 0;
     
@@ -106,10 +169,11 @@ fail:
 int pa_make_secure_parent_dir(const char *fn) {
     int ret = -1;
     char *slash, *dir = pa_xstrdup(fn);
-    
-    if (!(slash = strrchr(dir, '/')))
+
+    slash = pa_path_get_filename(dir);
+    if (slash == fn)
         goto finish;
-    *slash = 0;
+    *(slash-1) = 0;
     
     if (pa_make_secure_dir(dir) < 0)
         goto finish;
@@ -285,6 +349,15 @@ char *pa_get_user_name(char *s, size_t l) {
         }
         
         p = r->pw_name;
+
+#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
+        DWORD size = sizeof(buf);
+
+        if (!GetUserName(buf, &size))
+            return NULL;
+
+        p = buf;
+
 #else /* HAVE_PWD_H */
         return NULL;
 #endif /* HAVE_PWD_H */
@@ -318,6 +391,9 @@ char *pa_get_home_dir(char *s, size_t l) {
     if ((e = getenv("HOME")))
         return pa_strlcpy(s, e, l);
 
+    if ((e = getenv("USERPROFILE")))
+        return pa_strlcpy(s, e, l);
+
 #ifdef HAVE_PWD_H
 #ifdef HAVE_GETPWUID_R
     if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
@@ -349,6 +425,34 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
 int pa_gettimeofday(struct timeval *tv) {
 #ifdef HAVE_GETTIMEOFDAY
     return gettimeofday(tv, NULL);
+#elif defined(OS_IS_WIN32)
+    /*
+     * Copied from implementation by Steven Edwards (LGPL).
+     * Found on wine mailing list.
+     */
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define EPOCHFILETIME (116444736000000000i64)
+#else
+#define EPOCHFILETIME (116444736000000000LL)
+#endif
+
+    FILETIME        ft;
+    LARGE_INTEGER   li;
+    __int64         t;
+
+    if (tv) {
+        GetSystemTimeAsFileTime(&ft);
+        li.LowPart  = ft.dwLowDateTime;
+        li.HighPart = ft.dwHighDateTime;
+        t  = li.QuadPart;       /* In 100-nanosecond intervals */
+        t -= EPOCHFILETIME;     /* Offset to the Epoch time */
+        t /= 10;                /* In microseconds */
+        tv->tv_sec  = (long)(t / 1000000);
+        tv->tv_usec = (long)(t % 1000000);
+    }
+
+    return 0;
 #else
 #error "Platform lacks gettimeofday() or equivalent function."
 #endif
@@ -432,10 +536,12 @@ sensible: set the nice level to -15 and enable realtime scheduling if
 supported.*/
 void pa_raise_priority(void) {
 
+#ifdef HAVE_SYS_RESOURCE_H
     if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
         pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno));
     else 
         pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); 
+#endif
     
 #ifdef _POSIX_PRIORITY_SCHEDULING
     {
@@ -455,10 +561,21 @@ void pa_raise_priority(void) {
         pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); 
     }
 #endif
+
+#ifdef OS_IS_WIN32
+    if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
+        pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError());
+    else
+        pa_log_info(__FILE__": Successfully gained high priority class.\n"); 
+#endif
 }
 
 /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
 void pa_reset_priority(void) {
+#ifdef OS_IS_WIN32
+    SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
+#endif
+
 #ifdef _POSIX_PRIORITY_SCHEDULING
     {
         struct sched_param sp;
@@ -468,11 +585,15 @@ void pa_reset_priority(void) {
     }
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
     setpriority(PRIO_PROCESS, 0, 0);
+#endif
 }
 
 /* Set the FD_CLOEXEC flag for a fd */
 int pa_fd_set_cloexec(int fd, int b) {
+
+#ifdef FD_CLOEXEC
     int v;
     assert(fd >= 0);
 
@@ -483,7 +604,8 @@ int pa_fd_set_cloexec(int fd, int b) {
     
     if (fcntl(fd, F_SETFD, v) < 0)
         return -1;
-    
+#endif    
+
     return 0;
 }
 
@@ -491,6 +613,8 @@ int pa_fd_set_cloexec(int fd, int b) {
  * only. This shoul be used for eyecandy only, don't rely on return
  * non-NULL! */
 char *pa_get_binary_name(char *s, size_t l) {
+
+#ifdef HAVE_READLINK
     char path[PATH_MAX];
     int i;
     assert(s && l);
@@ -503,6 +627,15 @@ char *pa_get_binary_name(char *s, size_t l) {
 
     s[i] = 0;
     return s;
+#elif defined(OS_IS_WIN32)
+    char path[PATH_MAX];
+    if (!GetModuleFileName(NULL, path, PATH_MAX))
+        return NULL;
+    pa_strlcpy(s, pa_path_get_filename(path), l);
+    return s;
+#else
+    return NULL;
+#endif
 }
 
 /* Return a pointer to the filename inside a path (which is the last
@@ -510,7 +643,7 @@ char *pa_get_binary_name(char *s, size_t l) {
 char *pa_path_get_filename(const char *p) {
     char *fn;
 
-    if ((fn = strrchr(p, '/')))
+    if ((fn = strrchr(p, PATH_SEP)))
         return fn+1;
 
     return (char*) p;
@@ -684,6 +817,7 @@ int pa_uid_in_group(const char *name, gid_t *gid) {
 
 /* Lock or unlock a file entirely. (advisory) */
 int pa_lock_fd(int fd, int b) {
+#ifdef F_SETLKW
     struct flock flock;
 
     /* Try a R/W lock first */
@@ -704,6 +838,19 @@ int pa_lock_fd(int fd, int b) {
     }
         
     pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno));
+#endif
+
+#ifdef OS_IS_WIN32
+    HANDLE h = (HANDLE)_get_osfhandle(fd);
+
+    if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
+        return 0;
+    if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
+        return 0;
+
+    pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError());
+#endif
+
     return -1;
 }
 
@@ -795,31 +942,51 @@ int pa_unlock_lockfile(const char *fn, int fd) {
  * allocated buffer containing the used configuration file is
  * stored there.*/
 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
-    const char *e;
+    const char *fn;
     char h[PATH_MAX];
 
-    if (env && (e = getenv(env))) {
+#ifdef OS_IS_WIN32
+    char buf[PATH_MAX];
+
+    if (!getenv(POLYP_ROOTENV))
+        pa_set_root(NULL);
+#endif
+
+    if (env && (fn = getenv(env))) {
+#ifdef OS_IS_WIN32
+        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
+            return NULL;
+        fn = buf;
+#endif
+
         if (result)
-            *result = pa_xstrdup(e);
-        return fopen(e, "r");
+            *result = pa_xstrdup(fn);
+
+        return fopen(fn, "r");
     }
 
     if (local && pa_get_home_dir(h, sizeof(h))) {
         FILE *f;
-        char *l;
+        char *lfn;
         
-        l = pa_sprintf_malloc("%s/%s", h, local);
-        f = fopen(l, "r");
+        lfn = pa_sprintf_malloc("%s/%s", h, local);
+
+#ifdef OS_IS_WIN32
+        if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
+            return NULL;
+        lfn = buf;
+#endif
+
+        f = fopen(lfn, "r");
 
         if (f || errno != ENOENT) {
             if (result)
-                *result = l;
-            else
-                pa_xfree(l);
+                *result = pa_xstrdup(lfn);
+            pa_xfree(lfn);
             return f;
         }
         
-        pa_xfree(l);
+        pa_xfree(lfn);
     }
 
     if (!global) {
@@ -829,6 +996,12 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
         return NULL;
     }
 
+#ifdef OS_IS_WIN32
+    if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
+        return NULL;
+    global = buf;
+#endif
+
     if (result)
         *result = pa_xstrdup(global);
     
@@ -934,21 +1107,44 @@ int pa_startswith(const char *s, const char *pfx) {
 char *pa_runtime_path(const char *fn, char *s, size_t l) {
     char u[256];
 
+#ifndef OS_IS_WIN32
     if (fn && *fn == '/')
+#else
+    if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
+#endif
         return pa_strlcpy(s, fn, l);
-    
-    snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : "");
+
+    if (fn)    
+        snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
+    else
+        snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
+
+#ifdef OS_IS_WIN32
+    {
+        char buf[l];
+        strcpy(buf, s);
+        ExpandEnvironmentStrings(buf, s, l);
+    }
+#endif
+
     return s;
 }
 
 /* Wait t milliseconds */
 int pa_msleep(unsigned long t) {
+#ifdef OS_IS_WIN32
+    Sleep(t);
+    return 0;
+#elif defined(HAVE_NANOSLEEP)
     struct timespec ts;
 
     ts.tv_sec = t/1000;
     ts.tv_nsec = (t % 1000) * 1000000;
 
     return nanosleep(&ts, NULL);
+#else
+#error "Platform lacks a sleep function."
+#endif
 }
 
 /* Convert the string s to a signed integer in *ret_i */