mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01:00
Add an event signal to GSocketListener
This allows the caller to know when a socket has been bound so that it can for instance set the SO_SENDBUF and SO_RECVBUF socket options before listen is called https://bugzilla.gnome.org/show_bug.cgi?id=738207
This commit is contained in:
parent
ec9c248d7d
commit
b64e2956f6
@ -2225,6 +2225,7 @@ g_socket_control_message_get_type
|
||||
<FILE>gsocketlistener</FILE>
|
||||
<TITLE>GSocketListener</TITLE>
|
||||
GSocketListener
|
||||
GSocketListenerEvent
|
||||
g_socket_listener_new
|
||||
g_socket_listener_add_socket
|
||||
g_socket_listener_add_address
|
||||
|
@ -1750,6 +1750,29 @@ typedef enum {
|
||||
G_SOCKET_CLIENT_COMPLETE
|
||||
} GSocketClientEvent;
|
||||
|
||||
/**
|
||||
* GSocketListenerEvent:
|
||||
* @G_SOCKET_LISTENER_BINDING: The listener is about to bind a socket.
|
||||
* @G_SOCKET_LISTENER_BOUND: The listener has bound a socket.
|
||||
* @G_SOCKET_LISTENER_LISTENING: The listener is about to start
|
||||
* listening on this socket.
|
||||
* @G_SOCKET_LISTENER_LISTENED: The listener is now listening on
|
||||
* this socket.
|
||||
*
|
||||
* Describes an event occurring on a #GSocketListener. See the
|
||||
* #GSocketListener::event signal for more details.
|
||||
*
|
||||
* Additional values may be added to this type in the future.
|
||||
*
|
||||
* Since: 2.46
|
||||
*/
|
||||
typedef enum {
|
||||
G_SOCKET_LISTENER_BINDING,
|
||||
G_SOCKET_LISTENER_BOUND,
|
||||
G_SOCKET_LISTENER_LISTENING,
|
||||
G_SOCKET_LISTENER_LISTENED
|
||||
} GSocketListenerEvent;
|
||||
|
||||
/**
|
||||
* GTestDBusFlags:
|
||||
* @G_TEST_DBUS_NONE: No flags.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "config.h"
|
||||
#include "gsocketlistener.h"
|
||||
|
||||
#include <gio/gioenumtypes.h>
|
||||
#include <gio/gtask.h>
|
||||
#include <gio/gcancellable.h>
|
||||
#include <gio/gsocketaddress.h>
|
||||
@ -61,6 +62,13 @@ enum
|
||||
PROP_LISTEN_BACKLOG
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EVENT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static GQuark source_quark = 0;
|
||||
|
||||
@ -131,7 +139,6 @@ g_socket_listener_set_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
g_socket_listener_class_init (GSocketListenerClass *klass)
|
||||
{
|
||||
@ -149,6 +156,29 @@ g_socket_listener_class_init (GSocketListenerClass *klass)
|
||||
10,
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GSocketListener::event:
|
||||
* @listener: the #GSocketListener
|
||||
* @event: the event that is occurring
|
||||
* @socket: the #GSocket the event is occurring on
|
||||
*
|
||||
* Emitted when @listener's activity on @socket changes state.
|
||||
* Note that when @listener is used to listen on both IPv4 and
|
||||
* IPv6, a separate set of signals will be emitted for each, and
|
||||
* the order they happen in is undefined.
|
||||
*
|
||||
* Since: 2.46
|
||||
*/
|
||||
signals[EVENT] =
|
||||
g_signal_new (I_("event"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GSocketListenerClass, event),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 2,
|
||||
G_TYPE_SOCKET_LISTENER_EVENT,
|
||||
G_TYPE_SOCKET);
|
||||
|
||||
source_quark = g_quark_from_static_string ("g-socket-listener-source");
|
||||
}
|
||||
|
||||
@ -306,13 +336,29 @@ g_socket_listener_add_address (GSocketListener *listener,
|
||||
|
||||
g_socket_set_listen_backlog (socket, listener->priv->listen_backlog);
|
||||
|
||||
if (!g_socket_bind (socket, address, TRUE, error) ||
|
||||
!g_socket_listen (socket, error))
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BINDING, socket);
|
||||
|
||||
if (!g_socket_bind (socket, address, TRUE, error))
|
||||
{
|
||||
g_object_unref (socket);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BOUND, socket);
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENING, socket);
|
||||
|
||||
if (!g_socket_listen (socket, error))
|
||||
{
|
||||
g_object_unref (socket);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENED, socket);
|
||||
|
||||
local_address = NULL;
|
||||
if (effective_address)
|
||||
{
|
||||
@ -392,7 +438,6 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
|
||||
{
|
||||
GInetAddress *inet_address;
|
||||
GSocketAddress *address;
|
||||
gboolean result;
|
||||
|
||||
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
|
||||
address = g_inet_socket_address_new (inet_address, port);
|
||||
@ -400,18 +445,32 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
|
||||
|
||||
g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog);
|
||||
|
||||
result = g_socket_bind (socket6, address, TRUE, error) &&
|
||||
g_socket_listen (socket6, error);
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BINDING, socket6);
|
||||
|
||||
if (!g_socket_bind (socket6, address, TRUE, error))
|
||||
{
|
||||
g_object_unref (address);
|
||||
g_object_unref (socket6);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_object_unref (address);
|
||||
|
||||
if (!result)
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BOUND, socket6);
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENING, socket6);
|
||||
|
||||
if (!g_socket_listen (socket6, error))
|
||||
{
|
||||
g_object_unref (socket6);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENED, socket6);
|
||||
|
||||
if (source_object)
|
||||
g_object_set_qdata_full (G_OBJECT (socket6), source_quark,
|
||||
g_object_ref (source_object),
|
||||
@ -445,7 +504,6 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
|
||||
{
|
||||
GInetAddress *inet_address;
|
||||
GSocketAddress *address;
|
||||
gboolean result;
|
||||
|
||||
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
|
||||
address = g_inet_socket_address_new (inet_address, port);
|
||||
@ -454,21 +512,40 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
|
||||
g_socket_set_listen_backlog (socket4,
|
||||
listener->priv->listen_backlog);
|
||||
|
||||
result = g_socket_bind (socket4, address, TRUE, error) &&
|
||||
g_socket_listen (socket4, error);
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BINDING, socket4);
|
||||
|
||||
g_object_unref (address);
|
||||
|
||||
if (!result)
|
||||
if (!g_socket_bind (socket4, address, TRUE, error))
|
||||
{
|
||||
g_object_unref (address);
|
||||
g_object_unref (socket4);
|
||||
|
||||
if (socket6 != NULL)
|
||||
g_object_unref (socket6);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_object_unref (address);
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BOUND, socket4);
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENING, socket4);
|
||||
|
||||
if (!g_socket_listen (socket4, error))
|
||||
{
|
||||
g_object_unref (socket4);
|
||||
if (socket6 != NULL)
|
||||
g_object_unref (socket6);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENED, socket4);
|
||||
|
||||
g_object_unref (address);
|
||||
|
||||
if (source_object)
|
||||
g_object_set_qdata_full (G_OBJECT (socket4), source_quark,
|
||||
g_object_ref (source_object),
|
||||
@ -965,6 +1042,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
|
||||
address = g_inet_socket_address_new (inet_address, 0);
|
||||
g_object_unref (inet_address);
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BINDING, socket6);
|
||||
|
||||
result = g_socket_bind (socket6, address, TRUE, error);
|
||||
g_object_unref (address);
|
||||
|
||||
@ -976,6 +1057,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BOUND, socket6);
|
||||
|
||||
g_assert (G_IS_INET_SOCKET_ADDRESS (address));
|
||||
candidate_port =
|
||||
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
|
||||
@ -1004,6 +1088,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
|
||||
address = g_inet_socket_address_new (inet_address, candidate_port);
|
||||
g_object_unref (inet_address);
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BINDING, socket4);
|
||||
|
||||
/* a note on the 'error' clause below:
|
||||
*
|
||||
* if candidate_port is 0 then we report the error right away
|
||||
@ -1029,8 +1117,11 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
|
||||
if (result)
|
||||
/* got our candidate port successfully */
|
||||
break;
|
||||
|
||||
{
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BOUND, socket4);
|
||||
break;
|
||||
}
|
||||
else
|
||||
/* we failed to bind to the specified port. try again. */
|
||||
{
|
||||
@ -1060,6 +1151,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_BOUND, socket4);
|
||||
|
||||
g_assert (G_IS_INET_SOCKET_ADDRESS (address));
|
||||
candidate_port =
|
||||
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
|
||||
@ -1083,6 +1177,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
if (socket6 != NULL)
|
||||
{
|
||||
g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog);
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENING, socket6);
|
||||
|
||||
if (!g_socket_listen (socket6, error))
|
||||
{
|
||||
g_object_unref (socket6);
|
||||
@ -1092,6 +1190,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENED, socket6);
|
||||
|
||||
if (source_object)
|
||||
g_object_set_qdata_full (G_OBJECT (socket6), source_quark,
|
||||
g_object_ref (source_object),
|
||||
@ -1103,6 +1204,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
if (socket4 != NULL)
|
||||
{
|
||||
g_socket_set_listen_backlog (socket4, listener->priv->listen_backlog);
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENING, socket4);
|
||||
|
||||
if (!g_socket_listen (socket4, error))
|
||||
{
|
||||
g_object_unref (socket4);
|
||||
@ -1112,6 +1217,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_signal_emit (listener, signals[EVENT], 0,
|
||||
G_SOCKET_LISTENER_LISTENED, socket4);
|
||||
|
||||
if (source_object)
|
||||
g_object_set_qdata_full (G_OBJECT (socket4), source_quark,
|
||||
g_object_ref (source_object),
|
||||
|
@ -61,8 +61,11 @@ struct _GSocketListenerClass
|
||||
|
||||
void (* changed) (GSocketListener *listener);
|
||||
|
||||
void (* event) (GSocketListener *listener,
|
||||
GSocketListenerEvent *event,
|
||||
GSocket *socket);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
|
@ -19,6 +19,70 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
static void
|
||||
event_cb (GSocketListener *listener,
|
||||
GSocketListenerEvent event,
|
||||
GSocket *socket,
|
||||
gpointer data)
|
||||
{
|
||||
static GSocketListenerEvent expected_event = G_SOCKET_LISTENER_BINDING;
|
||||
gboolean *success = (gboolean *)data;
|
||||
|
||||
g_assert (G_IS_SOCKET_LISTENER (listener));
|
||||
g_assert (G_IS_SOCKET (socket));
|
||||
g_assert (event == expected_event);
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case G_SOCKET_LISTENER_BINDING:
|
||||
expected_event = G_SOCKET_LISTENER_BOUND;
|
||||
break;
|
||||
case G_SOCKET_LISTENER_BOUND:
|
||||
expected_event = G_SOCKET_LISTENER_LISTENING;
|
||||
break;
|
||||
case G_SOCKET_LISTENER_LISTENING:
|
||||
expected_event = G_SOCKET_LISTENER_LISTENED;
|
||||
break;
|
||||
case G_SOCKET_LISTENER_LISTENED:
|
||||
*success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_event_signal (void)
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
GInetAddress *iaddr;
|
||||
GSocketAddress *saddr;
|
||||
GSocketListener *listener;
|
||||
GError *error = NULL;
|
||||
|
||||
iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
|
||||
saddr = g_inet_socket_address_new (iaddr, 0);
|
||||
g_object_unref (iaddr);
|
||||
|
||||
listener = g_socket_listener_new ();
|
||||
|
||||
g_signal_connect (listener, "event", G_CALLBACK (event_cb), &success);
|
||||
|
||||
g_socket_listener_add_address (listener,
|
||||
saddr,
|
||||
G_SOCKET_TYPE_STREAM,
|
||||
G_SOCKET_PROTOCOL_TCP,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (saddr);
|
||||
|
||||
do
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
while (!success);
|
||||
|
||||
g_object_unref (listener);
|
||||
}
|
||||
|
||||
GMutex mutex_712570;
|
||||
GCond cond_712570;
|
||||
volatile gboolean finalized;
|
||||
@ -160,6 +224,7 @@ main (int argc,
|
||||
|
||||
g_test_bug_base ("http://bugzilla.gnome.org/");
|
||||
|
||||
g_test_add_func ("/socket-listener/event-signal", test_event_signal);
|
||||
g_test_add_func ("/socket-listener/threaded/712570", test_threaded_712570);
|
||||
|
||||
return g_test_run();
|
||||
|
Loading…
Reference in New Issue
Block a user