IOChannel and UDP



Hi there,

in order to use UDP with glib, currently you can use the IOChannel, but
most of the provided methods don't make sense (you can't just read or
write to an unconnected socket, and even on a connected socket you would
loose information).

I thought about adding a similar architecture like GIOChannel /
GIOUnixChannel for UDP (see attached files for a rough idea. I called the
general layer GIOMessage and the UDP implementation GIODgram). 

David Helder pointed out that we might better derive from GIOChannel and 
disable the methods that are impossible for datagrams. I'm not sure which
approach is the cleaner one. In one case you might end up with some
duplicate code, in the other case we have "dummy" methods we carry around
in the object.

Which approach do you prefer?

Thanks,
Jochen
#include <glib.h>
#include "giomessage.h"

void
g_io_message_init (GIOMessage *message)
{
  message->message_flags = 0;
  message->ref_count = 1;
}

void 
g_io_message_ref (GIOMessage *message)
{
  g_return_if_fail (message != NULL);

  message->ref_count++;
}

void 
g_io_message_unref (GIOMessage *message)
{
  g_return_if_fail (message != NULL);

  message->ref_count--;
  if (message->ref_count == 0)
    message->funcs->io_free (message);
}

GIOError 
g_io_message_recv (GIOMessage *message, 
		   gchar      *buf, 
		   guint       count,
		   guint      *bytes_read,
		   GIOAddress  sender)
{
  g_return_val_if_fail (message != NULL, G_IO_ERROR_UNKNOWN);

  return message->funcs->io_recv (message, buf, count, bytes_read, sender);
}

GIOError 
g_io_message_send (GIOMessage *message, 
		   gchar      *buf, 
		   guint       count,
		   guint      *bytes_written,
		   GIOAddress  recipient)
{
  g_return_val_if_fail (message != NULL, G_IO_ERROR_UNKNOWN);

  return message->funcs->io_send (message, buf, count, bytes_written, recipient);
}

void
g_io_message_close (GIOMessage *message)
{
  g_return_if_fail (message != NULL);

  message->funcs->io_close (message);
}

guint 
g_io_madd_watch_full (GIOMessage    *message,
		      gint           priority,
		      GIOCondition   condition,
		      GIOMFunc       func,
		      gpointer       user_data,
		      GDestroyNotify notify)
{
  g_return_val_if_fail (message != NULL, 0);

  return message->funcs->io_add_watch (message, priority, condition,
				       func, user_data, notify);
}

guint 
g_io_madd_watch (GIOMessage    *message,
		 GIOCondition   condition,
		 GIOMFunc       func,
		 gpointer       user_data)
{
  return g_io_madd_watch_full (message, 0, condition, func, user_data, NULL);
}
/* GIOMessage
 */

typedef struct _GIOMFuncs  GIOMFuncs;
typedef struct _GIOMessage GIOMessage;

typedef gpointer GIOAddress;

struct _GIOMessage
{
  guint message_flags;
  guint ref_count;
  GIOMFuncs *funcs;
};

typedef gboolean (*GIOMFunc) (GIOMessage   *source,
                              GIOCondition  condition,
                              gpointer      data);

struct _GIOMFuncs
{
  GIOError (*io_recv)   (GIOMessage 	*message, 
		         gchar      	*buf, 
		         guint      	 count,
			 guint      	*bytes_read,
			 GIOAddress	 sender);
  GIOError (*io_send)   (GIOMessage 	*message, 
		 	 gchar      	*buf, 
			 guint      	 count,
			 guint      	*bytes_written,
			 GIOAddress	 recipient);
  void (*io_close)      (GIOMessage	*message);
  guint (*io_add_watch) (GIOMessage     *message,
			 gint            priority,
			 GIOCondition    condition,
			 GIOMFunc        func,
			 gpointer        user_data,
			 GDestroyNotify  notify);
  void (*io_free)       (GIOMessage	*message);
};

