+2005-04-18 Tor Lillqvist <tml@novell.com>
+
+ * configure.in: Call AC_LIBTOOL_WIN32_DLL. Check for Win32, set
+ Automake conditional OS_WIN32. Pre-cache information that we do
+ have getaddrinfo(), getnameinfo(), and IPv6 on Win32. (The tests
+ wouldn't notice as they don't include the necessary headers or
+ link with -lws2_32. Easiest to just pre-cache it.)
+
+ * libsoup-zip.in: New file, to build zipfile-based distribution of
+ libsoup for Win32.
+
+ * Makefile.am (EXTRA_DIST)
+ * configure.in (AC_OUTPUT): Add libsoup-zip(.in).
+
+ * libsoup/Makefile.am: Use -no-undefined on Win32. Link with
+ WinSock library -lws2_32.
+
+ * libsoup/soup-portability.h: New file. On Unix it includes the
+ traditional BSD socket etc headers. On Win32 it includes
+ winsock2.h and ws2tcpip.h.
+
+ * libsoup/*.c
+ * libsoup/*.h: Correspondingly, don't include the BSD socket API
+ headers directly.
+
+ * libsoup/soup-address.h
+ * libsoup/soup-dns.h: Include soup-portability.h
+
+ * libsoup/soup-address.c (soup_address_class_init): This function
+ should get called before libsoup uses the WinSock API, so this is
+ a good place to call WSAStartup().
+
+ * libsoup/soup-auth-digest.c (get_protection_space): Use
+ g_strsplit() instead of the relatively unportable strtok_r().
+
+ * libsoup/soun-dns.c: Remove unused headers. Implement
+ inet_pton() and inet_ntop() on Win32 using WSAStringToAddress()
+ and WSAAddressToString().
+
+ * libsoup/soup-socket.c (SOUP_CLOSE_SOCKET, SOUP_IS_SOCKET_ERROR,
+ SOUP_IS_INVALID_SOCKET, SOUP_IS_CONNECT_STATUS_INPROGRESS):
+ Portability macros.
+ (soup_socket_class_init): Call soup_address_get_type() to make
+ sure WSAStartup() gets called (through soup_address_class_init()).
+ (update_fdflags): Use ioctlsocket(FIONBIO) on Win32.
+ (soup_socket_write): Conditionalize SIGPIPE use.
+
+ * tests/get.c: mkdir() is different in Microsoft's C library.
+
+ * tests/simple-httpd.c: Rename TRY_AGAIN label to AGAIN to avoid
+ some clash with winsock2.h (which includes windows.h). The Win32
+ headers pollute the namespace wildly.
+
2005-04-15 Dan Winship <danw@novell.com>
* libsoup/soup-dns.c (resolve_name): make this work with
SUBDIRS = libsoup tests docs
-EXTRA_DIST = libsoup.pc.in gtk-doc.make
+EXTRA_DIST = libsoup.pc.in gtk-doc.make libsoup-zip.in
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
AC_HEADER_STDC
# Initialize libtool
+AC_LIBTOOL_WIN32_DLL
AM_PROG_LIBTOOL
# This isn't a program, but it doesn't fit anywhere else...
AC_SUBST(XML_CFLAGS)
AC_SUBST(XML_LIBS)
+dnl ***********************
+dnl *** Check for Win32 ***
+dnl ***********************
+
+AC_MSG_CHECKING([for Win32])
+case "$host" in
+ *-*-mingw*)
+ os_win32=yes
+ AC_CACHE_VAL(ac_cv_func_getaddrinfo, [ac_cv_func_getaddrinfo=yes])
+ AC_CACHE_VAL(ac_cv_func_getnameinfo, [ac_cv_func_getnameinfo=yes])
+ AC_CACHE_VAL(soup_cv_ipv6, [soup_cv_ipv6=yes])
+ ;;
+ *)
+ os_win32=no
+ ;;
+esac
+AC_MSG_RESULT([$os_win32])
+AM_CONDITIONAL(OS_WIN32, [test $os_win32 = yes])
+
dnl *********************************
dnl *** Networking library checks ***
dnl *********************************
-Wmissing-prototypes -Wnested-externs -Wpointer-arith"
fi
-# Use reentrant functions (FIXME!)
-CFLAGS="$CFLAGS -D_REENTRANT"
+if test "$os_win32" != yes; then
+ # Use reentrant functions (FIXME!)
+ CFLAGS="$CFLAGS -D_REENTRANT"
+fi
dnl *************************
dnl *** Output Everything ***
AC_OUTPUT([
libsoup.pc
Makefile
+ libsoup-zip
libsoup/Makefile
tests/Makefile
docs/Makefile
--- /dev/null
+#!/bin/sh
+
+# Build zipfiles for libsoup on Win32. Separate runtime and developer
+# ones. After running make install, run this.
+
+ZIP=/tmp/libsoup-@VERSION@.zip
+DEVZIP=/tmp/libsoup-dev-@VERSION@.zip
+
+cd @prefix@
+rm $ZIP
+
+current_minus_age=`expr @SOUP_CURRENT@ - @SOUP_AGE@`
+
+zip $ZIP -@ <<EOF
+bin/libsoup-2.4-$current_minus_age.dll
+EOF
+
+rm $DEVZIP
+zip -r $DEVZIP -@ <<EOF
+include/libsoup-2.4
+lib/libsoup-2.4.dll.a
+lib/pkgconfig/libsoup-2.4.pc
+EOF
## Process this file with automake to produce Makefile.in
+if OS_WIN32
+LIBWS2_32 = -lws2_32
+NO_UNDEFINED = -no-undefined
+endif
+
INCLUDES = \
-DG_LOG_DOMAIN=\"libsoup\" \
-I$(top_srcdir) \
soup-message-queue.h \
soup-method.h \
soup-misc.h \
+ soup-portability.h \
soup-server-auth.h \
soup-server-message.h \
soup-server.h \
lib_LTLIBRARIES = libsoup-2.4.la
libsoup_2_4_la_LDFLAGS = \
- -version-info $(SOUP_CURRENT):$(SOUP_REVISION):$(SOUP_AGE)
+ -version-info $(SOUP_CURRENT):$(SOUP_REVISION):$(SOUP_AGE) $(NO_UNDEFINED)
libsoup_2_4_la_LIBADD = \
$(GLIB_LIBS) \
$(XML_LIBS) \
$(LIBGNUTLS_LIBS_STATIC) \
- $(LIBGNUTLS_LIBS)
+ $(LIBGNUTLS_LIBS) \
+ $(LIBWS2_32)
libsoup_2_4_la_SOURCES = \
$(MARSHAL_GENERATED) \
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <signal.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
#include "soup-address.h"
#include "soup-dns.h"
#include "soup-marshal.h"
soup_marshal_NONE__INT,
G_TYPE_NONE, 1,
G_TYPE_INT);
+
+#ifdef G_OS_WIN32
+ /* This hopefully is a good place to call WSAStartup */
+ {
+ WSADATA wsadata;
+ if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
+ g_error ("Windows Sockets could not be initialized");
+ }
+#endif
}
#define SOUP_ADDRESS_H
#include <sys/types.h>
-#include <sys/socket.h>
+#include <libsoup/soup-portability.h>
#include <libsoup/soup-types.h>
#define SOUP_TYPE_ADDRESS (soup_address_get_type ())
SoupAuthDigestPrivate *priv = SOUP_AUTH_DIGEST_GET_PRIVATE (auth);
GSList *space = NULL;
SoupUri *uri;
- char *domain, *d, *lasts, *dir, *slash;
+ char **dvec, *d, *dir, *slash;
+ int dix;
if (!priv->domain || !*priv->domain) {
/* If no domain directive, the protection space is the
return g_slist_prepend (NULL, g_strdup (""));
}
- domain = g_strdup (priv->domain);
- for (d = strtok_r (domain, " ", &lasts); d; d = strtok_r (NULL, " ", &lasts)) {
+ dvec = g_strsplit (priv->domain, " ", 0);
+ for (dix = 0; dvec[dix] != NULL; dix++) {
+ d = dvec[dix];
if (*d == '/')
dir = g_strdup (d);
else {
space = g_slist_prepend (space, dir);
}
}
- g_free (domain);
+ g_strfreev (dvec);
return space;
}
#include <fcntl.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
-#include <netinet/in.h>
-
#include "soup-address.h"
#include "soup-connection.h"
#include "soup-marshal.h"
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <sys/select.h>
#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include "soup-dns.h"
#include "soup-misc.h"
#define SOUP_DNS_SOCKADDR_LEN(sa) sizeof (struct sockaddr_in)
#endif
+#ifdef G_OS_WIN32
+
+static int
+inet_pton (int af,
+ const char *src,
+ void *dst)
+{
+ int address_length;
+
+ switch (af) {
+ case AF_INET:
+ address_length = sizeof (struct sockaddr_in);
+ break;
+
+ case AF_INET6:
+ address_length = sizeof (struct sockaddr_in6);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ g_error ("invalid address family");
+ }
+
+ return (WSAStringToAddress ((LPTSTR) src, af, NULL,
+ dst, &address_length) == 0);
+}
+
+static int
+inet_ntop (int af,
+ const void *src,
+ char *dst,
+ int cnt)
+{
+ int address_length;
+ DWORD string_length = cnt;
+
+ switch (af) {
+ case AF_INET:
+ address_length = sizeof (struct sockaddr_in);
+ break;
+
+ case AF_INET6:
+ address_length = sizeof (struct sockaddr_in6);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ g_error ("invalid address family");
+ }
+
+ return (WSAAddressToString ((LPSOCKADDR) src, address_length, NULL,
+ dst, &string_length) == 0);
+}
+
+#endif
+
typedef struct {
char *entry_name;
guint ref_count;
#include <glib.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
+
+#include <libsoup/soup-portability.h>
void soup_dns_init (void);
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005, Novell, Inc.
+ */
+
+#ifndef SOUP_PORTABILITY_H
+#define SOUP_PORTABILITY_H
+
+#include <glibconfig.h>
+
+#ifdef G_OS_WIN32
+
+#include <winsock2.h>
+#undef interface
+
+#include <ws2tcpip.h>
+
+#else
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#endif
+
+#endif /* SOUP_PORTABILITY_H */
#include "soup-ssl.h"
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
G_DEFINE_TYPE (SoupSocket, soup_socket, G_TYPE_OBJECT)
static void get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
+#ifdef G_OS_WIN32
+#define SOUP_CLOSE_SOCKET(socket) closesocket (socket)
+#define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR)
+#define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
+#define SOUP_IS_CONNECT_STATUS_INPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
+#else
+#define SOUP_CLOSE_SOCKET(socket) close (socket)
+#define SOUP_IS_SOCKET_ERROR(status) ((status) == -1)
+#define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0)
+#define SOUP_IS_CONNECT_STATUS_INPROGRESS() (errno == EINPROGRESS)
+#endif
+
static void
soup_socket_init (SoupSocket *sock)
{
"SSL credentials",
"SSL credential information, passed from the session to the SSL implementation",
G_PARAM_READWRITE));
+
+#ifdef G_OS_WIN32
+ /* Make sure WSAStartup() gets called. */
+ soup_address_get_type ();
+#endif
}
static void
update_fdflags (SoupSocketPrivate *priv)
{
- int flags, opt;
+ int opt;
+#ifndef G_OS_WIN32
+ int flags;
+#endif
if (priv->sockfd == -1)
return;
+#ifndef G_OS_WIN32
flags = fcntl (priv->sockfd, F_GETFL, 0);
if (flags != -1) {
if (priv->non_blocking)
flags &= ~O_NONBLOCK;
fcntl (priv->sockfd, F_SETFL, flags);
}
+#else
+ if (priv->non_blocking) {
+ u_long val = 1;
+ ioctlsocket (priv->sockfd, FIONBIO, &val);
+ } else {
+ u_long val = 0;
+ ioctlsocket (priv->sockfd, FIONBIO, &val);
+ }
+#endif
opt = (priv->nodelay != 0);
setsockopt (priv->sockfd, IPPROTO_TCP,
- TCP_NODELAY, &opt, sizeof (opt));
+ TCP_NODELAY, (void *) &opt, sizeof (opt));
opt = (priv->reuseaddr != 0);
setsockopt (priv->sockfd, SOL_SOCKET,
- SO_REUSEADDR, &opt, sizeof (opt));
+ SO_REUSEADDR, (void *) &opt, sizeof (opt));
}
static void
{
g_mutex_lock (priv->iolock);
if (!priv->iochannel) {
+#ifndef G_OS_WIN32
priv->iochannel =
g_io_channel_unix_new (priv->sockfd);
+#else
+ priv->iochannel =
+ g_io_channel_win32_new_socket (priv->sockfd);
+#endif
g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
g_io_channel_set_buffered (priv->iochannel, FALSE);
goto cant_connect;
if (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
- &error, &len) != 0)
+ (void *) &error, &len) != 0)
goto cant_connect;
if (error)
goto cant_connect;
}
priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
- if (priv->sockfd == -1) {
+ if (SOUP_IS_INVALID_SOCKET (priv->sockfd)) {
goto done;
}
update_fdflags (priv);
status = connect (priv->sockfd, sa, len);
- if (status == -1) {
- if (errno == EINPROGRESS) {
+ if (SOUP_IS_SOCKET_ERROR (status)) {
+ if (SOUP_IS_CONNECT_STATUS_INPROGRESS ()) {
/* Wait for connect to succeed or fail */
priv->watch =
g_io_add_watch (get_iochannel (priv),
connect_watch, sock);
return SOUP_STATUS_CONTINUE;
} else {
- close (priv->sockfd);
+ SOUP_CLOSE_SOCKET (priv->sockfd);
priv->sockfd = -1;
}
}
if (priv->non_blocking) {
priv->watch = g_idle_add (idle_connect_result, sock);
return SOUP_STATUS_CONTINUE;
- } else if (priv->sockfd == -1)
+ } else if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
return SOUP_STATUS_CANT_CONNECT;
else {
get_iochannel (priv);
sa_len = sizeof (sa);
sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, &sa_len);
- if (sockfd == -1)
+ if (SOUP_IS_INVALID_SOCKET (sockfd))
return TRUE;
new = g_object_new (SOUP_TYPE_SOCKET, NULL);
g_return_val_if_fail (sa != NULL, FALSE);
priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
- if (priv->sockfd < 0)
+ if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
goto cant_listen;
update_fdflags (priv);
cant_listen:
if (priv->sockfd != -1) {
- close (priv->sockfd);
+ SOUP_CLOSE_SOCKET (priv->sockfd);
priv->sockfd = -1;
}
else {
g_io_channel_set_close_on_unref (priv->iochannel,
FALSE);
- close (sockfd);
+ SOUP_CLOSE_SOCKET (sockfd);
}
}
{
SoupSocketPrivate *priv;
GIOStatus status;
+#ifdef SIGPIPE
gpointer pipe_handler;
+#endif
GIOCondition cond = G_IO_OUT;
GError *err = NULL;
return SOUP_SOCKET_WOULD_BLOCK;
}
+#ifdef SIGPIPE
pipe_handler = signal (SIGPIPE, SIG_IGN);
+#endif
status = g_io_channel_write_chars (priv->iochannel,
buffer, len, nwrote, &err);
+#ifdef SIGPIPE
signal (SIGPIPE, pipe_handler);
+#endif
if (err) {
if (err->domain == SOUP_SSL_ERROR &&
err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
#include <libsoup/soup.h>
+#ifdef G_OS_WIN32
+#include <io.h>
+#define mkdir(path, mode) _mkdir (path)
+#endif
+
gboolean recurse = FALSE;
SoupSession *session;
GMainLoop *loop;
path_to_open = g_strdup_printf (".%s", path);
- TRY_AGAIN:
+ AGAIN:
if (stat (path_to_open, &st) == -1) {
g_free (path_to_open);
if (errno == EPERM)
g_free (path_to_open);
path_to_open = g_strdup_printf (".%s/index.html", path);
- goto TRY_AGAIN;
+ goto AGAIN;
}
fd = open (path_to_open, O_RDONLY);