bug-bash
[Top][All Lists]
Advanced

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

Suggestion and patch for tcp-server-sockets


From: Ralf Goertz
Subject: Suggestion and patch for tcp-server-sockets
Date: Fri, 8 Jun 2007 12:52:47 +0200
User-agent: KMail/1.9.7

Hi,

the other day I asked for a reason why there are no server sockets for
bash. Since I got no answer, I decided to do it myself. I included a
patch against the unpatched 3.2 file lib/sh/netopen.c (I think that file
has not been patched by any of the 17 official patches). I think it is
not reasonable to have udp-server-sockets so I omitted them (it would
have been much more complicated to include them anyway).

Now, if you want to open a server socket just do

exec 5<>/dev/tcp//port

Here is the patch


--- bash-3.2/lib/sh/netopen.c   2006-08-02 23:20:30.000000000 +0200
+++ bash-3.2-serversocketpatch/lib/sh/netopen.c 2007-06-08 
12:14:46.000000000 +0200
@@ -70,8 +70,10 @@
 static int _getaddr __P((char *, struct in_addr *));
 static int _getserv __P((char *, int, unsigned short *));
 static int _netopen4 __P((char *, char *, int));
+static int _netopenserver4 __P((char *));
 #else /* HAVE_GETADDRINFO */
 static int _netopen6 __P((char *, char *, int));
+static int _netopenserver6 __P((char *));
 #endif
 
 static int _netopen __P((char *, char *, int));
@@ -200,6 +202,65 @@
 
   return(s);
 }
+
+static int 
+_netopenserver4(serv)
+     char *serv;
+{
+  struct sockaddr_in sin;
+  unsigned short p;
+  int s, e, ls, sockopt; /*ls is the listening socket */
+  struct linger fix_ling; /* as suggested by netcat */
+  char *errstring, *errstrings[]={"bind","listen","accept"};
+
+  if (_getserv(serv, 't', &p) == 0)
+    {
+      internal_error(_("%s: invalid service"), serv);
+      errno = EINVAL;
+      return -1;
+    }
+       
+  memset ((char *)&sin, 0, sizeof(sin));
+  sin.sin_family = AF_INET;
+  sin.sin_port = p;
+
+  ls = socket(AF_INET, SOCK_STREAM, 0);
+  if (ls < 0)
+    {
+      sys_error ("socket");
+      return (-1);
+    }
+  if (setsockopt(ls, SOL_SOCKET, SO_LINGER, &fix_ling, sizeof(fix_ling) 
< 0)); /* FIXME what to do if this fails */
+  if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt) 
< 0)); /* FIXME what to do if this fails */
+  
+  if (bind(ls, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+    {
+      errstring=errstrings[0];
+      goto err;
+    }
+  
+  if (listen(ls,1) < 0)
+    {
+      errstring=errstrings[1];
+      goto err;
+    }
+  
+  s = accept(ls,NULL,NULL);
+  if (s<0) 
+    {
+      errstring=errstrings[2];
+      goto err;
+    }
+  close(ls);
+  return(s);
+err:
+  e = errno;
+  sys_error(errstring);
+  close(ls);
+  errno = e;
+  return (-1);
+}
+
 #endif /* ! HAVE_GETADDRINFO */
 
 #ifdef HAVE_GETADDRINFO
@@ -266,6 +327,95 @@
     }
   return s;
 }
+/*
+ * Open a TCP server socket on port SERV.  Uses getaddrinfo(3) which
+ * provides support for IPv6.  Returns the connected socket or -1 on
+ * error.
+ */
+static int
+_netopenserver6 (serv)
+     char *serv;
+{
+  int s, e, ls, sockopt; /* ls is the listening socket */
+  struct linger fix_ling; /* as suggested by netcat */
+  struct addrinfo hints, *res, *res0;
+  int gerr,retval;
+  char *errstring, *errstrings[]={"bind","listen","accept"};
+
+  memset ((char *)&hints, 0, sizeof (hints));
+  /* XXX -- if problems with IPv6, set to PF_INET for IPv4 only */
+#ifdef DEBUG   /* PF_INET is the one that works for me */
+  hints.ai_family = PF_INET;
+#else
+  hints.ai_family = PF_UNSPEC;
+#endif
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_PASSIVE;
+  fix_ling.l_onoff = 1;
+  fix_ling.l_linger = 0;
+
+
+  gerr = getaddrinfo (NULL, serv, &hints, &res0);
+  if (gerr)
+    {
+      if (gerr == EAI_SERVICE)
+       internal_error ("%s: %s", serv, gai_strerror (gerr));
+      else
+       internal_error ("%s: %s", "localhost", gai_strerror (gerr));
+      errno = EINVAL;
+      return -1;
+    }
+
+  for (res = res0; res; res = res->ai_next)
+    {
+      if ((ls = socket (res->ai_family, res->ai_socktype, 
res->ai_protocol)) < 0)
+       {
+         if (res->ai_next)
+           continue;
+         sys_error ("socket");
+         freeaddrinfo (res0);
+         return -1;
+       }
+      retval = setsockopt(ls, SOL_SOCKET, SO_LINGER, &fix_ling, 
sizeof(fix_ling)); /* FIXME what to do if this fails */
+      retval = setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &sockopt, 
sizeof(sockopt)); /* FIXME what to do if this fails */
+      retval = bind(ls, res->ai_addr, res->ai_addrlen);
+      if (retval<0) 
+    {
+        errstring=errstrings[0];
+        goto err;
+    }
+      retval = listen(ls,1);
+      if (retval<0) 
+    {
+        errstring=errstrings[1];
+        goto err;
+    }
+      s = accept(ls,NULL,NULL);
+      if (s<0) 
+    {
+        errstring=errstrings[2];
+        goto err;
+    }
+      close(ls);
+      freeaddrinfo (res0);
+      break;
+       
+err:  
+      if (res->ai_next)
+           {
+             close (ls);
+             continue;
+           }
+         e = errno;
+         sys_error (errstring);
+         close (ls);
+         freeaddrinfo (res0);
+         errno = e;
+         return -1;
+   }
+  return s;
+}
+
 #endif /* HAVE_GETADDRINFO */
 
 /*
@@ -279,9 +429,15 @@
      int typ;
 {
 #ifdef HAVE_GETADDRINFO
-  return (_netopen6 (host, serv, typ));
+  if ((strlen(host) == 0) && (typ == 't')) /* /dev/tcp//serv */
+    return (_netopenserver6 (serv));
+  else 
+    return (_netopen6 (host, serv, typ));
 #else
-  return (_netopen4 (host, serv, typ));
+  if ((strlen(host) == 0) && (typ == 't')) /* /dev/tcp//serv */
+    return (_netopenserver4 (serv));
+  else 
+    return (_netopen4 (host, serv, typ));
 #endif
 }
 






reply via email to

[Prev in Thread] Current Thread [Next in Thread]