void        g_io_message_init   (GIOMessage    *message);
void        g_io_message_ref    (GIOMessage    *message);
void        g_io_message_unref  (GIOMessage    *message);
GIOError    g_io_message_recv   (GIOMessage    *message, 
			         gchar         *buf, 
			         guint          count,
			         guint         *bytes_read,
				 GIOAddress     sender);
GIOError  g_io_message_send     (GIOMessage    *message, 
			         gchar         *buf, 
			         guint          count,
			         guint         *bytes_written,
				 GIOAddress     recipient);
void      g_io_message_close    (GIOMessage    *message);
guint     g_io_madd_watch_full  (GIOMessage    *message,
			         gint           priority,
			         GIOCondition   condition,
			         GIOMFunc       func,
			         gpointer       user_data,
			         GDestroyNotify notify);
guint    g_io_madd_watch        (GIOMessage    *message,
			         GIOCondition   condition,
			         GIOMFunc       func,
			         gpointer       user_data);


#include <glib.h>
#include <sys/socket.h>
#include "giomessage.h"
#include "giodgram.h"
#include "errno.h"

static gboolean 
g_io_dgram_prepare (gpointer source_data, 
		    GTimeVal *current_time,
		    gint     *timeout,
		    gpointer user_data);

static gboolean 
g_io_dgram_check   (gpointer source_data,
		    GTimeVal *current_time,
		    gpointer user_data);

static gboolean
g_io_dgram_dispatch (gpointer source_data, 
		     GTimeVal *current_time,
		     gpointer user_data);

static void 
g_io_dgram_destroy (gpointer source_data);

static GIOError 
g_io_dgram_recv (GIOMessage *message, 
		 gchar      *buf, 
		 guint       count,
		 guint      *bytes_read,
		 GIOAddress  address);

static GIOError 
g_io_dgram_send(GIOMessage *message, 
		gchar      *buf, 
		guint       count,
		guint      *bytes_written,
		GIOAddress  address);

static void 
g_io_dgram_close (GIOMessage *message);

static guint 
g_io_dgram_add_watch (GIOMessage    *message,
		      gint           priority,
		      GIOCondition   condition,
		      GIOMFunc       func,
		      gpointer       user_data,
		      GDestroyNotify notify);

static void 
g_io_dgram_free (GIOMessage *message);

GSourceFuncs dgram_watch_funcs = {
  g_io_dgram_prepare,
  g_io_dgram_check,
  g_io_dgram_dispatch,
  g_io_dgram_destroy
};

GIOMFuncs dgram_message_funcs = {
  g_io_dgram_recv,
  g_io_dgram_send,
  g_io_dgram_close,
  g_io_dgram_add_watch,
  g_io_dgram_free,
};

static gboolean 
g_io_dgram_prepare (gpointer source_data, 
		    GTimeVal *current_time,
		    gint     *timeout,
		    gpointer user_data)
{
  *timeout = -1;
  return FALSE;
}

static gboolean 
g_io_dgram_check   (gpointer source_data,
		    GTimeVal *current_time,
		    gpointer user_data)
{
  GIODgramWatch *data = source_data;

  return (data->pollfd.revents & data->condition);
}

static gboolean
g_io_dgram_dispatch (gpointer source_data, 
		     GTimeVal *current_time,
		     gpointer user_data)

{
  GIODgramWatch *data = source_data;

  return (*data->callback)(data->message,
			   data->pollfd.revents & data->condition,
			   user_data);
}

static void 
g_io_dgram_destroy (gpointer source_data)
{
  GIODgramWatch *data = source_data;

  g_main_remove_poll (&data->pollfd);
  g_io_message_unref (data->message);
  g_free (data);
}

