Commit 4e631d2e authored by Philip Withnall's avatar Philip Withnall

gio: Add GDatagramBased interface and rebase GSocket on it

GDatagramBased is an interface abstracting datagram-based communications
in the style of the Berkeley sockets API. It may be contrasted to (for
example) GIOStream, which supports only streaming I/O.

GDatagramBased allows socket-like communications to be done through any
object, not just a concrete GSocket (which wraps socket()).

This adds the GDatagramBased interface, and implements it in GSocket.

https://bugzilla.gnome.org/show_bug.cgi?id=697907
parent e5e08ebe
......@@ -118,6 +118,7 @@
<chapter id="networking">
<title>Low-level network support</title>
<xi:include href="xml/gsocket.xml"/>
<xi:include href="xml/gdatagrambased.xml"/>
<xi:include href="xml/ginetaddress.xml"/>
<xi:include href="xml/ginetaddressmask.xml"/>
<xi:include href="xml/gsocketaddress.xml"/>
......
......@@ -1995,6 +1995,27 @@ G_TYPE_NETWORK_SERVICE
g_network_service_get_type
</SECTION>
<SECTION>
<FILE>gdatagrambased</FILE>
<TITLE>GDatagramBased</TITLE>
GDatagramBased
GDatagramBasedInterface
GDatagramBasedSourceFunc
g_datagram_based_receive_messages
g_datagram_based_send_messages
g_datagram_based_create_source
g_datagram_based_condition_check
g_datagram_based_condition_wait
<SUBSECTION Standard>
G_DATAGRAM_BASED
G_DATAGRAM_BASED_GET_IFACE
G_IS_DATAGRAM_BASED
G_TYPE_DATAGRAM_BASED
G_TYPE_IS_DATAGRAM_BASED
<SUBSECTION Private>
g_datagram_based_get_type
</SECTION>
<SECTION>
<FILE>gsocket</FILE>
<TITLE>GSocket</TITLE>
......
......@@ -357,6 +357,7 @@ libgio_2_0_la_SOURCES = \
gconverteroutputstream.c \
gcredentials.c \
gcredentialsprivate.h \
gdatagrambased.c \
gdatainputstream.c \
gdataoutputstream.c \
gdrive.c \
......@@ -548,6 +549,7 @@ gio_headers = \
gconverter.h \
gconverterinputstream.h \
gconverteroutputstream.h \
gdatagrambased.h \
gdatainputstream.h \
gdataoutputstream.h \
gdrive.h \
......
This diff is collapsed.
/*
* Copyright 2015 Collabora Ltd.
*
* This library 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.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Authors: Philip Withnall <philip.withnall@collabora.co.uk>
*/
#ifndef __G_DATAGRAM_BASED_H__
#define __G_DATAGRAM_BASED_H__
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#include <gio/giotypes.h>
G_BEGIN_DECLS
#define G_TYPE_DATAGRAM_BASED (g_datagram_based_get_type ())
#define G_DATAGRAM_BASED(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_DATAGRAM_BASED, GDatagramBased))
#define G_IS_DATAGRAM_BASED(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_DATAGRAM_BASED))
#define G_DATAGRAM_BASED_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_DATAGRAM_BASED, \
GDatagramBasedInterface))
#define G_TYPE_IS_DATAGRAM_BASED(type) (g_type_is_a ((type), \
G_TYPE_DATAGRAM_BASED))
/**
* GDatagramBased:
*
* Interface for socket-like objects with datagram semantics.
*
* Since: 2.48
*/
typedef struct _GDatagramBasedInterface GDatagramBasedInterface;
/**
* GDatagramBasedInterface:
* @g_iface: The parent interface.
* @receive_messages: Virtual method for g_datagram_based_receive_messages().
* @send_messages: Virtual method for g_datagram_based_send_messages().
* @create_source: Virtual method for g_datagram_based_create_source().
* @condition_check: Virtual method for g_datagram_based_condition_check().
* @condition_wait: Virtual method for
* g_datagram_based_condition_wait().
*
* Provides an interface for socket-like objects which have datagram semantics,
* following the Berkeley sockets API. The interface methods are thin wrappers
* around the corresponding virtual methods, and no pre-processing of inputs is
* implemented — so implementations of this API must handle all functionality
* documented in the interface methods.
*
* Since: 2.48
*/
struct _GDatagramBasedInterface
{
GTypeInterface g_iface;
/* Virtual table */
gint (*receive_messages) (GDatagramBased *datagram_based,
GInputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error);
gint (*send_messages) (GDatagramBased *datagram_based,
GOutputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error);
GSource *(*create_source) (GDatagramBased *datagram_based,
GIOCondition condition,
GCancellable *cancellable);
GIOCondition (*condition_check) (GDatagramBased *datagram_based,
GIOCondition condition);
gboolean (*condition_wait) (GDatagramBased *datagram_based,
GIOCondition condition,
gint64 timeout,
GCancellable *cancellable,
GError **error);
};
GLIB_AVAILABLE_IN_2_48
GType
g_datagram_based_get_type (void);
GLIB_AVAILABLE_IN_2_48
gint
g_datagram_based_receive_messages (GDatagramBased *datagram_based,
GInputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_2_48
gint
g_datagram_based_send_messages (GDatagramBased *datagram_based,
GOutputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_2_48
GSource *
g_datagram_based_create_source (GDatagramBased *datagram_based,
GIOCondition condition,
GCancellable *cancellable);
GLIB_AVAILABLE_IN_2_48
GIOCondition
g_datagram_based_condition_check (GDatagramBased *datagram_based,
GIOCondition condition);
GLIB_AVAILABLE_IN_2_48
gboolean
g_datagram_based_condition_wait (GDatagramBased *datagram_based,
GIOCondition condition,
gint64 timeout,
GCancellable *cancellable,
GError **error);
G_END_DECLS
#endif /* __G_DATAGRAM_BASED_H__ */
......@@ -39,6 +39,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverter, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverterInputStream, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverterOutputStream, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCredentials, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDatagramBased, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDataInputStream, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDataOutputStream, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDBusActionGroup, g_object_unref)
......
......@@ -44,6 +44,7 @@
#include <gio/gconverterinputstream.h>
#include <gio/gconverteroutputstream.h>
#include <gio/gcredentials.h>
#include <gio/gdatagrambased.h>
#include <gio/gdatainputstream.h>
#include <gio/gdataoutputstream.h>
#include <gio/gdbusaddress.h>
......
......@@ -40,6 +40,7 @@ typedef struct _GCharsetConverter GCharsetConverter;
typedef struct _GConverter GConverter;
typedef struct _GConverterInputStream GConverterInputStream;
typedef struct _GConverterOutputStream GConverterOutputStream;
typedef struct _GDatagramBased GDatagramBased;
typedef struct _GDataInputStream GDataInputStream;
typedef struct _GSimplePermission GSimplePermission;
typedef struct _GZlibCompressor GZlibCompressor;
......@@ -389,6 +390,24 @@ typedef gboolean (*GSocketSourceFunc) (GSocket *socket,
GIOCondition condition,
gpointer user_data);
/**
* GDatagramBasedSourceFunc:
* @datagram_based: the #GDatagramBased
* @condition: the current condition at the source fired
* @user_data: data passed in by the user
*
* This is the function type of the callback used for the #GSource
* returned by g_datagram_based_create_source().
*
* Returns: %G_SOURCE_REMOVE if the source should be removed,
* %G_SOURCE_CONTINUE otherwise
*
* Since: 2.48
*/
typedef gboolean (*GDatagramBasedSourceFunc) (GDatagramBased *datagram_based,
GIOCondition condition,
gpointer user_data);
/**
* GInputVector:
* @buffer: Pointer to a buffer where data will be written.
......
......@@ -53,6 +53,7 @@
#endif
#include "gcancellable.h"
#include "gdatagrambased.h"
#include "gioenumtypes.h"
#include "ginetaddress.h"
#include "ginitable.h"
......@@ -137,6 +138,32 @@ static gboolean g_socket_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error);
static void g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface);
static gint g_socket_datagram_based_receive_messages (GDatagramBased *self,
GInputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error);
static gint g_socket_datagram_based_send_messages (GDatagramBased *self,
GOutputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error);
static GSource *g_socket_datagram_based_create_source (GDatagramBased *self,
GIOCondition condition,
GCancellable *cancellable);
static GIOCondition g_socket_datagram_based_condition_check (GDatagramBased *datagram_based,
GIOCondition condition);
static gboolean g_socket_datagram_based_condition_wait (GDatagramBased *datagram_based,
GIOCondition condition,
gint64 timeout,
GCancellable *cancellable,
GError **error);
static GSocketAddress *
cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len);
......@@ -241,7 +268,9 @@ G_DEFINE_TYPE_WITH_CODE (GSocket, g_socket, G_TYPE_OBJECT,
G_ADD_PRIVATE (GSocket)
g_networking_init ();
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_socket_initable_iface_init));
g_socket_initable_iface_init);
G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED,
g_socket_datagram_based_iface_init));
static int
get_socket_errno (void)
......@@ -1007,6 +1036,16 @@ g_socket_initable_iface_init (GInitableIface *iface)
iface->init = g_socket_initable_init;
}
static void
g_socket_datagram_based_iface_init (GDatagramBasedInterface *iface)
{
iface->receive_messages = g_socket_datagram_based_receive_messages;
iface->send_messages = g_socket_datagram_based_send_messages;
iface->create_source = g_socket_datagram_based_create_source;
iface->condition_check = g_socket_datagram_based_condition_check;
iface->condition_wait = g_socket_datagram_based_condition_wait;
}
static void
g_socket_init (GSocket *socket)
{
......@@ -1053,6 +1092,109 @@ g_socket_initable_init (GInitable *initable,
return TRUE;
}
static gboolean
check_datagram_based (GDatagramBased *self,
GError **error)
{
switch (g_socket_get_socket_type (G_SOCKET (self)))
{
case G_SOCKET_TYPE_INVALID:
case G_SOCKET_TYPE_STREAM:
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Cannot use datagram operations on a non-datagram "
"socket."));
return FALSE;
case G_SOCKET_TYPE_DATAGRAM:
case G_SOCKET_TYPE_SEQPACKET:
/* Fall through. */
break;
}
/* Due to us sharing #GSocketSource with the #GSocket implementation, it is
* pretty tricky to split out #GSocket:timeout so that it does not affect
* #GDatagramBased operations (but still affects #GSocket operations). It is
* not worth that effort — just disallow it and require the user to specify
* timeouts on a per-operation basis. */
if (g_socket_get_timeout (G_SOCKET (self)) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Cannot use datagram operations on a socket with a "
"timeout set."));
return FALSE;
}
return TRUE;
}
static gint
g_socket_datagram_based_receive_messages (GDatagramBased *self,
GInputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error)
{
if (!check_datagram_based (self, error))
return FALSE;
return g_socket_receive_messages_with_timeout (G_SOCKET (self), messages,
num_messages, flags, timeout,
cancellable, error);
}
static gint
g_socket_datagram_based_send_messages (GDatagramBased *self,
GOutputMessage *messages,
guint num_messages,
gint flags,
gint64 timeout,
GCancellable *cancellable,
GError **error)
{
if (!check_datagram_based (self, error))
return FALSE;
return g_socket_send_messages_with_timeout (G_SOCKET (self), messages,
num_messages, flags, timeout,
cancellable, error);
}
static GSource *
g_socket_datagram_based_create_source (GDatagramBased *self,
GIOCondition condition,
GCancellable *cancellable)
{
if (!check_datagram_based (self, NULL))
return NULL;
return g_socket_create_source (G_SOCKET (self), condition, cancellable);
}
static GIOCondition
g_socket_datagram_based_condition_check (GDatagramBased *datagram_based,
GIOCondition condition)
{
if (!check_datagram_based (datagram_based, NULL))
return G_IO_ERR;
return g_socket_condition_check (G_SOCKET (datagram_based), condition);
}
static gboolean
g_socket_datagram_based_condition_wait (GDatagramBased *datagram_based,
GIOCondition condition,
gint64 timeout,
GCancellable *cancellable,
GError **error)
{
if (!check_datagram_based (datagram_based, error))
return FALSE;
return g_socket_condition_timed_wait (G_SOCKET (datagram_based), condition,
timeout, cancellable, error);
}
/**
* g_socket_new:
* @family: the socket family to use, e.g. %G_SOCKET_FAMILY_IPV4.
......
......@@ -83,6 +83,7 @@ OBJECTS = \
gbufferedoutputstream.obj \
gcancellable.obj \
gcontenttype.obj \
gdatagrambased.obj \
gdatainputstream.obj \
gdataoutputstream.obj \
# gdesktopappinfo.obj \
......
......@@ -18,6 +18,7 @@ gio/gconverter.c
gio/gconverterinputstream.c
gio/gconverteroutputstream.c
gio/gcredentials.c
gio/gdatagrambased.c
gio/gdatainputstream.c
gio/gdataoutputstream.c
gio/gdbusaddress.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment