[PATCH] Socket::create: Add support for Unix domain sockets

Carl Worth cworth at cworth.org
Thu Jan 31 14:25:19 PST 2008


---
 builtin-sockets.c |  127 +++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 85 insertions(+), 42 deletions(-)

diff --git a/builtin-sockets.c b/builtin-sockets.c
index 32cec13..47b6ab1 100644
--- a/builtin-sockets.c
+++ b/builtin-sockets.c
@@ -16,6 +16,8 @@
 #include	<fcntl.h>
 #include	<sys/types.h>
 #include	<sys/socket.h>
+#include	<sys/un.h>
+#include	<limits.h>
 #include        <netinet/in.h>
 #include	<netdb.h>
 #include	<string.h>
@@ -32,7 +34,7 @@
 NamespacePtr SocketNamespace;
 Type	     *typeSockaddr;

-Value do_Socket_create (Value type);
+Value do_Socket_create (Value family, Value type);
 Value do_Socket_connect (Value s, Value host, Value port);
 Value do_Socket_bind (Value s, Value host, Value port);
 Value do_Socket_listen (Value s, Value backlog);
@@ -55,12 +57,6 @@ import_Socket_namespace()
     };

     static const struct fbuiltin_1 funcs_1[] = {
-        { do_Socket_create, "create", "f", "i", "\n"
-	    " file create (int type)\n"
-	    "\n"
-	    " Create a socket where 'type' is one of:\n"
-	    "   SOCK_STREAM:	a stream socket.\n"
-	    "   SOCK_DGRAM:	a datagram socket.\n" },
         { do_Socket_accept, "accept", "f", "f", "\n"
 	    " file accept (file listen)\n"
 	    "\n"
@@ -73,6 +69,16 @@ import_Socket_namespace()
     };

     static const struct fbuiltin_2 funcs_2[] = {
+        { do_Socket_create, "create", "f", "ii", "\n"
+	    " file create (int type)\n"
+	    "\n"
+	    " Create a socket where 'family' is one of:\n"
+	    "   AF_UNIX:	Local communication.\n"
+	    "   AF_INET:	IPv4 Internet protocols.\n"
+	    "   AF_INET6:	IPv6 Internet protocols.\n"
+	    " and where 'type' is one of:\n"
+	    "   SOCK_STREAM:	a stream socket.\n"
+	    "   SOCK_DGRAM:	a datagram socket.\n" },
         { do_Socket_listen, "listen", "v", "fi", "\n"
 	    " void listen (file socket, int length)\n"
 	    "\n"
@@ -100,6 +106,11 @@ import_Socket_namespace()
     };

     static const struct ibuiltin ivars[] = {
+	{ AF_UNIX, "AF_UNIX", &SocketNamespace },
+	{ AF_INET, "AF_INET", &SocketNamespace },
+#ifdef AF_INET6
+	{ AF_INET6, "AF_INET6", &SocketNamespace },
+#endif
 	{ SOCK_STREAM, "SOCK_STREAM", &SocketNamespace },
 	{ SOCK_DGRAM, "SOCK_DGRAM", &SocketNamespace },
 	{ SHUT_RD, "SHUT_RD", &SocketNamespace },
@@ -143,21 +154,32 @@ import_Socket_namespace()

 /* File::file do_Socket_create ({SOCK_STREAM,SOCK_DGRAM} type); */
 Value
-do_Socket_create (Value type)
+do_Socket_create (Value family, Value type)
 {
     ENTER ();
-    int itype, s;
+    int ifamily, itype, s;
+    ifamily = IntPart (family, "Illegal address family");
     itype = IntPart (type, "Illegal socket type");
     if (aborting)
 	RETURN (Void);
-    s = socket (PF_INET, itype, 0);
+    s = socket (ifamily, itype, 0);
     if (s == -1)
 	RETURN (Void);
     RETURN (FileCreate (s, FileReadable|FileWritable));
 }

-static Bool address_lookup (Value hostname, Value portname,
-			    struct sockaddr_in *addr)
+typedef union {
+    struct sockaddr_in in;
+    struct sockaddr_un un;
+    struct sockaddr addr;
+    struct {
+	struct sockaddr_un un;
+	char path[PATH_MAX];
+    } align;
+} sockaddr_all_t;
+
+static Bool address_lookup (int s, Value hostname, Value portname,
+			    sockaddr_all_t *addr, socklen_t *len)
 {
     struct hostent *host;
     struct servent *port;
@@ -176,32 +198,51 @@ static Bool address_lookup (Value hostname, Value portname,
     if (*hostchars == '\0' || *portchars == '\0')
 	return False; /* FIXME: more here? */

-    addr->sin_family = AF_INET;
-
-    /* host lookup */
-    host = gethostbyname (hostchars);
-    if (host == 0)
-    {
-	herror ("address_lookup");
-	return False; /* FIXME: more here? */
-    }
-    memcpy (&addr->sin_addr.s_addr, host->h_addr_list[0], sizeof addr->sin_addr.s_addr);
+    /* Read the address family back from the kernel. */
+    *len = sizeof (*addr);
+    if (getsockname (s, &addr->addr, len) < 0)
+	return False;

-    /* port lookup */
-    portnum = strtol (portchars, &endptr, /* base */ 10);
-    if (*endptr != '\0') /* non-numeric port specification */
-    {
-	/* FIXME: this should not always be "tcp"! */
-	port = getservbyname (portchars, "tcp");
-	if (port == 0)
-	    return False; /* FIXME: more here? */
-	addr->sin_port = port->s_port;
-    }
-    else
-    {
-	if (portnum <= 0 || portnum >= (1 << 16))
+    switch (addr->addr.sa_family) {
+    case AF_UNIX:
+	if (strlen (portchars) > PATH_MAX)
+	    return False;
+	*len = SUN_LEN (&addr->un);
+	strcpy (addr->un.sun_path, portchars);
+	break;
+    case AF_INET:
+	/* host lookup */
+	host = gethostbyname (hostchars);
+	if (host == 0)
+	{
+	    herror ("address_lookup");
 	    return False; /* FIXME: more here? */
-	addr->sin_port = htons (portnum);
+	}
+	memcpy (&addr->in.sin_addr.s_addr, host->h_addr_list[0], sizeof addr->in.sin_addr.s_addr);
+
+	/* port lookup */
+	portnum = strtol (portchars, &endptr, /* base */ 10);
+
+	if (*endptr != '\0') /* non-numeric port specification */
+	{
+	    /* FIXME: this should not always be "tcp"! */
+	    port = getservbyname (portchars, "tcp");
+	    if (port == 0)
+		return False; /* FIXME: more here? */
+	    addr->in.sin_port = port->s_port;
+	}
+	else
+	{
+	    if (portnum <= 0 || portnum >= (1 << 16))
+		return False; /* FIXME: more here? */
+	    addr->in.sin_port = htons (portnum);
+	}
+	break;
+#if AF_INET6
+    case AF_INET6:
+#endif
+    default:
+	return False;
     }

     return True;
@@ -212,9 +253,10 @@ Value
 do_Socket_connect (Value s, Value host, Value port)
 {
     ENTER ();
-    struct sockaddr_in addr;
+    sockaddr_all_t addr;
+    socklen_t len;

-    if (!address_lookup (host, port, &addr))
+    if (!address_lookup (s->file.fd, host, port, &addr, &len))
 	RETURN (Void);

     if (!running->thread.partial)
@@ -230,7 +272,7 @@ do_Socket_connect (Value s, Value host, Value port)
 			(char *) &one, sizeof (int));
 	}
 #endif
-	n = connect (s->file.fd, (struct sockaddr *) &addr, sizeof addr);
+	n = connect (s->file.fd, &addr.addr, len);
 	flags &= ~O_NONBLOCK;
 	fcntl (s->file.fd, F_SETFL, flags);
 	err = errno;
@@ -266,9 +308,10 @@ Value
 do_Socket_bind (Value s, Value host, Value port)
 {
     ENTER ();
-    struct sockaddr_in addr;
+    sockaddr_all_t addr;
+    socklen_t len;

-    if (!address_lookup (host, port, &addr))
+    if (!address_lookup (s->file.fd, host, port, &addr, &len))
 	RETURN (Void);

 #ifdef SO_REUSEADDR
@@ -277,7 +320,7 @@ do_Socket_bind (Value s, Value host, Value port)
 	setsockopt (s->file.fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (int));
     }
 #endif
-    if (bind (s->file.fd, (struct sockaddr *) &addr, sizeof addr) == -1)
+    if (bind (s->file.fd, &addr.addr, len) == -1)
     {
 	RaiseStandardException (exception_io_error,
 				FileGetErrorMessage (errno),
--
1.5.3.2




More information about the Nickle mailing list