This patch adds unix datagram socket support to nc(1).  It's basically
the same patch I sent last June (see
http://marc.info/?l=openbsd-tech&m=127627296925965&w=2), but updated
for -current.

Tested on amd64.  Doesn't appear to cause any regressions to existing
support, tested with unix stream and IP stream and datagram sockets.
Looking for OKs.

Jeremy

Index: atomicio.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/atomicio.c,v
retrieving revision 1.9
diff -u -p -r1.9 atomicio.c
--- atomicio.c  7 Sep 2007 14:50:44 -0000       1.9
+++ atomicio.c  6 Jan 2011 21:48:04 -0000
@@ -53,7 +53,7 @@ atomicio(ssize_t (*f) (int, void *, size
                case -1:
                        if (errno == EINTR)
                                continue;
-                       if (errno == EAGAIN) {
+                       if ((errno == EAGAIN) || (errno == ENOBUFS)) {
                                (void)poll(&pfd, 1, -1);
                                continue;
                        }
Index: netcat.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/netcat.c,v
retrieving revision 1.98
diff -u -p -r1.98 netcat.c
--- netcat.c    3 Jul 2010 04:44:51 -0000       1.98
+++ netcat.c    6 Jan 2011 21:48:04 -0000
@@ -89,6 +89,7 @@ u_int rtableid;
 int timeout = -1;
 int family = AF_UNSPEC;
 char *portlist[PORT_MAX+1];
+char *unix_dg_tmp_socket;
 
 void   atelnet(int, unsigned char *, unsigned int);
 void   build_ports(char *);
@@ -99,6 +100,7 @@ int  remote_connect(const char *, const c
 int    socks_connect(const char *, const char *, struct addrinfo,
            const char *, const char *, struct addrinfo, int, const char *);
 int    udptest(int);
+int    unix_bind(char *);
 int    unix_connect(char *);
 int    unix_listen(char *);
 void   set_common_sockopts(int);
@@ -241,8 +243,6 @@ main(int argc, char *argv[])
 
        /* Cruft to make sure options are clean, and used properly. */
        if (argv[0] && !argv[1] && family == AF_UNIX) {
-               if (uflag)
-                       errx(1, "cannot use -u and -U");
                host = argv[0];
                uport = NULL;
        } else if (argv[0] && !argv[1]) {
@@ -265,6 +265,18 @@ main(int argc, char *argv[])
        if (!lflag && kflag)
                errx(1, "must use -l with -k");
 
+       /* Get name of temporary socket for unix datagram client */
+       if ((family == AF_UNIX) && uflag && !lflag) {
+               if(pflag) {
+                       unix_dg_tmp_socket = pflag;
+               } else {
+                       if((unix_dg_tmp_socket = (char *)malloc(19)) == NULL)
+                               errx(1, "not enough memory");
+                       strlcpy(unix_dg_tmp_socket, "/tmp/nc.XXXXXXXXXX", 19);
+                       mktemp(unix_dg_tmp_socket);
+               }
+       }
+
        /* Initialize addrinfo structure. */
        if (family != AF_UNIX) {
                memset(&hints, 0, sizeof(struct addrinfo));
@@ -307,8 +319,12 @@ main(int argc, char *argv[])
                int connfd;
                ret = 0;
 
-               if (family == AF_UNIX)
-                       s = unix_listen(host);
+               if (family == AF_UNIX) {
+                       if(uflag)
+                               s = unix_bind(host);
+                       else
+                               s = unix_listen(host);
+               }
 
                /* Allow only one connection at a time, but stay alive. */
                for (;;) {
@@ -337,17 +353,19 @@ main(int argc, char *argv[])
                                if (rv < 0)
                                        err(1, "connect");
 
-                               connfd = s;
+                               readwrite(s);
                        } else {
                                len = sizeof(cliaddr);
                                connfd = accept(s, (struct sockaddr *)&cliaddr,
                                    &len);
+                               readwrite(connfd);
+                               close(connfd);
                        }
 
-                       readwrite(connfd);
-                       close(connfd);
                        if (family != AF_UNIX)
                                close(s);
+                       else if (uflag)
+                               connect(s, NULL, 0);
 
                        if (!kflag)
                                break;
@@ -361,6 +379,8 @@ main(int argc, char *argv[])
                } else
                        ret = 1;
 
+               if(uflag)
+                       unlink(unix_dg_tmp_socket);
                exit(ret);
 
        } else {
@@ -421,18 +441,19 @@ main(int argc, char *argv[])
 }
 
 /*
- * unix_connect()
- * Returns a socket connected to a local unix socket. Returns -1 on failure.
+ * unix_bind()
+ * Returns a unix socket bound to the given path
  */
 int
-unix_connect(char *path)
+unix_bind(char *path)
 {
        struct sockaddr_un sun;
        int s;
 
-       if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+       /* Create unix domain socket. */
+       if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
+            0)) < 0)
                return (-1);
-       (void)fcntl(s, F_SETFD, 1);
 
        memset(&sun, 0, sizeof(struct sockaddr_un));
        sun.sun_family = AF_UNIX;
@@ -443,27 +464,32 @@ unix_connect(char *path)
                errno = ENAMETOOLONG;
                return (-1);
        }
-       if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+
+       if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
                close(s);
                return (-1);
        }
        return (s);
-
 }
 
 /*
- * unix_listen()
- * Create a unix domain socket, and listen on it.
+ * unix_connect()
+ * Returns a socket connected to a local unix socket. Returns -1 on failure.
  */
 int
-unix_listen(char *path)
+unix_connect(char *path)
 {
        struct sockaddr_un sun;
        int s;
 
-       /* Create unix domain socket. */
-       if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
-               return (-1);
+       if (uflag) {
+               if((s = unix_bind(unix_dg_tmp_socket)) < 0)
+                       return (-1);
+       } else {
+               if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+                       return (-1);
+       }
+       (void)fcntl(s, F_SETFD, 1);
 
        memset(&sun, 0, sizeof(struct sockaddr_un));
        sun.sun_family = AF_UNIX;
@@ -474,11 +500,24 @@ unix_listen(char *path)
                errno = ENAMETOOLONG;
                return (-1);
        }
-
-       if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+       if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
                close(s);
                return (-1);
        }
+       return (s);
+
+}
+
+/*
+ * unix_listen()
+ * Create a unix domain socket, and listen on it.
+ */
+int
+unix_listen(char *path)
+{
+       int s;
+       if((s = unix_bind(path)) < 0)
+               return (-1);
 
        if (listen(s, 5) < 0) {
                close(s);

Reply via email to