[alsa-devel] [PATCH] Aseqnet, no nagle and dual stack

Rob van der Putten rob at sput.nl
Sat May 4 14:51:53 CEST 2019


Hi there


On 28/04/2019 10:00, Takashi Iwai wrote:

> On Tue, 23 Apr 2019 20:25:58 +0200,
> Rob van der Putten wrote:
> On Tue, 23 Apr 2019 20:25:58 +0200,
> Rob van der Putten wrote:
>>
>> Hi there
>>
>>
>> Not an ALSA source patch, but a patch for an ALSA related util.
>> Aseqnet sends ALSA sound_seq MIDI over TCP/IP. The patch below
>> disables nagle, enables quickack and makes aseqnet dual-stack.
> 
> Thanks for the patch.  Could you repost with a proper patch change log
> and your Signed-off-by line so that one can apply to git repo?

Added
- Disabled Nagle's algorithm
- Enbled quickack
- IPv6 support

Signed-off-by: Rob van der Putten <rob at sput.nl>

> About the changes:
>> --- aseqnet.c.bak	2012-01-25 10:43:38.000000000 +0100
>> +++ aseqnet.c	2017-08-26 14:17:58.261868853 +0200
>> @@ -3,6 +3,8 @@
>>    *   ver.0.1
>>    *
>>    * Copyright (C) 1999-2000 Takashi Iwai
>> + * Modified by Rob van der Putten, Leiden, Holland,
>> + * rob at sput dot nl.
> 
> We don't need to add each change in the source like that as all
> tracked in git.
> 
>> @@ -15,18 +17,21 @@
>>    *
>>    */
>>
>> +#include <alsa/asoundlib.h>
>> +#include <arpa/inet.h>
>> +#include <assert.h>
>> +#include <ctype.h>
>> +#include <getopt.h>
>> +#include <locale.h>
>> +#include <netdb.h>
>> +#include <netinet/in.h>
>> +#include <netinet/tcp.h>
>> +#include <signal.h>
>>   #include <stdio.h>
>>   #include <stdlib.h>
>> -#include <ctype.h>
>>   #include <string.h>
>> -#include <netinet/in.h>
>>   #include <sys/socket.h>
>> -#include <netdb.h>
>> -#include <locale.h>
>> -#include <alsa/asoundlib.h>
>> -#include <getopt.h>
>> -#include <signal.h>
>> -#include <assert.h>
>> +#include <sys/types.h>
>>   #include "aconfig.h"
>>   #include "gettext.h"
> 
> Why these large rearrangement of include files?  If it must be
> inevitably done, please describe the reason in the changelog, too.

I just put them into alphabetical order. I changed that back.

>> @@ -327,17 +332,24 @@
>>    */
>>   static void init_server(int port)
>>   {
>> +	/*
>> +	*       RvdP, changed to support IPv6
>> +	*       Dual stack only!
>> +	*/
> 
> Wouldn't it potentially break things?  IMO, it's better to keep the
> old behavior (ipv4-only), at least, with an option.

Server:
The behaviour is determined by /proc/sys/net/ipv6/bindv6only
If this is one, the listening socket will be IPv6 only instead of dual
stack. A socket option is used to set IPV6_V6ONLY to zero, which forces 
the listening socket dual stack.

Client:
The 'for (rp = result; rp != NULL; rp = rp->ai_next) {' loop keeps 
trying to connect to the remote host: If IPv6 fails, it uses IPv4 instead.

Both:
I added a -4 / --ipv4 option.
This not in the previous patch.
It also introduces the string '-4, --ipv4 : IPv4 only' for which there 
no translations. And a new bit in the man page, with an added man page 
patch.

> Also, drop your initials in the commit, it's rather superfluous.

A new aseqnet patch. Note: This patches the original, not the previous 
patch.
--- a/seq/aseqnet/aseqnet.c
+++ b/seq/aseqnet/aseqnet.c
@@ -29,6 +29,9 @@
  #include <assert.h>
  #include "aconfig.h"
  #include "gettext.h"
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <sys/types.h>

  /*
   * 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;


A man page patch;
--- a/seq/aseqnet/aseqnet.1
+++ b/seq/aseqnet/aseqnet.1
@@ -1,4 +1,4 @@
-.TH aseqnet 1 "January 1, 2000"
+.TH aseqnet 1 "May 1, 2019"
  .SH NAME
  aseqnet \- ALSA sequencer connectors over network

@@ -72,6 +72,9 @@
  .TP
  .B \-v
  Verbose mode.
+.TP
+.B \-4
+IPv4 only.

  .SH "SEE ALSO"
  aconnect(1), pmidi(1)


Regards,
Rob



More information about the Alsa-devel mailing list