summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2009-05-14 12:11:36 (GMT)
committerAlexander Larsson <alexl@redhat.com>2009-05-14 12:11:36 (GMT)
commitb50eaecbae7a03b0a73494d7e70054f1a08a093b (patch)
tree6d9ce70ef607f83f88634cce0ec13562e2e6290f
parent6a9275874b05c933e78e184ce8ea25ca8db48c7d (diff)
downloadgnio-b50eaecbae7a03b0a73494d7e70054f1a08a093b.tar.gz
gnio-b50eaecbae7a03b0a73494d7e70054f1a08a093b.tar.xz
Make reuse address a bind argument instead of a setting
Since we can't always turn this on, but its almost always what you want for a server socket we make this an argument to bind. That way all users of bind (i.e. all server sockets and a few other users) need to decide on this and can set it.
-rw-r--r--gio/gsocket.c166
-rw-r--r--gio/gsocket.h1
-rw-r--r--gio/gtcplistener.c4
-rw-r--r--gio/gunixlistener.c2
-rw-r--r--test/server.c5
5 files changed, 50 insertions, 128 deletions
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 1cdb67b..80e112a 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -118,7 +118,6 @@ enum
PROP_FD,
PROP_BLOCKING,
PROP_LISTEN_BACKLOG,
- PROP_REUSE_ADDRESS,
PROP_KEEPALIVE,
PROP_LOCAL_ADDRESS,
PROP_REMOTE_ADDRESS
@@ -136,7 +135,6 @@ struct _GSocketPrivate
GSocketAddress *remote_address;
guint inited : 1;
guint blocking : 1;
- guint reuse_address : 1;
guint keepalive : 1;
guint closed : 1;
#ifdef G_OS_WIN32
@@ -395,19 +393,6 @@ g_socket_details_from_fd (GSocket *socket)
socket->priv->keepalive = FALSE;
}
- optlen = sizeof bool_val;
- if (getsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
- (void *)&bool_val, &optlen) == 0)
- {
- g_assert (optlen == sizeof bool_val);
- socket->priv->reuse_address = !!bool_val;
- }
- else
- {
- /* Can't read, maybe not supported, assume FALSE */
- socket->priv->reuse_address = FALSE;
- }
-
return;
err:
@@ -561,10 +546,6 @@ g_socket_get_property (GObject *object,
g_value_set_int (value, socket->priv->listen_backlog);
break;
- case PROP_REUSE_ADDRESS:
- g_value_set_boolean (value, socket->priv->reuse_address);
- break;
-
case PROP_KEEPALIVE:
g_value_set_boolean (value, socket->priv->keepalive);
break;
@@ -616,10 +597,6 @@ g_socket_set_property (GObject *object,
g_socket_set_listen_backlog (socket, g_value_get_int (value));
break;
- case PROP_REUSE_ADDRESS:
- g_socket_set_reuse_address (socket, g_value_get_boolean (value));
- break;
-
case PROP_KEEPALIVE:
g_socket_set_keepalive (socket, g_value_get_boolean (value));
break;
@@ -736,13 +713,6 @@ g_socket_class_init (GSocketClass *klass)
10,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_REUSE_ADDRESS,
- g_param_spec_boolean ("reuse-address",
- P_("Reuse address"),
- P_("Allow reuse of local addresses when binding"),
- FALSE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
g_object_class_install_property (gobject_class, PROP_KEEPALIVE,
g_param_spec_boolean ("keepalive",
P_("Keep connection alive"),
@@ -779,7 +749,6 @@ g_socket_init (GSocket *socket)
socket->priv->fd = -1;
socket->priv->blocking = TRUE;
socket->priv->listen_backlog = 10;
- socket->priv->reuse_address = FALSE;
socket->priv->construct_error = NULL;
socket->priv->remote_address = NULL;
socket->priv->local_address = NULL;
@@ -928,80 +897,11 @@ g_socket_get_blocking (GSocket *socket)
}
/**
- * g_socket_set_reuse_address:
- * @socket: a #GSocket.
- * @reuse: Whether to use allow address reuse or not.
- *
- * Setting @reuse to %TRUE enables reusing the socket
- * address used by a previous socket when binding to
- * an address with g_socket_bind().
- *
- * The exact behaviour of this call varies a bit. For TCP sockets on Unix
- * it means that we allow reuse of a socket address that was previously in
- * use and still have outstanding connections in the WAIT state. Enabling
- * this for a server socket is generally safe and useful, as it means you
- * can quickly restart a server application without waiting for all the
- * old connections to time out.
- *
- * However, on windows it means that all reuse of the address is allowed,
- * even if there is another actively listening socket bound to that port.
- * This is not generally a good thing to use. However, on Windows you
- * are automatically allowed to bind to an address if there are outstanding
- * connections in the WAIT state, so address reuse is not as important
- * there as on Unix.
- *
- * Since: 2.22
- **/
-void
-g_socket_set_reuse_address (GSocket *socket,
- gboolean reuse)
-{
- int value;
-
- g_return_if_fail (G_IS_SOCKET (socket));
-
- reuse = !!reuse;
- if (socket->priv->reuse_address == reuse)
- return;
-
- value = (int) reuse;
- if (setsockopt (socket->priv->fd, SOL_SOCKET, SO_REUSEADDR,
- (gpointer) &value, sizeof (value)) < 0)
- {
- int errsv = get_socket_errno ();
- g_warning ("error setting reuse address: %s", socket_strerror (errsv));
- return;
- }
-
- socket->priv->reuse_address = reuse;
- g_object_notify (G_OBJECT (socket), "reuse_address");
-}
-
-/**
- * g_socket_get_reuse_address:
- * @socket: a #GSocket.
- *
- * Gets the reuse_address mode of the socket. For details on this,
- * see g_socket_set_reuse_address().
- *
- * Returns: %TRUE if address reuse is used, %FALSE otherwise.
- *
- * Since: 2.22
- **/
-gboolean
-g_socket_get_reuse_address (GSocket *socket)
-{
- g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
-
- return socket->priv->reuse_address;
-}
-
-/**
* g_socket_set_keepalive:
* @socket: a #GSocket.
* @keepalive: Whether to use try to keep the connection alive or not.
*
- * Setting @reuse to %TRUE enables the sending of periodic ping requests
+ * Setting @keepalive to %TRUE enables the sending of periodic ping requests
* on idle connections in order to keep the connection alive. This is only
* useful for connection oriented sockets. The exact period used between
* each ping is system and protocol dependent.
@@ -1100,7 +1000,7 @@ g_socket_set_listen_backlog (GSocket *socket,
if (backlog != socket->priv->listen_backlog)
{
socket->priv->listen_backlog = backlog;
- g_object_notify (G_OBJECT (socket), "reuse_address");
+ g_object_notify (G_OBJECT (socket), "listen-backlog");
}
}
@@ -1312,6 +1212,7 @@ g_socket_listen (GSocket *socket,
* g_socket_bind:
* @socket: a #GSocket.
* @address: a #GSocketAddress specifying the local address.
+ * @allow_reuse: whether to allow reusing this address
* @error: #GError for error reporting, or %NULL to ignore.
*
* When a socket is created it is attached to an address family, but it
@@ -1321,40 +1222,65 @@ g_socket_listen (GSocket *socket,
* It is generally required to bind to a local address before you can
* receive connections. (See g_socket_listen() and g_socket_accept() ).
*
+ * If @allow_reuse is %TRUE this allows the bind call to succeed in some
+ * situation where it would otherwise return a %G_IO_ERROR_ADDRESS_IN_USE
+ * error. The main example is for a TCP server socket where there are
+ * outstanding connections in the WAIT state, which are generally safe
+ * to ignore. However, setting it to %TRUE doesn't mean the call will
+ * succeed if there is a socket actively bound to the address.
+ *
+ * In general, pass %TRUE if the socket will be used to accept connections,
+ * otherwise pass %FALSE.
+ *
* Returns: %TRUE on success, %FALSE on error.
*
* Since: 2.22
**/
gboolean
g_socket_bind (GSocket *socket,
- GSocketAddress *address,
- GError **error)
+ GSocketAddress *address,
+ gboolean reuse_address,
+ GError **error)
{
+ gchar addr[256];
+ int value;
+
g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE);
if (!check_socket (socket, error))
return FALSE;
- {
- gchar addr[256];
-
- if (!g_socket_address_to_native (address, addr, sizeof addr))
+ /* SO_REUSEADDR on windows means something else and is not what we want.
+ It always allows the unix variant of SO_REUSEADDR anyway */
+#ifndef G_OS_WIN32
+ value = (int) !!reuse_address;
+ if (setsockopt (socket->priv->fd, SOL_SOCKET, SO_REUSEADDR,
+ (gpointer) &value, sizeof (value)) < 0)
+ {
+ int errsv = get_socket_errno ();
+ g_set_error (error,
+ G_IO_ERROR, socket_io_error_from_errno (errsv),
+ _("Error setting reuse_address: %s"), socket_strerror (errsv));
return FALSE;
+ }
+#endif
- if (bind (socket->priv->fd, (struct sockaddr *) addr,
- g_socket_address_get_native_size (address)) < 0)
- {
- int errsv = get_socket_errno ();
- g_set_error (error,
- G_IO_ERROR, socket_io_error_from_errno (errsv),
- _("Error binding to address: %s"), socket_strerror (errsv));
- return FALSE;
- }
+ if (!g_socket_address_to_native (address, addr, sizeof addr))
+ return FALSE;
- socket->priv->local_address = g_object_ref (address);
+ if (bind (socket->priv->fd, (struct sockaddr *) addr,
+ g_socket_address_get_native_size (address)) < 0)
+ {
+ int errsv = get_socket_errno ();
+ g_set_error (error,
+ G_IO_ERROR, socket_io_error_from_errno (errsv),
+ _("Error binding to address: %s"), socket_strerror (errsv));
+ return FALSE;
+ }
- return TRUE;
- }
+ socket->priv->local_address = g_object_ref (address);
+
+ return TRUE;
}
/**
diff --git a/gio/gsocket.h b/gio/gsocket.h
index 4cf0aa8..5984b74 100644
--- a/gio/gsocket.h
+++ b/gio/gsocket.h
@@ -187,6 +187,7 @@ void g_socket_set_listen_backlog (GSocket
gboolean g_socket_is_connected (GSocket *socket);
gboolean g_socket_bind (GSocket *socket,
GSocketAddress *address,
+ gboolean allow_reuse,
GError **error);
gboolean g_socket_connect (GSocket *socket,
GSocketAddress *address,
diff --git a/gio/gtcplistener.c b/gio/gtcplistener.c
index 02a2c1a..60eb52a 100644
--- a/gio/gtcplistener.c
+++ b/gio/gtcplistener.c
@@ -86,11 +86,9 @@ g_tcp_listener_socket_factory (GSocketListener *listener,
if (socket == NULL)
return NULL;
- g_socket_set_reuse_address (socket, TRUE);
-
sockaddr = g_inet_socket_address_new (address, tcp_listener->priv->port);
- if (!g_socket_bind (socket, sockaddr, error))
+ if (!g_socket_bind (socket, sockaddr, TRUE, error))
{
g_object_unref (socket);
socket = NULL;
diff --git a/gio/gunixlistener.c b/gio/gunixlistener.c
index 4cba4ca..95ab516 100644
--- a/gio/gunixlistener.c
+++ b/gio/gunixlistener.c
@@ -54,7 +54,7 @@ g_unix_listener_socket_factory (GSocketListener *listener,
sockaddr = g_unix_socket_address_new (unix_listener->priv->path);
/* XXX fix */
- g_socket_bind (socket, sockaddr, NULL);
+ g_socket_bind (socket, sockaddr, TRUE, NULL);
g_socket_listen (socket, NULL);
g_object_unref (sockaddr);
diff --git a/test/server.c b/test/server.c
index c598539..0733af5 100644
--- a/test/server.c
+++ b/test/server.c
@@ -151,14 +151,11 @@ main (int argc,
return 1;
}
- if (!dont_reuse_address)
- g_socket_set_reuse_address (socket, TRUE);
-
if (non_blocking)
g_socket_set_blocking (socket, FALSE);
src_address = g_inet_socket_address_new (g_inet_address_new_any (G_SOCKET_FAMILY_IPV4), port);
- if (!g_socket_bind (socket, src_address, &error))
+ if (!g_socket_bind (socket, src_address, !dont_reuse_address, &error))
{
g_printerr ("Can't bind socket: %s\n", error->message);
return 1;