]> mj.ucw.cz Git - sock.git/blobdiff - sock.c
Release 1.1. See the ChangeLog.
[sock.git] / sock.c
diff --git a/sock.c b/sock.c
index cb574246d6746d8bf60c6a10a8974528c13eda42..f59f2c8f517ebf5903d0cf7401f75b1eace0b3b3 100644 (file)
--- a/sock.c
+++ b/sock.c
@@ -1,44 +1,43 @@
 /*
  *     Command-Line Socket Interface
  *
- *     (c) 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *     (c) 1998--2001 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  *
  *     This program can be freely distributed and used according
  *     to the terms of the GNU General Public Licence.
  */
 
-/*
- * FIXME: --version
- */
-
 #include "config.h"
 
+#include <sys/types.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include <getopt.h>
+#include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <sys/un.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
-#include <sys/signal.h>
+#include <signal.h>
 #include <sys/wait.h>
 #include <sys/time.h>
-#include <sys/types.h>
 
-static char *opts = "vtuxb:lde";
+#define SOCK_VERSION "1.1"
+
+static char *opts = "vtuxb:lden";
 
 static enum { ip, ux } addr = ip;
 static enum { deflt, tcp, udp, uxp } proto = deflt;
-static int listen_p, verbose, daemon_p, both_eof_p;
+static int listen_p, verbose, daemon_p, single_eof_p, avoid_dns_p;
 static char *cmd, *my_name;
 
-static struct sockaddr sa_bind, sa_conn;
+static struct sockaddr *sa_bind, *sa_conn;
 static char *na_bind, *na_conn;
-static int sa_bind_p;
+static int sock_addr_length;
 
 #ifdef __GNUC__
 #define NORET __attribute__((noreturn))
@@ -63,7 +62,8 @@ Usage: %s [-vtuxde] ([-b <local>] <remote> | -l <local>) [<command>]\n\
 -b\tBind local end to specified address\n\
 -l\tListening mode\n\
 -d\tDaemon mode (listen only) -- process multiple connections\n\
--e\tTerminate only if EOF seen in both directions\n\
+-e\tTerminate as soon as EOF is seen in any direction\n\
+-n\tAvoid reverse DNS lookups\n\
 ", my_name);
   exit(1);
 }
@@ -93,10 +93,31 @@ die(char *x, ...)
   exit(1);
 }
 
+static void *
+xmalloc(int size)
+{
+  void *x = malloc(size);
+  if (!x)
+    die("Out of memory");
+  return x;
+}
+
+static struct sockaddr *
+alloc_sockaddr(void)
+{
+  struct sockaddr *sa;
+  sock_addr_length = (addr == ux) ? sizeof(struct sockaddr_un) : sizeof(struct sockaddr_in);
+  sa = xmalloc(sock_addr_length);
+  memset(sa, 0, sizeof(*sa));
+  sa->sa_family = (addr == ux) ? AF_UNIX : AF_INET;
+  return sa;
+}
+
 static char *
-parse_addr(struct sockaddr *sa, char *a, int need_port, int need_addr)
+parse_addr(struct sockaddr **sap, char *a, int need_port, int need_addr)
 {
   char *o = a;
+  struct sockaddr *sa = alloc_sockaddr();
 
   switch (addr)
     {
@@ -110,6 +131,8 @@ parse_addr(struct sockaddr *sa, char *a, int need_port, int need_addr)
        else if (need_port)
          die("%s: port number required", a);
        s->sin_family = AF_INET;
+       if (!*a && need_addr)
+         a = "localhost";
        if (*a)
          {
            struct hostent *e = gethostbyname(a);
@@ -120,8 +143,6 @@ parse_addr(struct sockaddr *sa, char *a, int need_port, int need_addr)
            memcpy(&s->sin_addr, e->h_addr, sizeof(struct in_addr));
            o = e->h_name;
          }
-       else if (need_addr)
-         die("Host name required");
        if (p)
          {
            struct servent *e = NULL;
@@ -162,6 +183,7 @@ parse_addr(struct sockaddr *sa, char *a, int need_port, int need_addr)
        break;
       }
     }
+  *sap = sa;
   return o;
 }
 