static GIOError 
g_io_dgram_recv (GIOMessage *message, 
		 gchar      *buf, 
		 guint       count,
		 guint      *bytes_read,
		 GIOAddress  address)
{
  GIODgramMessage *dgram_message = (GIODgramMessage *)message;
  gint result;
  GIODgramAddress *saddr;

  saddr = (GIODgramAddress *)address;

  result = recvfrom (dgram_message->fd, buf, count, 0, &(saddr->addr),
  		     &(saddr->len));

  if (result < 0)
    {
      *bytes_read = 0;
      switch (errno)
	{
	case EINVAL:
	  return G_IO_ERROR_INVAL;
	case EAGAIN:
	  return G_IO_ERROR_AGAIN;
	default:
	  return G_IO_ERROR_UNKNOWN;
	}
    }
  else
    {
      *bytes_read = result;
      return G_IO_ERROR_NONE;
    }
}
		       
static GIOError 
g_io_dgram_send(GIOMessage *message, 
		gchar      *buf, 
		guint       count,
		guint      *bytes_written,
		GIOAddress  address)
{
  GIODgramMessage *dgram_message = (GIODgramMessage *)message;
  gint result;
  GIODgramAddress *saddr;

  saddr = (GIODgramAddress *)address;

  result = sendto (dgram_message->fd, buf, count, 0, &(saddr->addr), 
  		   saddr->len);

  if (result < 0)
    {
      *bytes_written = 0;
      switch (errno)
	{
	case EINVAL:
	  return G_IO_ERROR_INVAL;
	case EAGAIN:
	  return G_IO_ERROR_AGAIN;
	default:
	  return G_IO_ERROR_UNKNOWN;
	}
    }
  else
    {
      *bytes_written = result;
      return G_IO_ERROR_NONE;
    }
}

static void 
g_io_dgram_close (GIOMessage *message)
{
  GIODgramMessage *dgram_message = (GIODgramMessage *)message;

  close (dgram_message->fd);
}

static void 
g_io_dgram_free (GIOMessage *message)
{
  GIODgramMessage *dgram_message = (GIODgramMessage *)message;

  g_free (dgram_message);
}

static guint 
g_io_dgram_add_watch (GIOMessage    *message,
		      gint           priority,
		      GIOCondition   condition,
		      GIOMFunc       func,
		      gpointer       user_data,
		      GDestroyNotify notify)
{
  GIODgramWatch *watch = g_new (GIODgramWatch, 1);
  GIODgramMessage *dgram_message = (GIODgramMessage *)message;
  
  watch->message = message;
  g_io_message_ref (message);

  watch->callback = func;
  watch->condition = condition;

  watch->pollfd.fd = dgram_message->fd;
  watch->pollfd.events = condition;

  g_main_add_poll (&watch->pollfd, priority);

  return g_source_add (priority, TRUE, &dgram_watch_funcs, watch, user_data, notify);
}

GIOMessage *
g_io_message_dgram_new (gint fd)
{
  GIODgramMessage *dgram_message = g_new (GIODgramMessage, 1);
  GIOMessage *message = (GIOMessage *)dgram_message;

  g_io_message_init (message);
  message->funcs = &dgram_message_funcs;

  dgram_message->fd = fd;
  return message;
}

gint
g_io_message_dgram_get_fd (GIOMessage *message)
{
  GIODgramMessage *dgram_message = (GIODgramMessage *)message;
  return dgram_message->fd;
}
/*
 * Datagram Messages
 */

typedef struct _GIODgramMessage GIODgramMessage;
typedef struct _GIODgramWatch GIODgramWatch;
typedef struct _GIODgramAddress GIODgramAddress;

struct _GIODgramMessage {
  GIOMessage message;
  gint fd;
};

struct _GIODgramWatch {
  GPollFD       pollfd;
  GIOMessage   *message;
  GIOCondition  condition;
  GIOMFunc      callback;
};

struct _GIODgramAddress {
  socklen_t	  len;
  struct sockaddr addr;
};

GIOMessage * g_io_message_dgram_new (gint fd);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]