--- a/seq/aseqnet/aseqnet.c +++ b/seq/aseqnet/aseqnet.c @@ -29,6 +29,9 @@ #include #include "aconfig.h" #include "gettext.h" +#include +#include +#include /* * prototypes @@ -78,6 +81,8 @@ static int verbose = 0; static int info = 0; +static int ipv4only = 0; + /* * main routine @@ -90,6 +95,7 @@ {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"info", 0, NULL, 'i'}, + {"ipv4", 0, NULL, '4'}, {NULL, 0, NULL, 0}, }; @@ -104,7 +110,7 @@ textdomain(PACKAGE); #endif - while ((c = getopt_long(argc, argv, "p:s:d:vi", long_option, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "p:s:d:vi4", long_option, NULL)) != -1) { switch (c) { case 'p': if (isdigit(*optarg)) @@ -124,6 +130,9 @@ case 'i': info++; break; + case '4': + ipv4only++; + break; default: usage(); exit(1); @@ -172,6 +181,7 @@ printf(_(" -d,--dest addr : write to given addr (client:port)\n")); printf(_(" -v, --verbose : print verbose messages\n")); printf(_(" -i, --info : print certain received events\n")); + printf(_(" -4, --ipv4 : IPv4 only\n")); } @@ -329,25 +339,64 @@ { int i; int curstate = 1; - struct sockaddr_in addr; - - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(port); + int ipv6only = 0; + int nodelay = 1; + int quickack = 1; + struct sockaddr_in addr4; + struct sockaddr_in6 addr; + + if (ipv4only == 0) { + memset(&addr, 0, sizeof(addr)); + + addr.sin6_family = AF_INET6; + inet_pton(AF_INET6, "::", &(addr.sin6_addr)); + addr.sin6_port = htons(port); + + sockfd = socket(PF_INET6, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("create socket"); + exit(1); + } + } else { + memset(&addr4, 0, sizeof(addr4)); - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) { - perror("create socket"); - exit(1); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = INADDR_ANY; + addr4.sin_port = htons(port); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("create socket"); + exit(1); + } } setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)); /* the return value is ignored.. */ - if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("can't bind"); - exit(1); + if (ipv4only == 0) { + /* Force dual stack */ + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)); + /* the return value is ignored.. */ + } + + /* Nagle and quickack */ + if ((setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay))) < 0) { + perror("Error setsockopt tcp_nodelay"); + } + if ((setsockopt(sockfd, IPPROTO_TCP, TCP_QUICKACK, &quickack, sizeof(quickack))) < 0) { + perror("Error setsockopt tcp_quickack"); + } + + if (ipv4only == 0) { + if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("can't bind"); + exit(1); + } + } else { + if (bind(sockfd, (struct sockaddr *) &addr4, sizeof(addr4)) < 0) { + perror("can't bind"); + exit(1); + } } if (listen(sockfd, 5) < 0) { @@ -365,7 +414,8 @@ */ static void start_connection(void) { - struct sockaddr_in addr; + struct sockaddr_in6 addr; + struct sockaddr_in addr4; int i; socklen_t addr_len; @@ -377,9 +427,15 @@ fprintf(stderr, _("too many connections!\n")); exit(1); } - memset(&addr, 0, sizeof(addr)); - addr_len = sizeof(addr); - netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len); + if (ipv4only == 0) { + memset(&addr, 0, sizeof(addr)); + addr_len = sizeof(addr); + netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len); + } else { + memset(&addr4, 0, sizeof(addr4)); + addr_len = sizeof(addr4); + netfd[i] = accept(sockfd, (struct sockaddr *)&addr4, &addr_len); + } if (netfd[i] < 0) { perror("accept"); exit(1); @@ -394,30 +450,57 @@ */ static void init_client(char *server, int port) { - struct sockaddr_in addr; - struct hostent *host; + struct addrinfo hints; + struct addrinfo *result, *rp; int curstate = 1; - int fd; + int nodelay = 1; + int quickack = 1; + int fd, s; + char portstr[8]; + struct hostent *host; - if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ - perror("create socket"); + memset(&hints, 0, sizeof(struct addrinfo)); + if(ipv4only == 0) + hints.ai_family = AF_UNSPEC; + else + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + /* hints.ai_protocol = IPPROTO_TCP; */ + hints.ai_flags = 0; + + memset(portstr, 0, 8); + snprintf(portstr, 6, "%d", port); + + s = getaddrinfo(server, portstr, &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + exit(1); + } + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + close(fd); + } + if (rp == NULL) { + fprintf(stderr, "Could not connect\n"); exit(1); } + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) { perror("setsockopt"); exit(1); } - if ((host = gethostbyname(server)) == NULL){ - fprintf(stderr, _("can't get address %s\n"), server); - exit(1); + + if ((setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay))) < 0) { + perror("Error setsockopt tcp_nodelay"); } - addr.sin_port = htons(port); - addr.sin_family = AF_INET; - memcpy(&addr.sin_addr, host->h_addr, host->h_length); - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("connect"); - exit(1); + if ((setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &quickack, sizeof(quickack))) < 0) { + perror("Error setsockopt tcp_quickack"); } + if (verbose) fprintf(stderr, _("ok.. connected\n")); netfd[0] = fd;