300 lines
8.1 KiB
Diff
300 lines
8.1 KiB
Diff
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 */
|