Re: [gnet-dev] Unix socket support
- From: Mark Ferlatte <ferlatte cryptio net>
- To: David Helder <dhelder umich edu>
- Cc: gnet-dev gnetlibrary org
- Subject: Re: [gnet-dev] Unix socket support
- Date: Thu, 18 Oct 2001 23:32:59 -0700
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]