@@ -173,10 +195,11 @@ name_addr(struct sockaddr *sa)
     case ip:
       {
        struct sockaddr_in *a = (struct sockaddr_in *) sa;
-       struct hostent *h = gethostbyaddr((char *) &a->sin_addr.s_addr, sizeof(struct in_addr), AF_INET);
-       if (!h)
-         mdie("xxx");
-       return h->h_name;
+       struct hostent *h = avoid_dns_p ? NULL : gethostbyaddr((char *) &a->sin_addr.s_addr, sizeof(struct in_addr), AF_INET);
+       if (h)
+         return h->h_name;
+       else
+         return inet_ntoa(a->sin_addr);
       }
     case ux:
       {
@@ -191,7 +214,7 @@ name_addr(struct sockaddr *sa)
 static RETSIGTYPE
 sigchld_handler(int sig)
 {
-  while (wait3(NULL, WNOHANG, NULL) > 0)
+  while (waitpid(-1, NULL, WNOHANG) > 0)
     ;
 }
 
@@ -200,7 +223,7 @@ setup_sigchld(void)
 {
   struct sigaction sa;
 
-  bzero(&sa, sizeof(sa));
+  memset(&sa, 0, sizeof(sa));
   sa.sa_handler = sigchld_handler;
   sa.sa_flags = SA_RESTART;
   if (sigaction(SIGCHLD, &sa, NULL) < 0)
@@ -237,8 +260,15 @@ gw(int sk)
       int n;
       fd_set in, out;
 
-      if (fcntl(0, F_SETFL, O_NDELAY) < 0 ||
-         fcntl(1, F_SETFL, O_NDELAY) < 0 ||
+      if (proto == udp)
+       {
+         if (listen_p)
+           ieof = 1;
+         else
+           oeof = 1;
+       }
+      if (!ieof && fcntl(0, F_SETFL, O_NDELAY) < 0 ||
+         !oeof && fcntl(1, F_SETFL, O_NDELAY) < 0 ||
          fcntl(sk, F_SETFL, O_NDELAY) < 0)
        mdie("fcntl");
       FD_ZERO(&in);
@@ -259,7 +289,7 @@ gw(int sk)
              ieof = 2;
            }
          if (ibr == ib && obr == ob &&
-             (both_eof_p ? (ieof && oeof) : (ieof || oeof)))
+             (single_eof_p ? (ieof || oeof) : (ieof && oeof)))
            break;
          if (select(sk+1, &in, &out, NULL, NULL) < 0)
            mdie("select");
@@ -314,6 +344,12 @@ main(int argc, char **argv)
 {
   int c, sk;
 
+  if (argc == 2 && !strcmp(argv[1], "--version"))
+    {
+      puts("This is sock " SOCK_VERSION ". Be happy.");
+      return 0;
+    }
+
   my_name = argv[0];
   while ((c = getopt(argc, argv, opts)) > 0)
     switch (c)
@@ -325,25 +361,33 @@ main(int argc, char **argv)
        daemon_p++;
        break;
       case 't':
+       if (proto != deflt)
+         usage();
        proto = tcp;
        break;
       case 'u':
+       if (proto != deflt)
+         usage();
        proto = udp;
        break;
       case 'x':
-       addr = ux;
+       if (proto != deflt)
+         usage();
        proto = uxp;
        break;
       case 'l':
        listen_p++;
        break;
       case 'b':
-       if (sa_bind_p++)
+       if (na_bind)
          usage();
-       na_bind = parse_addr(&sa_bind, optarg, 0, 0);
+       na_bind = optarg;
        break;
       case 'e':
-       both_eof_p++;
+       single_eof_p++;
+       break;
+      case 'n':
+       avoid_dns_p++;
        break;
       default:
        usage();
@@ -354,15 +398,21 @@ main(int argc, char **argv)
   else if (argc != optind + 1)
     usage();
 
+  if (proto == uxp)
+    addr = ux;
+
   if (listen_p)
     {
-      if (sa_bind_p)
+      if (na_bind)
        usage();
       na_bind = parse_addr(&sa_bind, argv[optind], 1, 0);
-      sa_bind_p = 1;
     }
   else
-    na_conn = parse_addr(&sa_conn, argv[optind], 1, 1);
+    {
+      if (na_bind)
+       na_bind = parse_addr(&sa_bind, na_bind, 0, 0);
+      na_conn = parse_addr(&sa_conn, argv[optind], 1, 1);
+    }
 
   switch (proto)
     {
@@ -381,31 +431,38 @@ main(int argc, char **argv)
     }
   if (sk < 0)
     mdie("socket");
-  if (sa_bind_p)
+  if (sa_bind)
     {
       int one = 1;
-      if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
+      if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one)) < 0)
        mdie("setsockopt(SO_REUSEADDR)");
-      if (bind(sk, &sa_bind, sizeof(sa_bind)) < 0)
+      if (bind(sk, sa_bind, sock_addr_length) < 0)
        mdie("bind");
     }
 
   if (listen_p)
     {
-      int l = sizeof(sa_conn);
+      struct sockaddr *sa_incoming;
       if (verbose)
        fprintf(stderr, "Listening on %s\n", na_bind);
+      if (proto == udp)
+       {
+         gw(sk);
+         return 0;
+       }
       if (listen(sk, (daemon_p ? 10 : 1)) < 0)
        mdie("listen");
       if (cmd && daemon_p)
        setup_sigchld();
+      sa_incoming = alloc_sockaddr();
       for(;;)
        {
-         int ns = accept(sk, &sa_conn, &l);
+         int l = sock_addr_length;
+         int ns = accept(sk, sa_incoming, &l);
          if (ns < 0)
            mdie("accept");
          if (verbose)
-           fprintf(stderr, "Got connection from %s\n", name_addr(&sa_conn));
+           fprintf(stderr, "Got connection from %s\n", name_addr(sa_incoming));
          if (!daemon_p)
            {
              close(sk);
@@ -433,7 +490,7 @@ main(int argc, char **argv)
     {
       if (verbose)
        fprintf(stderr, "Connecting to %s\n", na_conn);
-      if (connect(sk, &sa_conn, sizeof(sa_conn)) < 0)
+      if (connect(sk, sa_conn, sock_addr_length) < 0)
        mdie("connect");
       gw(sk);
     }