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 } _______________________________________________ Bug-bash mailing list Bug-bash@gnu.org http://lists.gnu.org/mailman/listinfo/bug-bash