Re: [gnet-dev] Unix socket support



Here's a first pass.  I couldn't find the SGML source to the docs, so
they aren't updated, but the code is commented.

The interesting stuff is in src/unix.[ch], and examples/echo*-unix.c.  I
made minor changes to gnet-private.h, and the build infrastructure.

I also fixed a compile warning in server.c, and a typo in a comment in
tcp.c, but I can resend those in a seperate patch if you'd like.

Please let me know if you'd like something changed, or if you have
suggestions for improvements.

M

On Thu, Oct 18, 2001 at 02:00:33PM -0400, David Helder wrote:
> 
> Ok.  Yes, I'll take a patch then.
> 
> David
> 
> 
> On Thu, 18 Oct 2001, Mark Ferlatte wrote:
> 
> > On Thu, Oct 18, 2001 at 01:40:29PM -0400, David Helder wrote:
> > > > The closest thing is probably named pipes, although the semantics are a
> > > > bit different.
> > > >
> > > > Would you be amiable to a patch to add AF_UNIX support, even if there
> > > > wasn't a Windows equivalent?
> > >
> > > Sure.  The interface would be like tcp.h?
> >
> > As much as possible.
> >
> > M
> >
> 
> -- 
>       __          _    __ David Helder - dhelder umich edu
>   ___/ /__ __  __(_)__/ / <http://www.eecs.umich.edu/~dhelder>
>  / _  / _ `/ |/ / / _  /  Jungle Monkey: <http://www.junglemonkey.net>
>  |_,_/|_,_/|___/_/|_,_/   Paper CD Case: <http://www.papercdcase.com>
diff -ruN gnet-1.1.0/examples/Makefile.am gnet-1.1.0-unix/examples/Makefile.am
--- gnet-1.1.0/examples/Makefile.am	Thu May 24 18:29:56 2001
+++ gnet-1.1.0-unix/examples/Makefile.am	Thu Oct 18 19:06:20 2001
@@ -4,6 +4,7 @@
 
 EXTRA_PROGRAMS = echoserver echoclient 	\
 		 echoserver-udp echoclient-udp	\
+		 echoserver-unix echoclient-unix \
 		 hfetch sdr ljoust
 EXTRA_DIST     = ljoust.c
 CLEANFILES     = $(EXTRA_PROGRAMS) ljoust
@@ -27,6 +28,12 @@
 echoclient_udp_SOURCES = \
 	echoclient-udp.c
 
+echoserver_unix_SOURCES = \
+	echoserver-unix.c
+
+echoclient_unix_SOURCES = \
+	echoclient-unix.c
+
 sdr_SOURCES = \
 	sdr.c
 
@@ -40,7 +47,7 @@
 
 ########################################
 
-examples: echoserver echoclient 	\
-	  echoserver-udp echoclient-udp \
-	  hfetch sdr			\
-	  dnstest
+examples: echoserver echoclient 	  \
+	  echoserver-udp echoclient-udp   \
+	  echoserver-unix echoclient-unix \
+	  hfetch sdr			  \
diff -ruN gnet-1.1.0/examples/Makefile.in gnet-1.1.0-unix/examples/Makefile.in
--- gnet-1.1.0/examples/Makefile.in	Thu May 24 18:32:58 2001
+++ gnet-1.1.0-unix/examples/Makefile.in	Thu Oct 18 23:21:21 2001
@@ -87,7 +87,7 @@
 glib_cflags = @glib_cflags@
 glib_libs = @glib_libs@
 
-EXTRA_PROGRAMS = echoserver echoclient 			 echoserver-udp echoclient-udp			 hfetch sdr ljoust
+EXTRA_PROGRAMS = echoserver echoclient 			 echoserver-udp echoclient-udp			 echoserver-unix echoclient-unix 		 hfetch sdr ljoust
 
 EXTRA_DIST = ljoust.c
 CLEANFILES = $(EXTRA_PROGRAMS) ljoust
@@ -110,6 +110,12 @@
 echoclient_udp_SOURCES =  	echoclient-udp.c
 
 
+echoserver_unix_SOURCES =  	echoserver-unix.c
+
+
+echoclient_unix_SOURCES =  	echoclient-unix.c
+
+
 sdr_SOURCES =  	sdr.c
 
 
@@ -138,6 +144,14 @@
 echoclient_udp_LDADD = $(LDADD)
 echoclient_udp_DEPENDENCIES = 
 echoclient_udp_LDFLAGS = 
+echoserver_unix_OBJECTS =  echoserver-unix.o
+echoserver_unix_LDADD = $(LDADD)
+echoserver_unix_DEPENDENCIES = 
+echoserver_unix_LDFLAGS = 
+echoclient_unix_OBJECTS =  echoclient-unix.o
+echoclient_unix_LDADD = $(LDADD)
+echoclient_unix_DEPENDENCIES = 
+echoclient_unix_LDFLAGS = 
 hfetch_OBJECTS =  hfetch.o
 hfetch_LDADD = $(LDADD)
 hfetch_DEPENDENCIES = 
@@ -163,8 +177,8 @@
 
 TAR = tar
 GZIP_ENV = --best
-SOURCES = $(echoserver_SOURCES) $(echoclient_SOURCES) $(echoserver_udp_SOURCES) $(echoclient_udp_SOURCES) $(hfetch_SOURCES) $(sdr_SOURCES) ljoust.c
-OBJECTS = $(echoserver_OBJECTS) $(echoclient_OBJECTS) $(echoserver_udp_OBJECTS) $(echoclient_udp_OBJECTS) $(hfetch_OBJECTS) $(sdr_OBJECTS) ljoust.o
+SOURCES = $(echoserver_SOURCES) $(echoclient_SOURCES) $(echoserver_udp_SOURCES) $(echoclient_udp_SOURCES) $(echoserver_unix_SOURCES) $(echoclient_unix_SOURCES) $(hfetch_SOURCES) $(sdr_SOURCES) ljoust.c
+OBJECTS = $(echoserver_OBJECTS) $(echoclient_OBJECTS) $(echoserver_udp_OBJECTS) $(echoclient_udp_OBJECTS) $(echoserver_unix_OBJECTS) $(echoclient_unix_OBJECTS) $(hfetch_OBJECTS) $(sdr_OBJECTS) ljoust.o
 
 all: all-redirect
 .SUFFIXES:
@@ -231,6 +245,14 @@
 	@rm -f echoclient-udp
 	$(LINK) $(echoclient_udp_LDFLAGS) $(echoclient_udp_OBJECTS) $(echoclient_udp_LDADD) $(LIBS)
 
+echoserver-unix: $(echoserver_unix_OBJECTS) $(echoserver_unix_DEPENDENCIES)
+	@rm -f echoserver-unix
+	$(LINK) $(echoserver_unix_LDFLAGS) $(echoserver_unix_OBJECTS) $(echoserver_unix_LDADD) $(LIBS)
+
+echoclient-unix: $(echoclient_unix_OBJECTS) $(echoclient_unix_DEPENDENCIES)
+	@rm -f echoclient-unix
+	$(LINK) $(echoclient_unix_LDFLAGS) $(echoclient_unix_OBJECTS) $(echoclient_unix_LDADD) $(LIBS)
+
 hfetch: $(hfetch_OBJECTS) $(hfetch_DEPENDENCIES)
 	@rm -f hfetch
 	$(LINK) $(hfetch_LDFLAGS) $(hfetch_OBJECTS) $(hfetch_LDADD) $(LIBS)
@@ -283,14 +305,6 @@
 	    || cp -p $$d/$$file $(distdir)/$$file || :; \
 	  fi; \
 	done
-echoclient-udp.o: echoclient-udp.c ../gnetconfig.h
-echoclient.o: echoclient.c ../gnetconfig.h
-echoserver-udp.o: echoserver-udp.c ../gnetconfig.h
-echoserver.o: echoserver.c ../gnetconfig.h
-hfetch.o: hfetch.c ../gnetconfig.h
-hostinfo.o: hostinfo.c ../gnetconfig.h
-sdr.o: sdr.c ../gnetconfig.h
-
 info-am:
 info: info-am
 dvi-am:
@@ -369,10 +383,10 @@
 
 ########################################
 
-examples: echoserver echoclient 	\
-	  echoserver-udp echoclient-udp \
-	  hfetch sdr			\
-	  dnstest
+examples: echoserver echoclient 	  \
+	  echoserver-udp echoclient-udp   \
+	  echoserver-unix echoclient-unix \
+	  hfetch sdr			  \
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff -ruN gnet-1.1.0/examples/echoclient-unix.c gnet-1.1.0-unix/examples/echoclient-unix.c
--- gnet-1.1.0/examples/echoclient-unix.c	Wed Dec 31 16:00:00 1969
+++ gnet-1.1.0-unix/examples/echoclient-unix.c	Thu Oct 18 23:10:09 2001
@@ -0,0 +1,113 @@
+/* Unix Socket Echo client
+ * Copyright (C) 2001  Mark Ferlatte
+ * Adapted from echoclient.c, Copyright (C) 2000  David Helder
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gnet/gnet.h>
+
+typedef enum { NORMAL, ASYNC} ClientType;
+
+
+static void usage (int status);
+
+static void normal_echoclient (gchar* path);
+static void async_echoclient (gchar* path);
+
+int
+main(int argc, char** argv)
+{
+	ClientType client_type = NORMAL;
+
+	if (argc != 2 && argc != 3)
+		usage(EXIT_FAILURE);
+	if (argc == 3) {
+		if (strcmp(argv[1], "--async") == 0)
+			client_type = ASYNC;
+		else
+			usage(EXIT_FAILURE);
+	}
+
+	switch (client_type) {
+	case NORMAL:
+		g_print ("Normal echo client running\n");
+		normal_echoclient(argv[argc - 1]);
+		break;
+	case ASYNC:
+		g_print ("Asynchronous echo client running (UNFINISHED)\n");
+		async_echoclient(argv[argc - 1]);
+		break;
+	default:
+		g_assert_not_reached();
+	}
+
+	return 0;
+}
+
+static void
+usage (int status)
+{
+	g_print ("usage: echoclient [(nothing)|--async] <path>\n");
+	exit(status);
+}
+
+
+static void
+normal_echoclient(gchar* path)
+{
+	GUnixSocket *socket = NULL;
+	GIOChannel* iochannel = NULL;
+	gchar buffer[1024];
+	guint n;
+	GIOError e = G_IO_ERROR_NONE;
+
+	g_assert(path != NULL);
+
+	/* Create the socket */
+	socket = gnet_unix_socket_new(path);
+	g_assert (socket != NULL);
+
+	/* Get the IOChannel */
+	iochannel = gnet_unix_socket_get_iochannel(socket);
+	g_assert (iochannel != NULL);
+
+	while (fgets(buffer, sizeof(buffer), stdin) != 0) {
+		n = strlen(buffer);
+		e = gnet_io_channel_writen(iochannel, buffer, n, &n);
+		if (e != G_IO_ERROR_NONE)
+			break;
+		e = gnet_io_channel_readn(iochannel, buffer, n, &n);
+		if (e != G_IO_ERROR_NONE)
+			break;
+		fwrite(buffer, n, 1, stdout);
+	}
+
+	if (e != G_IO_ERROR_NONE) 
+		g_print ("IO error (%d)\n", e);
+	return;
+}
+
+static void
+async_echoclient(gchar *path)
+{
+	g_print("Sorry, there is no async echoclient yet.\n");
+	return;
+}
diff -ruN gnet-1.1.0/examples/echoserver-unix.c gnet-1.1.0-unix/examples/echoserver-unix.c
--- gnet-1.1.0/examples/echoserver-unix.c	Wed Dec 31 16:00:00 1969
+++ gnet-1.1.0-unix/examples/echoserver-unix.c	Thu Oct 18 23:09:09 2001
@@ -0,0 +1,310 @@
+/* Unix socket Echo server
+ * Copyright (C) 2001  Mark Ferlatte
+ * Adapted from echoserver.c, Copyright (C) 2000  David Helder
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+#include <glib.h>
+#include <gnet/gnet.h>
+
+typedef enum { NORMAL, ASYNC} ServerType;
+
+void cleanup_on_sig(int signum);
+
+static void usage(int status);
+static void normal_echoserver(gchar *path);
+static void async_echoserver(gchar *path);
+
+gchar *socket_path;
+
+int
+main(int argc, char** argv)
+{
+	gchar *path = NULL;
+	ServerType server_type = NORMAL;
+	struct stat stbuf;
+	
+	if (argc !=  2 && argc != 3) {
+		usage(EXIT_FAILURE);
+	}
+	if (argc == 3) {
+		if (strcmp(argv[1], "--async") == 0)
+			server_type = ASYNC;
+		else {
+			usage(EXIT_FAILURE);
+		}
+	}
+	
+	path = g_new0(gchar, strlen(argv[argc - 1]));
+	path = memcpy(path, argv[argc - 1], strlen(argv[argc - 1]));
+
+	if (stat(path, &stbuf) == 0) {
+		if (S_ISSOCK(stbuf.st_mode)) {
+			unlink(path);
+		} else {
+			g_print("%s is not a socket!\n", path);
+			exit(EXIT_FAILURE);
+		}
+	}
+	socket_path = path;
+
+	signal(SIGINT, cleanup_on_sig);
+	signal(SIGTERM, cleanup_on_sig);
+		
+	switch (server_type) {
+	case NORMAL:
+		g_print("Normal echo server running\n");
+		normal_echoserver(path);
+		break;
+	case ASYNC:
+		g_print("Async echo server running\n");
+		async_echoserver(path);
+		break;
+	default:
+		g_assert_not_reached();
+	}
+	return 0;
+}
+
+static void
+usage(int status)
+{
+	g_print("usage: echoserver-unix [(nothing)|--async] <path>\n");
+	exit(status);
+}
+
+void
+cleanup_on_sig(int signum)
+{
+	struct stat stbuf;
+	if (stat(socket_path, &stbuf) == 0) {
+		if (S_ISSOCK(stbuf.st_mode)) {
+			unlink(socket_path);
+		}
+	}
+	exit(EXIT_SUCCESS);
+}
+
+static void
+normal_echoserver(gchar *path)
+{
+	GUnixSocket *server;
+	GUnixSocket *client = NULL;
+	gchar buffer[1024];
+	guint n;
+	GIOChannel *ioclient = NULL;
+	GIOError e;
+
+	g_assert(path != NULL);
+	
+	/* Create the server */
+	server = gnet_unix_socket_server_new(path);
+	g_assert(server != NULL);
+
+	while ((client = gnet_unix_socket_server_accept(server)) != NULL) {
+		ioclient = gnet_unix_socket_get_iochannel(client);
+		g_assert(ioclient != NULL);
+
+		while ((e = gnet_io_channel_readline(ioclient, buffer,
+						     sizeof(buffer), &n))
+		       == G_IO_ERROR_NONE && (n > 0)) {
+			e = gnet_io_channel_writen(ioclient, buffer, n, &n);
+			if (e != G_IO_ERROR_NONE)
+				break;
+			fwrite(buffer, n, 1, stdout);
+		}
+		if (e != G_IO_ERROR_NONE)
+			fprintf(stderr,
+				"\nRecieved error %d (closing socket).\n",
+				e);
+		g_io_channel_unref(ioclient);
+		gnet_unix_socket_delete(client);
+	}
+}
+
+typedef struct
+{
+	GUnixSocket *socket;
+	GIOChannel *iochannel;
+	guint out_watch;
+	gchar buffer[1024];
+	guint n;
+} client_state;
+
+static void clientstate_delete(client_state *state);
+
+static gboolean async_server_iofunc(GIOChannel *server,
+				    GIOCondition c, gpointer data);
+static gboolean async_client_iofunc(GIOChannel *client,
+				    GIOCondition c, gpointer data);
+
+static void
+clientstate_delete(client_state *state)
+{
+	if (state->out_watch)
+		g_source_remove(state->out_watch);
+	g_io_channel_unref(state->iochannel);
+	gnet_unix_socket_delete(state->socket);
+	g_free(state);
+}
+
+static void
+async_echoserver(gchar *path)
+{
+	GUnixSocket *server;
+	GIOChannel *iochannel = NULL;
+	GMainLoop *main_loop = NULL;
+
+	g_assert(path != NULL);
+	server = gnet_unix_socket_server_new(path);
+	g_assert(server != NULL);
+
+	main_loop = g_main_new(FALSE);
+
+	/* Add a watch for incoming clients */
+	iochannel = gnet_unix_socket_get_iochannel(server);
+	g_io_add_watch(iochannel,
+		       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+		       async_server_iofunc, server);
+
+	/* Start the main loop */
+	g_main_run(main_loop);
+}
+
+static gboolean
+async_server_iofunc(GIOChannel *iochannel, GIOCondition c, gpointer data)
+{
+	GUnixSocket *server = (GUnixSocket *) data;
+	g_assert(server != NULL);
+
+	if (c & G_IO_IN) {
+		GUnixSocket *client = NULL;
+		GIOChannel *client_iochannel = NULL;
+		client_state *cs = NULL;
+
+		client = gnet_unix_socket_server_accept(server);
+		g_assert(client != NULL);
+
+		client_iochannel = gnet_unix_socket_get_iochannel(client);
+		g_assert(client_iochannel != NULL);
+
+		cs = g_new0(client_state, 1);
+		cs->socket = client;
+		cs->iochannel = client_iochannel;
+
+		g_io_add_watch(client_iochannel,
+			       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			       async_client_iofunc, cs);
+	} else {
+		fprintf(stderr, "Server error %d\n", c);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/*
+
+  This callback is called for (IN|ERR) or OUT.  
+
+  We add the watch for (IN|ERR) when the client connects in
+  async_server_iofunc().  We remove it if the connection is closed
+  (i.e. we read 0 bytes) or if there's an error.
+
+  We add the watch for OUT when we have something to write and remove
+  it when we're done writing or when the connection is closed.
+ */
+static gboolean
+async_client_iofunc(GIOChannel *iochannel, GIOCondition c,
+		    gpointer data)
+{
+	client_state *cs = (client_state *) data;
+
+	g_assert(cs != NULL);
+
+	/* Check for socket error */
+	if (c & G_IO_ERR) {
+		fprintf(stderr, "Client socket error!\n");
+		goto error;
+	}
+	/* Check for data to be read (or if the socket was closed) */
+	if (c & G_IO_IN) {
+		GIOError e;
+		guint bytes_read;
+
+		/* Read the data into our buffer */
+		e = g_io_channel_read(iochannel,
+				      &cs->buffer[cs->n],
+				      sizeof(cs->buffer) - cs->n,
+				      &bytes_read);
+		/* Check for socket error */
+		if (e != G_IO_ERROR_NONE) {
+			fprintf(stderr, "Client read error: %d\n", e);
+			goto error;
+		} else if (bytes_read == 0) {
+		/* Check if we read 0 bytes, which means the connection
+		   is closed */
+			goto error;
+		} else {
+			g_assert(bytes_read > 0);
+			/* If there isn't an out_watch, add one */
+			if (cs->out_watch == 0) {
+				cs->out_watch =
+					g_io_add_watch(iochannel,
+						       G_IO_OUT,
+						       async_client_iofunc,
+						       cs);
+			}
+			fwrite(&cs->buffer[cs->n], bytes_read, 1, stdout);
+			cs->n += bytes_read;
+		}
+	}
+	if (c & G_IO_OUT) {
+		GIOError e;
+		guint bytes_written;
+		/* Write the data out */
+		e = g_io_channel_write(iochannel, cs->buffer, cs->n,
+				       &bytes_written);
+		if (e != G_IO_ERROR_NONE) {
+			fprintf(stderr, "Client write error: %d\n", e);
+			clientstate_delete(cs);
+			return FALSE;
+		} else if (bytes_written > 0) {
+			/* Move the memory down some (you wouldn't do this
+			   in a performance server because it's slow) */
+			g_memmove(cs->buffer,
+				  &cs->buffer[bytes_written],
+				  bytes_written);
+			cs->n -= bytes_written;
+		}
+		/* Check if done */
+		if (cs->n == 0) {
+			cs->out_watch = 0;
+			return FALSE;
+		}
+	}
+	return TRUE;
+
+ error:
+	clientstate_delete(cs);
+	return FALSE;
+}
diff -ruN gnet-1.1.0/src/Makefile.am gnet-1.1.0-unix/src/Makefile.am
--- gnet-1.1.0/src/Makefile.am	Sat Feb 17 12:26:21 2001
+++ gnet-1.1.0-unix/src/Makefile.am	Thu Oct 18 16:23:53 2001
@@ -25,7 +25,8 @@
 	pack.c			\
 	url.c			\
 	conn.c			\
-	server.c
+	server.c		\
+	unix.c
 
 gnetinclude_HEADERS = 		\
 	gnet.h			\
@@ -39,6 +40,7 @@
 	pack.h			\
 	url.h			\
 	conn.h			\
-	server.h
+	server.h		\
+	unix.h
 
 EXTRA_DIST = gnet-private.h
diff -ruN gnet-1.1.0/src/Makefile.in gnet-1.1.0-unix/src/Makefile.in
--- gnet-1.1.0/src/Makefile.in	Thu May 24 18:32:56 2001
+++ gnet-1.1.0-unix/src/Makefile.in	Thu Oct 18 23:21:21 2001
@@ -96,10 +96,10 @@
 libgnet_la_LDFLAGS =  	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) 	-release $(LT_RELEASE)
 
 
-libgnet_la_SOURCES =  	gnet.c				gnet-private.c			inetaddr.c			mcast.c				tcp.c				udp.c				iochannel.c			md5.c				sha.c				pack.c				url.c				conn.c				server.c
+libgnet_la_SOURCES =  	gnet.c				gnet-private.c			inetaddr.c			mcast.c				tcp.c				udp.c				iochannel.c			md5.c				sha.c				pack.c				url.c				conn.c				server.c			unix.c
 
 
-gnetinclude_HEADERS =  	gnet.h			        inetaddr.h                      mcast.h           		tcp.h			        udp.h				iochannel.h			md5.h				sha.h				pack.h				url.h				conn.h				server.h
+gnetinclude_HEADERS =  	gnet.h			        inetaddr.h                      mcast.h           		tcp.h			        udp.h				iochannel.h			md5.h				sha.h				pack.h				url.h				conn.h				server.h			unix.h
 
 
 EXTRA_DIST = gnet-private.h
@@ -116,7 +116,7 @@
 libgnet_la_LIBADD = 
 libgnet_la_OBJECTS =  gnet.lo gnet-private.lo inetaddr.lo mcast.lo \
 tcp.lo udp.lo iochannel.lo md5.lo sha.lo pack.lo url.lo conn.lo \
-server.lo
+server.lo unix.lo
 CFLAGS = @CFLAGS@
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -270,39 +270,6 @@
 	    || cp -p $$d/$$file $(distdir)/$$file || :; \
 	  fi; \
 	done
-conn.lo conn.o : conn.c conn.h tcp.h inetaddr.h iochannel.h
-gnet-private.lo gnet-private.o : gnet-private.c gnet-private.h \
-	../config.h gnet.h ../gnetconfig.h inetaddr.h iochannel.h udp.h \
-	mcast.h tcp.h pack.h url.h conn.h server.h md5.h sha.h
-gnet.lo gnet.o : gnet.c gnet-private.h ../config.h gnet.h \
-	../gnetconfig.h inetaddr.h iochannel.h udp.h mcast.h tcp.h \
-	pack.h url.h conn.h server.h md5.h sha.h
-inetaddr.lo inetaddr.o : inetaddr.c gnet-private.h ../config.h gnet.h \
-	../gnetconfig.h inetaddr.h iochannel.h udp.h mcast.h tcp.h \
-	pack.h url.h conn.h server.h md5.h sha.h
-iochannel.lo iochannel.o : iochannel.c gnet-private.h ../config.h gnet.h \
-	../gnetconfig.h inetaddr.h iochannel.h udp.h mcast.h tcp.h \
-	pack.h url.h conn.h server.h md5.h sha.h
-mcast.lo mcast.o : mcast.c gnet-private.h ../config.h gnet.h \
-	../gnetconfig.h inetaddr.h iochannel.h udp.h mcast.h tcp.h \
-	pack.h url.h conn.h server.h md5.h sha.h
-md5.lo md5.o : md5.c md5.h
-pack.lo pack.o : pack.c pack.h
-packtest.o: packtest.c pack.h
-server.lo server.o : server.c server.h tcp.h inetaddr.h conn.h \
-	iochannel.h gnet-private.h ../config.h gnet.h ../gnetconfig.h \
-	udp.h mcast.h pack.h url.h md5.h sha.h
-sha.lo sha.o : sha.c sha.h ../config.h
-tcp.lo tcp.o : tcp.c gnet-private.h ../config.h gnet.h ../gnetconfig.h \
-	inetaddr.h iochannel.h udp.h mcast.h tcp.h pack.h url.h conn.h \
-	server.h md5.h sha.h
-udp.lo udp.o : udp.c gnet-private.h ../config.h gnet.h ../gnetconfig.h \
-	inetaddr.h iochannel.h udp.h mcast.h tcp.h pack.h url.h conn.h \
-	server.h md5.h sha.h
-url.lo url.o : url.c gnet-private.h ../config.h gnet.h ../gnetconfig.h \
-	inetaddr.h iochannel.h udp.h mcast.h tcp.h pack.h url.h conn.h \
-	server.h md5.h sha.h
-
 info-am:
 info: info-am
 dvi-am:
diff -ruN gnet-1.1.0/src/gnet-private.h gnet-1.1.0-unix/src/gnet-private.h
--- gnet-1.1.0/src/gnet-private.h	Tue Mar  6 12:30:16 2001
+++ gnet-1.1.0-unix/src/gnet-private.h	Thu Oct 18 18:47:35 2001
@@ -54,7 +54,8 @@
 #include <sys/sockio.h>
 #endif
 #include <sys/time.h>
-
+#include <sys/stat.h>
+#include <sys/un.h>
 #include <sys/utsname.h>
 #include <sys/wait.h>
 
@@ -127,6 +128,15 @@
   struct sockaddr sa;		/* Why not an InetAddr? */
   guint ref_count;
   GIOChannel* iochannel;
+};
+
+struct _GUnixSocket
+{
+	gint sockfd;
+	struct sockaddr sa;
+	guint ref_count;
+	gboolean server;
+	GIOChannel *iochannel;
 };
 
 struct _GMcastSocket
diff -ruN gnet-1.1.0/src/gnet.h gnet-1.1.0-unix/src/gnet.h
--- gnet-1.1.0/src/gnet.h	Wed May 23 07:08:07 2001
+++ gnet-1.1.0-unix/src/gnet.h	Thu Oct 18 18:06:50 2001
@@ -35,7 +35,7 @@
 #include "server.h"
 #include "md5.h"
 #include "sha.h"
-
+#include "unix.h"
 
 #ifdef __cplusplus
 extern "C" {
diff -ruN gnet-1.1.0/src/server.c gnet-1.1.0-unix/src/server.c
--- gnet-1.1.0/src/server.c	Wed May  2 14:02:47 2001
+++ gnet-1.1.0-unix/src/server.c	Thu Oct 18 17:11:54 2001
@@ -17,9 +17,10 @@
  * Boston, MA  02111-1307, USA.
  */
 
+#include "gnet-private.h"
 #include <memory.h>
 #include "server.h"
-#include "gnet-private.h"
+
 
 
 
diff -ruN gnet-1.1.0/src/tcp.c gnet-1.1.0-unix/src/tcp.c
--- gnet-1.1.0/src/tcp.c	Tue May 22 20:26:23 2001
+++ gnet-1.1.0-unix/src/tcp.c	Thu Oct 18 17:02:35 2001
@@ -689,7 +689,7 @@
  *  @port: Port number for the socket (0 if you don't care).
  *
  *  Create and open a new #GTcpSocket with the specified port number.
- *  Use this sort of socket when your are a server and you know what
+ *  Use this sort of socket when you are a server and you know what
  *  the port number should be (or pass 0 if you don't care what the
  *  port is).
  *
diff -ruN gnet-1.1.0/src/unix.c gnet-1.1.0-unix/src/unix.c
--- gnet-1.1.0/src/unix.c	Wed Dec 31 16:00:00 1969
+++ gnet-1.1.0-unix/src/unix.c	Thu Oct 18 18:51:31 2001
@@ -0,0 +1,326 @@
+/* GNet - Networking library
+ * Copyright (C) 2000  David Helder
+ * Copyright (C) 2001  Mark Ferlatte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#include "gnet-private.h"
+#include "unix.h"
+
+/* gnet_unix_socket_connect:
+   @path: Path to socket to connect to
+
+   A quick and easy GUnixSocket constructor.  This connects to the
+   specified path.  This function does block.  Use this function when you
+   are a client connecting to a server and you don't mind blocking.
+
+   Returns: A new GUnixSocket, or NULL if there was a failure.
+ */
+GUnixSocket *
+gnet_unix_socket_connect(const gchar *path)
+{
+	return gnet_unix_socket_new(path);
+}
+	
+/* gnet_unix_socket_new:
+   @path: Path to connect to.
+
+   Connect to a specified address.  use this sort of socket when you're a
+   client connecting to a server.  This function will block to connect.
+
+   Returns a new GUnixSocket, or NULL if there was a failure.
+ */
+GUnixSocket *
+gnet_unix_socket_new(const gchar *path)
+{
+	GUnixSocket *s = g_new0(GUnixSocket, 1);
+	struct sockaddr_un *sa_un;
+	
+	g_return_val_if_fail(path != NULL, NULL);
+	sa_un = (struct sockaddr_un *) &s->sa;
+	/* Create socket */
+	s->ref_count = 1;
+	s->server = FALSE;
+	s->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (s->sockfd < 0) {
+		g_free(s);
+		return NULL;
+	}
+	memcpy(sa_un->sun_path, path, strlen(path));
+	sa_un->sun_family = AF_UNIX;
+	if (connect(s->sockfd, &s->sa, sizeof(s->sa)) != 0) {
+		g_free(s);
+		return NULL;
+	}
+	return s;
+}
+
+/* gnet_unix_socket_delete:
+   @s: UnixSocket to delete.
+
+   Close and delete a GUnixSocket.
+ */
+
+void
+gnet_unix_socket_delete(GUnixSocket *s)
+{
+	if (s != NULL)
+		gnet_unix_socket_unref(s);
+}
+
+/* gnet_unix_socket_ref
+   @s: GUnixSocket to reference
+
+   Increment the reference counter of the GUnixSocket.
+ */
+void
+gnet_unix_socket_ref(GUnixSocket *s)
+{
+	g_return_if_fail(s != NULL);
+	++s->ref_count;
+}
+
+/* gnet_unix_socket_unref
+   @s: GUnixSocket to unreference
+
+   Remove a reference from the GUnixSocket.  When the reference count
+   reaches 0, the socket is deleted.
+ */
+void
+gnet_unix_socket_unref(GUnixSocket *s)
+{
+	g_return_if_fail(s != NULL);
+
+	--s->ref_count;
+
+	if (s->ref_count == 0) {
+		GNET_CLOSE_SOCKET(s->sockfd); /* Don't care if this fails */
+		if (s->iochannel)
+			g_io_channel_unref(s->iochannel);
+		if (s->server) {
+			struct stat buf;
+			if (stat(gnet_unix_socket_get_path(s), &buf) == 0) {
+				if (S_ISSOCK(buf.st_mode)) {
+					/* FIXME */
+					unlink(gnet_unix_socket_get_path(s));
+				}
+			}
+		} 
+		g_free(s);
+	}
+}
+    
+/* gnet_unix_socket_get_iochannel
+   @socket: GUnixSocket to get GIOChannel from.
+
+   Get the GIOChannel for the GUnixSocket.
+
+   For a client socket, the GIOChannel represents the data stream.  Use it
+   like you would any other GIOChannel.
+
+   For a server socket, however, the GIOChannel represents incoming
+   connections.  If you can read from it, there's a connection waiting to
+   be accepted.
+
+   There is one channel for every socket.  This function refs the
+   channel before returning it.  You should unref the channel when you are
+   done with it.  However, you should not close the channel - this is done
+   when you delete the socket.
+
+   Returns: A GIOChannel; NULL on failure.
+ */
+GIOChannel *
+gnet_unix_socket_get_iochannel(GUnixSocket *socket)
+{
+	g_return_val_if_fail(socket != NULL, NULL);
+
+	if (socket->iochannel == NULL)
+		socket->iochannel = GNET_SOCKET_IOCHANNEL_NEW(socket->sockfd);
+	g_io_channel_ref(socket->iochannel);
+	return socket->iochannel;
+}
+
+/* gnet_unix_socket_get_path:
+   @socket: GUnixSocket to get the path of.
+
+   Get the path of the socket.
+
+   Returns: gchar *path to socket; NULL on failure.
+ */
+gchar *
+gnet_unix_socket_get_path(const GUnixSocket *socket)
+{
+	struct sockaddr_un *sa_un;
+	g_return_val_if_fail(socket != NULL, NULL);
+	sa_un = (struct sockaddr_un *) &socket->sa;
+	return sa_un->sun_path;
+}
+
+/* gnet_unix_socket_server_new:
+   @path: Path for the socket.
+
+   Create and open a new GUnixSocket with the specified path.
+   Use this sort of socket when you are a server.
+
+   Returns: a new GUnixSocket, or NULL if there was a failure.
+ */
+GUnixSocket *
+gnet_unix_socket_server_new(gchar *path)
+{
+	struct sockaddr_un *sa_un;
+	GUnixSocket *s;
+	gint flags;
+	socklen_t n;
+
+	g_return_val_if_fail(path != NULL, NULL);
+	
+	s = g_new0(GUnixSocket, 1);
+	sa_un = (struct sockaddr_un *) &s->sa;
+	sa_un->sun_family = AF_UNIX;
+	memcpy(sa_un->sun_path, path, strlen(path));
+	s->ref_count = 1;
+	s->server = TRUE;
+	s->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (s->sockfd < 0)
+		goto error;
+
+	flags = fcntl(s->sockfd, F_GETFL, 0);
+	if (flags == -1)
+		goto error;
+	/* Make the socket non-blocking */
+	if (fcntl(s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
+		goto error;
+
+	if (bind(s->sockfd, &s->sa, sizeof(s->sa)) != 0)
+		goto error;
+
+	n = sizeof(s->sa);
+	/* Get the socket name FIXME: why? */
+	if (getsockname(s->sockfd, &s->sa, &n) != 0)
+		goto error;
+
+	if (listen(s->sockfd, 10) != 0)
+		goto error;
+
+	return s;
+	
+ error:
+	if (s)
+		g_free(s);
+	return NULL;
+}
+
+/* gnet_unix_socket_server_accept:
+   @socket: GUnixSocket to accept connections from
+
+   Accept connections from the socket.  The socket must have been created
+   using gnet_unix_socket_server_new();  This function will block (use
+   gnet_unix_socket_server_accept_nonblock() if you don't want to block).
+   If the socket's GIOChannel is readable, it DOES NOT mean that this function
+   will block.
+
+   Returns: a new GUnixSocket if there is another connect, or NULL if
+   there's an error.
+ */
+GUnixSocket *
+gnet_unix_socket_server_accept(const GUnixSocket *socket)
+{
+	gint sockfd;
+	struct sockaddr sa;
+	fd_set fdset;
+	socklen_t n;
+	GUnixSocket *s;
+
+	g_return_val_if_fail(socket != NULL, NULL);
+
+ try_again:
+	FD_ZERO(&fdset);
+	FD_SET(socket->sockfd, &fdset);
+
+	if (select(socket->sockfd + 1, &fdset, NULL, NULL, NULL) == -1) {
+		if (errno == EINTR)
+			goto try_again;
+		return NULL;
+	}
+	n = sizeof(s->sa);
+	if ((sockfd = accept(socket->sockfd, &sa, &n)) == -1) {
+		if (errno == EWOULDBLOCK ||
+		    errno == ECONNABORTED ||
+#ifdef EPROTO		/* OpenBSD does not have EPROTO */
+		    errno == EPROTO ||
+#endif /* EPROTO */
+		    errno == EINTR)
+			goto try_again;
+		return NULL;
+	}
+	s = g_new0(GUnixSocket, 1);
+	s->ref_count = 1;
+	s->sockfd = sockfd;
+	memcpy(&s->sa, &sa, sizeof(s->sa));
+	return s;
+}
+
+/* gnet_unix_socket_server_accept_nonblock:
+   @socket: GUnixSocket to accept connections from.
+
+   Accept a connection from the socket without blocking.  The socket
+   must have been created using gnet_unix_socket_server_new().  This
+   function is best used with the sockets GIOChannel.  If the channel is
+   readable, then you PROBABLY have a connection.  It is possible for the
+   connection to close by the time you call this, so it may return NULL even
+   if the channel was readable.
+
+   Returns a new GUnixSocket if there was another connect, or NULL otherwise.
+ */
+GUnixSocket *
+gnet_unix_socket_server_accept_nonblock(const GUnixSocket *socket)
+{
+	gint sockfd;
+	struct sockaddr sa;
+	fd_set fdset;
+	socklen_t n;
+	GUnixSocket *s;
+	struct timeval tv = {0, 0};
+
+	g_return_val_if_fail (socket != NULL, NULL);
+
+ try_again:
+	FD_ZERO(&fdset);
+	FD_SET(socket->sockfd, &fdset);
+
+	if(select(socket->sockfd + 1, &fdset, NULL, NULL, &tv) == -1) {
+		if (errno == EINTR)
+			goto try_again;
+		return NULL;
+	}
+
+	n = sizeof(sa);
+	
+	if ((sockfd = accept(socket->sockfd, &sa, &n)) == -1) {
+		/* If we get an error, return.  We don't want to try again
+		   as we do in gnet_unix_socket_server_accept() - it might
+		   cause a block. */
+		return NULL;
+	}
+
+	s = g_new0(GUnixSocket, 1);
+	s->ref_count = 1;
+	s->sockfd = sockfd;
+	memcpy(&s->sa, &sa, sizeof(s->sa));
+
+	return s;
+}
diff -ruN gnet-1.1.0/src/unix.h gnet-1.1.0-unix/src/unix.h
--- gnet-1.1.0/src/unix.h	Wed Dec 31 16:00:00 1969
+++ gnet-1.1.0-unix/src/unix.h	Thu Oct 18 23:01:10 2001
@@ -0,0 +1,72 @@
+/* GNet - Networking library
+ * Copyright (C) 2000  David Helder
+ * Copyright (C) 2001  Mark Ferlatte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _GNET_UNIX_H
+#define _GNET_UNIX_H
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+   All fields in GUnixSocket are private and should be accessed only by
+   using the functions below.
+ */
+typedef struct _GUnixSocket GUnixSocket;
+
+/* Quick and easy blocking constructor */
+GUnixSocket *
+gnet_unix_socket_connect(const gchar *path);
+
+/* Blocking constructor */
+GUnixSocket *
+gnet_unix_socket_new(const gchar *path);
+
+void
+gnet_unix_socket_delete(GUnixSocket *s);
+
+void
+gnet_unix_socket_ref(GUnixSocket *s);
+
+void
+gnet_unix_socket_unref(GUnixSocket *s);
+
+GIOChannel *
+gnet_unix_socket_get_iochannel(GUnixSocket *socket);
+
+gchar *
+gnet_unix_socket_get_path(const GUnixSocket *socket);
+
+GUnixSocket *
+gnet_unix_socket_server_new(gchar *path);
+
+GUnixSocket *
+gnet_unix_socket_server_accept(const GUnixSocket *socket);
+
+GUnixSocket *
+gnet_unix_socket_server_accept_nonblock(const GUnixSocket *socket);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _GNET_UNIX_H */
diff -ruN gnet-1.1.0/tests/Makefile.in gnet-1.1.0-unix/tests/Makefile.in
--- gnet-1.1.0/tests/Makefile.in	Thu May 24 18:33:00 2001
+++ gnet-1.1.0-unix/tests/Makefile.in	Thu Oct 18 23:21:21 2001
@@ -264,24 +264,6 @@
 	    || cp -p $$d/$$file $(distdir)/$$file || :; \
 	  fi; \
 	done
-dnstest.o: dnstest.c ../src/gnet.h ../gnetconfig.h ../src/inetaddr.h \
-	../src/iochannel.h ../src/udp.h ../src/mcast.h ../src/tcp.h \
-	../src/pack.h ../src/url.h ../src/conn.h ../src/server.h \
-	../src/md5.h ../src/sha.h
-hash.o: hash.c ../config.h ../src/gnet.h ../gnetconfig.h \
-	../src/inetaddr.h ../src/iochannel.h ../src/udp.h \
-	../src/mcast.h ../src/tcp.h ../src/pack.h ../src/url.h \
-	../src/conn.h ../src/server.h ../src/md5.h ../src/sha.h
-hostinfo.o: hostinfo.c ../src/gnet.h ../gnetconfig.h ../src/inetaddr.h \
-	../src/iochannel.h ../src/udp.h ../src/mcast.h ../src/tcp.h \
-	../src/pack.h ../src/url.h ../src/conn.h ../src/server.h \
-	../src/md5.h ../src/sha.h
-pack.o: pack.c ../src/pack.h
-unpack.o: unpack.c ../src/gnet.h ../gnetconfig.h ../src/inetaddr.h \
-	../src/iochannel.h ../src/udp.h ../src/mcast.h ../src/tcp.h \
-	../src/pack.h ../src/url.h ../src/conn.h ../src/server.h \
-	../src/md5.h ../src/sha.h
-
 info-am:
 info: info-am
 dvi-am:


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