freebsd-ports/net/sock/files/patch-src__cliopen.c

265 lines
7.6 KiB
C
Raw Normal View History

--- src/cliopen.c.orig 2010-05-28 00:03:25 UTC
+++ src/cliopen.c
@@ -10,42 +10,107 @@
#include "sock.h"
+/*
+ * Try to convert the host name as an IPv4 dotted-decimal number
+ * or an IPv6 address.
+ */
+int convert_host_address(char *host)
+{
+ struct in_addr inaddr;
+ char inaddr_buf[INET6_ADDRSTRLEN];
+
+ if (AF_INET == af_46) {
+ if (inet_pton(AF_INET, host, &inaddr) == 1) {
+ /* IPv4 dotted-decimal */
+ servaddr4.sin_addr = inaddr;
+
+ return (1);
+ }
+ } else {
+ if (inet_pton(AF_INET6, host, inaddr_buf) == 1) {
+ /* IPv6 address */
+ memcpy(&servaddr6.sin6_addr, inaddr_buf,
+ sizeof(struct in6_addr));
+
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Try to convert the host name as a host name string.
+ */
+int convert_host_name(char *host)
+{
+ struct hostent *hp;
+
+ if (AF_INET == af_46) {
+ if ( (hp = gethostbyname2(host, AF_INET)) != NULL) {
+ /* IPv4 address */
+ memcpy(&servaddr4.sin_addr, hp->h_addr, hp->h_length);
+
+ return (1);
+ }
+ } else {
+ /*
+ * Fixme: This doesn't work on FreeBSD 8.4.
+ * Only an IPv4 address is returned.
+ * getaddrinfo() doesn't work either.
+ */
+ if ( (hp = gethostbyname2(host, AF_INET6)) != NULL) {
+ /* IPv6 address */
+ memcpy(&servaddr6.sin6_addr, hp->h_addr, hp->h_length);
+
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
int cliopen(char *host, char *port)
{
int fd, i, on;
char *protocol;
- struct in_addr inaddr;
+ char inaddr_buf[INET6_ADDRSTRLEN];
struct servent *sp;
- struct hostent *hp;
+ socklen_t socklen;
protocol = udp ? "udp" : "tcp";
/* initialize socket address structure */
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
+ bzero(&servaddr4, sizeof(servaddr4));
+ servaddr4.sin_family = AF_INET;
+
+ bzero(&servaddr6, sizeof(servaddr6));
+ servaddr6.sin6_family = AF_INET6;
/* see if "port" is a service name or number */
if ( (i = atoi(port)) == 0) {
if ( (sp = getservbyname(port, protocol)) == NULL)
- err_quit("getservbyname() error for: %s/%s", port, protocol);
-
- servaddr.sin_port = sp->s_port;
- } else
- servaddr.sin_port = htons(i);
+ err_quit("getservbyname() error for: %s/%s",
+ port, protocol);
+ servaddr4.sin_port = sp->s_port;
+ servaddr6.sin6_port = sp->s_port;
+ } else {
+ servaddr4.sin_port = htons(i);
+ servaddr6.sin6_port = htons(i);
+ }
/*
- * First try to convert the host name as a dotted-decimal number.
- * Only if that fails do we call gethostbyname().
+ * First try to convert the host name as an IPv4 dotted-decimal number
+ * or an IPv6 address. Only if that fails do we try to convert the
+ * host name as a host name string.
*/
-
- if (inet_aton(host, &inaddr) == 1)
- servaddr.sin_addr = inaddr; /* it's dotted-decimal */
- else if ( (hp = gethostbyname(host)) != NULL)
- bcopy(hp->h_addr, &servaddr.sin_addr, hp->h_length);
- else
- err_quit("invalid hostname: %s", host);
+ if (convert_host_address(host) != 1) {
+ if (convert_host_name(host) != 1) {
+ err_quit("invalid hostname: %s", host);
+ }
+ }
- if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
+ if ( (fd = socket(af_46, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
err_sys("socket() error");
if (reuseaddr) {
@@ -71,21 +136,46 @@ int cliopen(char *host, char *port)
* (and port) using -l option. Allow localip[] to be set but bindport
* to be 0.
*/
-
if (bindport != 0 || localip[0] != 0 || udp) {
- bzero(&cliaddr, sizeof(cliaddr));
- cliaddr.sin_family = AF_INET;
- cliaddr.sin_port = htons(bindport); /* can be 0 */
- if (localip[0] != 0) {
- if (inet_aton(localip, &cliaddr.sin_addr) == 0)
- err_quit("invalid IP address: %s", localip);
- } else
- cliaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */
-
- if (bind(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0)
- err_sys("bind() error");
+ if (af_46 == AF_INET) {
+ bzero(&cliaddr4, sizeof(cliaddr4));
+ cliaddr4.sin_family = AF_INET;
+ /* can be 0 */
+ cliaddr4.sin_port = htons(bindport);
+ if (localip[0] != 0) {
+ if (inet_aton(localip, &cliaddr4.sin_addr) == 0)
+ err_quit("invalid IP address: %s",
+ localip);
+ } else {
+ /* wildcard */
+ cliaddr4.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ if (bind(fd, (struct sockaddr *) &cliaddr4,
+ sizeof(cliaddr4)) < 0) {
+ err_sys("bind() error");
+ }
+ } else {
+ bzero(&cliaddr6, sizeof(cliaddr6));
+ cliaddr6.sin6_len = sizeof(struct sockaddr_in6);
+ cliaddr6.sin6_family = AF_INET6;
+ /* can be 0 */
+ cliaddr6.sin6_port = htons(bindport);
+
+ /* Fixme: localip not implemented for IPv6 */
+ cliaddr6.sin6_addr = in6addr_any;
+
+ /* Fixme: Want to set IPV6_BINDANY? */
+
+ if (bind(fd, (struct sockaddr *) &cliaddr6,
+ sizeof(cliaddr6)) < 0) {
+ err_sys("bind() error");
+ }
+ }
}
-
+
+ /* Fixme: Does not work */
+ //join_mcast_client(fd, &cliaddr4, &cliaddr6, &servaddr4, &servaddr6);
+
/* Need to allocate buffers before connect(), since they can affect
* TCP options (window scale, etc.).
*/
@@ -96,13 +186,21 @@ int cliopen(char *host, char *port)
/*
* Connect to the server. Required for TCP, optional for UDP.
*/
-
if (udp == 0 || connectudp) {
for ( ; ; ) {
- if (connect(fd, (struct sockaddr *) &servaddr, sizeof(servaddr))
- == 0)
+ if (AF_INET == af_46) {
+ if (connect(fd, (struct sockaddr *) &servaddr4,
+ sizeof(servaddr4)) == 0)
break; /* all OK */
- if (errno == EINTR) /* can happen with SIGIO */
+ } else {
+ servaddr6.sin6_len =
+ sizeof(struct sockaddr_in6);
+ servaddr6.sin6_family = AF_INET6;
+ if (connect(fd, (struct sockaddr *) &servaddr6,
+ sizeof(servaddr6)) == 0)
+ break; /* all OK */
+ }
+ if (errno == EINTR) /* can happen with SIGIO */
continue;
if (errno == EISCONN) /* can happen with SIGIO */
break;
@@ -114,16 +212,38 @@ int cliopen(char *host, char *port)
/* Call getsockname() to find local address bound to socket:
TCP ephemeral port was assigned by connect() or bind();
UDP ephemeral port was assigned by bind(). */
- i = sizeof(cliaddr);
- if (getsockname(fd, (struct sockaddr *) &cliaddr, &i) < 0)
- err_sys("getsockname() error");
-
- /* Can't do one fprintf() since inet_ntoa() stores
- the result in a static location. */
- fprintf(stderr, "connected on %s.%d ",
- INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
- fprintf(stderr, "to %s.%d\n",
- INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port));
+ if (AF_INET == af_46) {
+ socklen = sizeof(cliaddr4);
+ if (getsockname(fd,
+ (struct sockaddr *) &cliaddr4, &socklen) < 0) {
+ err_sys("getsockname() error");
+ }
+ /* Can't do one fprintf() since inet_ntoa() stores
+ the result in a static location. */
+ fprintf(stderr, "connected on %s.%d ",
+ INET_NTOA(cliaddr4.sin_addr),
+ ntohs(cliaddr4.sin_port));
+ fprintf(stderr, "to %s.%d\n",
+ INET_NTOA(servaddr4.sin_addr),
+ ntohs(servaddr4.sin_port));
+ } else {
+ socklen = sizeof(cliaddr6);
+ if (getsockname(fd,
+ (struct sockaddr *) &cliaddr6, &socklen) < 0) {
+ err_sys("getsockname() error");
+ }
+
+ inet_ntop(AF_INET6,
+ &cliaddr6.sin6_addr.__u6_addr.__u6_addr8,
+ inaddr_buf, sizeof(inaddr_buf));
+ fprintf(stderr, "connected on %s.%d ",
+ inaddr_buf, ntohs(cliaddr6.sin6_port));
+ inet_ntop(AF_INET6,
+ &servaddr6.sin6_addr.__u6_addr.__u6_addr8,
+ inaddr_buf, sizeof(inaddr_buf));
+ fprintf(stderr, "to %s.%d\n",
+ inaddr_buf, ntohs(servaddr6.sin6_port));
+ }
}
sockopts(fd, 1); /* some options get set after connect() */