diff -bru gawk-3.1.5.orig/io.c gawk-3.1.5/io.c --- gawk-3.1.5.orig/io.c 2006-07-07 16:13:08.000000000 +0200 +++ gawk-3.1.5/io.c 2006-07-10 13:18:13.000000000 +0200 @@ -71,7 +71,6 @@ extern int MRL; #ifdef HAVE_SOCKETS -enum inet_prot { INET_NONE, INET_TCP, INET_UDP, INET_RAW }; #ifndef SHUT_RD #define SHUT_RD 0 @@ -1133,24 +1132,60 @@ /* socketopen --- open a socket and set it into connected state */ static int -socketopen(enum inet_prot type, int localport, int remoteport, const char *remotehostname) +socketopen(int type, const char *localpname, const char *remotepname, + const char *remotehostname) { - struct hostent *hp = gethostbyname(remotehostname); - struct sockaddr_in local_addr, remote_addr; + struct addrinfo *lres, *lres0; + struct addrinfo lhints; + struct addrinfo *rres, *rres0; + struct addrinfo rhints; + + int lerror; + int rerror; + int socket_fd; int any_remote_host = strcmp(remotehostname, "0"); + memset (&lhints, '\0', sizeof (lhints)); + lhints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + lhints.ai_socktype = type; + + lerror = getaddrinfo (NULL, localpname, &lhints, &lres); + if (lerror) { + if (strcmp(localpname, "0")) + fatal(_("local port invalid in `/inet'")); + lres0 = NULL; + lres = &lhints; + } else + lres0 = lres; + + while (lres) { + memset (&rhints, '\0', sizeof (rhints)); + rhints.ai_flags = lhints.ai_flags; + rhints.ai_socktype = lhints.ai_socktype; + rhints.ai_family = lhints.ai_family; + rhints.ai_protocol = lhints.ai_protocol; + + rerror = getaddrinfo (remotehostname, remotepname, &rhints, &rres); + if (rerror) { + if (lres0) + freeaddrinfo(lres0); + fatal(_("remote host and port information invalid")); + } + rres0 = rres; socket_fd = INVALID_HANDLE; - switch (type) { - case INET_TCP: - if (localport != 0 || remoteport != 0) { + while (rres) { + socket_fd = socket (rres->ai_family, + rres->ai_socktype, rres->ai_protocol); + if (socket_fd < 0 || socket_fd == INVALID_HANDLE) + goto nextrres; + + if (type == SOCK_STREAM) { int on = 1; #ifdef SO_LINGER struct linger linger; - memset(& linger, '\0', sizeof(linger)); #endif - socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *) & on, sizeof(on)); #ifdef SO_LINGER @@ -1160,57 +1195,27 @@ (char *) & linger, sizeof(linger)); #endif } - break; - case INET_UDP: - if (localport != 0 || remoteport != 0) - socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - break; - case INET_RAW: -#ifdef SOCK_RAW - if (localport == 0 && remoteport == 0) - socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); -#endif - break; - case INET_NONE: - /* fall through */ - default: - cant_happen(); - break; - } + if (bind(socket_fd, lres->ai_addr, lres->ai_addrlen) != 0) + goto nextrres; - if (socket_fd < 0 || socket_fd == INVALID_HANDLE - || (hp == NULL && any_remote_host != 0)) - return INVALID_HANDLE; - - local_addr.sin_family = remote_addr.sin_family = AF_INET; - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - remote_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = htons(localport); - remote_addr.sin_port = htons(remoteport); - if (bind(socket_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == 0) { if (any_remote_host != 0) { /* not ANY => create a client */ - if (type == INET_TCP || type == INET_UDP) { - memcpy(&remote_addr.sin_addr, hp->h_addr, - sizeof(remote_addr.sin_addr)); - if (connect(socket_fd, - (struct sockaddr *) &remote_addr, - sizeof(remote_addr)) != 0) { - close(socket_fd); - if (localport == 0) - socket_fd = INVALID_HANDLE; - else - socket_fd = socketopen(type, localport, 0, "0"); - } + if (type != SOCK_RAW) { + if (connect(socket_fd, rres->ai_addr, + rres->ai_addrlen) == 0) + break; } else { /* /inet/raw client not ready yet */ fatal(_("/inet/raw client not ready yet, sorry")); if (geteuid() != 0) + /* FIXME: is this second fatal ever reached? */ fatal(_("only root may use `/inet/raw'.")); } } else { /* remote host is ANY => create a server */ - if (type == INET_TCP) { + if (type == SOCK_STREAM) { int clientsocket_fd = INVALID_HANDLE; - socklen_t namelen = sizeof(remote_addr); + + struct sockaddr_storage remote_addr; + socklen_t namelen = sizeof (remote_addr); if (listen(socket_fd, 1) >= 0 && (clientsocket_fd = accept(socket_fd, @@ -1218,25 +1223,22 @@ &namelen)) >= 0) { close(socket_fd); socket_fd = clientsocket_fd; - } else { - close(socket_fd); - socket_fd = INVALID_HANDLE; + break; } - } else if (type == INET_UDP) { + } else if (type == SOCK_DGRAM) { #ifdef MSG_PEEK char buf[10]; + struct sockaddr_storage remote_addr; socklen_t readle; if (recvfrom(socket_fd, buf, 1, MSG_PEEK, (struct sockaddr *) & remote_addr, - & readle) < 1 - || readle != sizeof(remote_addr) - || connect(socket_fd, + & readle) >= 0 + && readle + && connect(socket_fd, (struct sockaddr *)& remote_addr, - readle) != 0) { - close(socket_fd); - socket_fd = INVALID_HANDLE; - } + readle) == 0) + break; #endif } else { /* /inet/raw server not ready yet */ @@ -1245,10 +1247,20 @@ fatal(_("only root may use `/inet/raw'.")); } } - } else { + +nextrres: + if (socket_fd != INVALID_HANDLE) close(socket_fd); socket_fd = INVALID_HANDLE; + rres = rres->ai_next; + } + freeaddrinfo(rres0); + if (socket_fd != INVALID_HANDLE) + break; + lres = lres->ai_next; } + if (lres0) + freeaddrinfo(lres0); return socket_fd; } @@ -1313,30 +1325,24 @@ } else if (STREQN(name, "/inet/", 6)) { #ifdef HAVE_SOCKETS /* /inet/protocol/localport/hostname/remoteport */ - enum inet_prot protocol = INET_NONE; - int localport, remoteport; + int protocol; char *hostname; char *hostnameslastcharp; char *localpname; - char proto[4]; - struct servent *service; + char *localpnamelastcharp; cp = (char *) name + 6; /* which protocol? */ if (STREQN(cp, "tcp/", 4)) - protocol = INET_TCP; + protocol = SOCK_STREAM; else if (STREQN(cp, "udp/", 4)) - protocol = INET_UDP; + protocol = SOCK_DGRAM; else if (STREQN(cp, "raw/", 4)) - protocol = INET_RAW; + protocol = SOCK_RAW; else fatal(_("no (known) protocol supplied in special filename `%s'"), name); - proto[0] = cp[0]; - proto[1] = cp[1]; - proto[2] = cp[2]; - proto[3] = '\0'; cp += 4; /* which localport? */ @@ -1354,25 +1360,17 @@ * By using atoi() the use of decimal numbers is enforced. */ *cp = '\0'; - - localport = atoi(localpname); - if (strcmp(localpname, "0") != 0 - && (localport <= 0 || localport > 65535)) { - service = getservbyname(localpname, proto); - if (service == NULL) - fatal(_("local port invalid in `%s'"), name); - else - localport = ntohs(service->s_port); - } - *cp = '/'; + localpnamelastcharp = cp; /* which hostname? */ cp++; hostname = cp; while (*cp != '/' && *cp != '\0') cp++; - if (*cp != '/' || cp == hostname) + if (*cp != '/' || cp == hostname) { + *localpnamelastcharp = '/'; fatal(_("must supply a remote hostname to `/inet'")); + } *cp = '\0'; hostnameslastcharp = cp; @@ -1386,22 +1384,15 @@ * Here too, require a port, let them explicitly put 0 if * they don't care. */ - if (*cp == '\0') + if (*cp == '\0') { + *localpnamelastcharp = '/'; + *hostnameslastcharp = '/'; fatal(_("must supply a remote port to `/inet'")); - remoteport = atoi(cp); - if (strcmp(cp, "0") != 0 - && (remoteport <= 0 || remoteport > 65535)) { - service = getservbyname(cp, proto); - if (service == NULL) - fatal(_("remote port invalid in `%s'"), name); - else - remoteport = ntohs(service->s_port); } - /* Open Sesame! */ - openfd = socketopen(protocol, localport, remoteport, hostname); + openfd = socketopen(protocol, localpname, cp, hostname); + *localpnamelastcharp = '/'; *hostnameslastcharp = '/'; - #else /* ! HAVE_SOCKETS */ fatal(_("TCP/IP communications are not supported")); #endif /* HAVE_SOCKETS */