Diff for /qemu/qemu-sockets.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2018/04/24 17:20:57 version 1.1.1.3, 2018/04/24 17:34:43
Line 29 Line 29
 static int sockets_debug = 0;  static int sockets_debug = 0;
 static const int on=1, off=0;  static const int on=1, off=0;
   
   /* used temporarely until all users are converted to QemuOpts */
   static QemuOptsList dummy_opts = {
       .name = "dummy",
       .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head),
       .desc = {
           {
               .name = "path",
               .type = QEMU_OPT_STRING,
           },{
               .name = "host",
               .type = QEMU_OPT_STRING,
           },{
               .name = "port",
               .type = QEMU_OPT_STRING,
           },{
               .name = "to",
               .type = QEMU_OPT_NUMBER,
           },{
               .name = "ipv4",
               .type = QEMU_OPT_BOOL,
           },{
               .name = "ipv6",
               .type = QEMU_OPT_BOOL,
           },
           { /* end if list */ }
       },
   };
   
 static int inet_getport(struct addrinfo *e)  static int inet_getport(struct addrinfo *e)
 {  {
     struct sockaddr_in *i4;      struct sockaddr_in *i4;
Line 88  static void inet_print_addrinfo(const ch Line 116  static void inet_print_addrinfo(const ch
     }      }
 }  }
   
 int inet_listen(const char *str, char *ostr, int olen,  int inet_listen_opts(QemuOpts *opts, int port_offset)
                 int socktype, int port_offset)  
 {  {
     struct addrinfo ai,*res,*e;      struct addrinfo ai,*res,*e;
     char addr[64];      const char *addr;
     char port[33];      char port[33];
     char uaddr[INET6_ADDRSTRLEN+1];      char uaddr[INET6_ADDRSTRLEN+1];
     char uport[33];      char uport[33];
     const char *opts, *h;      int slisten,rc,to,try_next;
     int slisten,rc,pos,to,try_next;  
   
     memset(&ai,0, sizeof(ai));      memset(&ai,0, sizeof(ai));
     ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;      ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
     ai.ai_family = PF_UNSPEC;      ai.ai_family = PF_UNSPEC;
     ai.ai_socktype = socktype;      ai.ai_socktype = SOCK_STREAM;
   
     /* parse address */      if (qemu_opt_get(opts, "port") == NULL) {
     if (str[0] == ':') {          fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
         /* no host given */          return -1;
         addr[0] = '\0';  
         if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {  
             fprintf(stderr, "%s: portonly parse error (%s)\n",  
                     __FUNCTION__, str);  
             return -1;  
         }  
     } else if (str[0] == '[') {  
         /* IPv6 addr */  
         if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {  
             fprintf(stderr, "%s: ipv6 parse error (%s)\n",  
                     __FUNCTION__, str);  
             return -1;  
         }  
         ai.ai_family = PF_INET6;  
     } else if (qemu_isdigit(str[0])) {  
         /* IPv4 addr */  
         if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {  
             fprintf(stderr, "%s: ipv4 parse error (%s)\n",  
                     __FUNCTION__, str);  
             return -1;  
         }  
         ai.ai_family = PF_INET;  
     } else {  
         /* hostname */  
         if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {  
             fprintf(stderr, "%s: hostname parse error (%s)\n",  
                     __FUNCTION__, str);  
             return -1;  
         }  
     }      }
       pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
       addr = qemu_opt_get(opts, "host");
   
     /* parse options */      to = qemu_opt_get_number(opts, "to", 0);
     opts = str + pos;      if (qemu_opt_get_bool(opts, "ipv4", 0))
     h = strstr(opts, ",to=");  
     to = h ? atoi(h+4) : 0;  
     if (strstr(opts, ",ipv4"))  
         ai.ai_family = PF_INET;          ai.ai_family = PF_INET;
     if (strstr(opts, ",ipv6"))      if (qemu_opt_get_bool(opts, "ipv6", 0))
         ai.ai_family = PF_INET6;          ai.ai_family = PF_INET6;
   
     /* lookup */      /* lookup */
Line 152  int inet_listen(const char *str, char *o Line 148  int inet_listen(const char *str, char *o
         snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);          snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);      rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
     if (rc != 0) {      if (rc != 0) {
         fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,          fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                 addr, port, gai_strerror(rc));                  gai_strerror(rc));
         return -1;          return -1;
     }      }
     if (sockets_debug)      if (sockets_debug)
Line 164  int inet_listen(const char *str, char *o Line 160  int inet_listen(const char *str, char *o
         getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,          getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
                         uaddr,INET6_ADDRSTRLEN,uport,32,                          uaddr,INET6_ADDRSTRLEN,uport,32,
                         NI_NUMERICHOST | NI_NUMERICSERV);                          NI_NUMERICHOST | NI_NUMERICSERV);
         slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol);          slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
         if (slisten < 0) {          if (slisten < 0) {
             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,              fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
                     inet_strfamily(e->ai_family), strerror(errno));                      inet_strfamily(e->ai_family), strerror(errno));
Line 211  listen: Line 207  listen:
         freeaddrinfo(res);          freeaddrinfo(res);
         return -1;          return -1;
     }      }
     if (ostr) {      snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
         if (e->ai_family == PF_INET6) {      qemu_opt_set(opts, "host", uaddr);
             snprintf(ostr, olen, "[%s]:%d%s", uaddr,      qemu_opt_set(opts, "port", uport);
                      inet_getport(e) - port_offset, opts);      qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
         } else {      qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
             snprintf(ostr, olen, "%s:%d%s", uaddr,  
                      inet_getport(e) - port_offset, opts);  
         }  
     }  
     freeaddrinfo(res);      freeaddrinfo(res);
     return slisten;      return slisten;
 }  }
   
 int inet_connect(const char *str, int socktype)  int inet_connect_opts(QemuOpts *opts)
 {  {
     struct addrinfo ai,*res,*e;      struct addrinfo ai,*res,*e;
     char addr[64];      const char *addr;
     char port[33];      const char *port;
     char uaddr[INET6_ADDRSTRLEN+1];      char uaddr[INET6_ADDRSTRLEN+1];
     char uport[33];      char uport[33];
     int sock,rc;      int sock,rc;
Line 236  int inet_connect(const char *str, int so Line 228  int inet_connect(const char *str, int so
     memset(&ai,0, sizeof(ai));      memset(&ai,0, sizeof(ai));
     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;      ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
     ai.ai_family = PF_UNSPEC;      ai.ai_family = PF_UNSPEC;
     ai.ai_socktype = socktype;      ai.ai_socktype = SOCK_STREAM;
   
     /* parse address */      addr = qemu_opt_get(opts, "host");
     if (str[0] == '[') {      port = qemu_opt_get(opts, "port");
         /* IPv6 addr */      if (addr == NULL || port == NULL) {
         if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {          fprintf(stderr, "inet_connect: host and/or port not specified\n");
             fprintf(stderr, "%s: ipv6 parse error (%s)\n",          return -1;
                     __FUNCTION__, str);  
             return -1;  
         }  
         ai.ai_family = PF_INET6;  
     } else if (qemu_isdigit(str[0])) {  
         /* IPv4 addr */  
         if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {  
             fprintf(stderr, "%s: ipv4 parse error (%s)\n",  
                     __FUNCTION__, str);  
             return -1;  
         }  
         ai.ai_family = PF_INET;  
     } else {  
         /* hostname */  
         if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {  
             fprintf(stderr, "%s: hostname parse error (%s)\n",  
                     __FUNCTION__, str);  
             return -1;  
         }  
     }      }
   
     /* parse options */      if (qemu_opt_get_bool(opts, "ipv4", 0))
     if (strstr(str, ",ipv4"))  
         ai.ai_family = PF_INET;          ai.ai_family = PF_INET;
     if (strstr(str, ",ipv6"))      if (qemu_opt_get_bool(opts, "ipv6", 0))
         ai.ai_family = PF_INET6;          ai.ai_family = PF_INET6;
   
     /* lookup */      /* lookup */
     if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {      if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
         fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc),          fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                 addr, port);                  gai_strerror(rc));
         return -1;          return -1;
     }      }
     if (sockets_debug)      if (sockets_debug)
Line 286  int inet_connect(const char *str, int so Line 258  int inet_connect(const char *str, int so
             fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);              fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
             continue;              continue;
         }          }
         sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol);          sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
         if (sock < 0) {          if (sock < 0) {
             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,              fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
             inet_strfamily(e->ai_family), strerror(errno));              inet_strfamily(e->ai_family), strerror(errno));
Line 314  int inet_connect(const char *str, int so Line 286  int inet_connect(const char *str, int so
     return -1;      return -1;
 }  }
   
   int inet_dgram_opts(QemuOpts *opts)
   {
       struct addrinfo ai, *peer = NULL, *local = NULL;
       const char *addr;
       const char *port;
       char uaddr[INET6_ADDRSTRLEN+1];
       char uport[33];
       int sock = -1, rc;
   
       /* lookup peer addr */
       memset(&ai,0, sizeof(ai));
       ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
       ai.ai_family = PF_UNSPEC;
       ai.ai_socktype = SOCK_DGRAM;
   
       addr = qemu_opt_get(opts, "host");
       port = qemu_opt_get(opts, "port");
       if (addr == NULL || strlen(addr) == 0) {
           addr = "localhost";
       }
       if (port == NULL || strlen(port) == 0) {
           fprintf(stderr, "inet_dgram: port not specified\n");
           return -1;
       }
   
       if (qemu_opt_get_bool(opts, "ipv4", 0))
           ai.ai_family = PF_INET;
       if (qemu_opt_get_bool(opts, "ipv6", 0))
           ai.ai_family = PF_INET6;
   
       if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
           fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                   gai_strerror(rc));
           return -1;
       }
       if (sockets_debug) {
           fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port);
           inet_print_addrinfo(__FUNCTION__, peer);
       }
   
       /* lookup local addr */
       memset(&ai,0, sizeof(ai));
       ai.ai_flags = AI_PASSIVE;
       ai.ai_family = peer->ai_family;
       ai.ai_socktype = SOCK_DGRAM;
   
       addr = qemu_opt_get(opts, "localaddr");
       port = qemu_opt_get(opts, "localport");
       if (addr == NULL || strlen(addr) == 0) {
           addr = NULL;
       }
       if (!port || strlen(port) == 0)
           port = "0";
   
       if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
           fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                   gai_strerror(rc));
           return -1;
       }
       if (sockets_debug) {
           fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port);
           inet_print_addrinfo(__FUNCTION__, local);
       }
   
       /* create socket */
       sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
       if (sock < 0) {
           fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
                   inet_strfamily(peer->ai_family), strerror(errno));
           goto err;
       }
       setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
   
       /* bind socket */
       if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen,
                       uaddr,INET6_ADDRSTRLEN,uport,32,
                       NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
           fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
           goto err;
       }
       if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
           fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
                   inet_strfamily(local->ai_family), uaddr, inet_getport(local));
           goto err;
       }
   
       /* connect to peer */
       if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen,
                       uaddr, INET6_ADDRSTRLEN, uport, 32,
                       NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
           fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
           goto err;
       }
       if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
           fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
                   inet_strfamily(peer->ai_family),
                   peer->ai_canonname, uaddr, uport, strerror(errno));
           goto err;
       }
   
       freeaddrinfo(local);
       freeaddrinfo(peer);
       return sock;
   
   err:
       if (-1 != sock)
           closesocket(sock);
       if (local)
           freeaddrinfo(local);
       if (peer)
           freeaddrinfo(peer);
       return -1;
   }
   
   /* compatibility wrapper */
   static int inet_parse(QemuOpts *opts, const char *str)
   {
       const char *optstr, *h;
       char addr[64];
       char port[33];
       int pos;
   
       /* parse address */
       if (str[0] == ':') {
           /* no host given */
           addr[0] = '\0';
           if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
               fprintf(stderr, "%s: portonly parse error (%s)\n",
                       __FUNCTION__, str);
               return -1;
           }
       } else if (str[0] == '[') {
           /* IPv6 addr */
           if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
               fprintf(stderr, "%s: ipv6 parse error (%s)\n",
                       __FUNCTION__, str);
               return -1;
           }
           qemu_opt_set(opts, "ipv6", "yes");
       } else if (qemu_isdigit(str[0])) {
           /* IPv4 addr */
           if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
               fprintf(stderr, "%s: ipv4 parse error (%s)\n",
                       __FUNCTION__, str);
               return -1;
           }
           qemu_opt_set(opts, "ipv4", "yes");
       } else {
           /* hostname */
           if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
               fprintf(stderr, "%s: hostname parse error (%s)\n",
                       __FUNCTION__, str);
               return -1;
           }
       }
       qemu_opt_set(opts, "host", addr);
       qemu_opt_set(opts, "port", port);
   
       /* parse options */
       optstr = str + pos;
       h = strstr(optstr, ",to=");
       if (h)
           qemu_opt_set(opts, "to", h+4);
       if (strstr(optstr, ",ipv4"))
           qemu_opt_set(opts, "ipv4", "yes");
       if (strstr(optstr, ",ipv6"))
           qemu_opt_set(opts, "ipv6", "yes");
       return 0;
   }
   
   int inet_listen(const char *str, char *ostr, int olen,
                   int socktype, int port_offset)
   {
       QemuOpts *opts;
       char *optstr;
       int sock = -1;
   
       opts = qemu_opts_create(&dummy_opts, NULL, 0);
       if (inet_parse(opts, str) == 0) {
           sock = inet_listen_opts(opts, port_offset);
           if (sock != -1 && ostr) {
               optstr = strchr(str, ',');
               if (qemu_opt_get_bool(opts, "ipv6", 0)) {
                   snprintf(ostr, olen, "[%s]:%s%s",
                            qemu_opt_get(opts, "host"),
                            qemu_opt_get(opts, "port"),
                            optstr ? optstr : "");
               } else {
                   snprintf(ostr, olen, "%s:%s%s",
                            qemu_opt_get(opts, "host"),
                            qemu_opt_get(opts, "port"),
                            optstr ? optstr : "");
               }
           }
       }
       qemu_opts_del(opts);
       return sock;
   }
   
   int inet_connect(const char *str, int socktype)
   {
       QemuOpts *opts;
       int sock = -1;
   
       opts = qemu_opts_create(&dummy_opts, NULL, 0);
       if (inet_parse(opts, str) == 0)
           sock = inet_connect_opts(opts);
       qemu_opts_del(opts);
       return sock;
   }
   
 #ifndef _WIN32  #ifndef _WIN32
   
 int unix_listen(const char *str, char *ostr, int olen)  int unix_listen_opts(QemuOpts *opts)
 {  {
     struct sockaddr_un un;      struct sockaddr_un un;
     char *path, *opts;      const char *path = qemu_opt_get(opts, "path");
     int sock, fd, len;      int sock, fd;
   
     sock = socket(PF_UNIX, SOCK_STREAM, 0);      sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
     if (sock < 0) {      if (sock < 0) {
         perror("socket(unix)");          perror("socket(unix)");
         return -1;          return -1;
     }      }
   
     opts = strchr(str, ',');  
     if (opts) {  
         len = opts - str;  
         path = qemu_malloc(len+1);  
         snprintf(path, len+1, "%.*s", len, str);  
     } else  
         path = qemu_strdup(str);  
   
     memset(&un, 0, sizeof(un));      memset(&un, 0, sizeof(un));
     un.sun_family = AF_UNIX;      un.sun_family = AF_UNIX;
     if (path && strlen(path)) {      if (path && strlen(path)) {
Line 352  int unix_listen(const char *str, char *o Line 527  int unix_listen(const char *str, char *o
          * worst case possible is bind() failing, i.e. a DoS attack.           * worst case possible is bind() failing, i.e. a DoS attack.
          */           */
         fd = mkstemp(un.sun_path); close(fd);          fd = mkstemp(un.sun_path); close(fd);
           qemu_opt_set(opts, "path", un.sun_path);
     }      }
     snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : "");  
   
     unlink(un.sun_path);      unlink(un.sun_path);
     if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {      if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
Line 367  int unix_listen(const char *str, char *o Line 542  int unix_listen(const char *str, char *o
   
     if (sockets_debug)      if (sockets_debug)
         fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);          fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
     qemu_free(path);  
     return sock;      return sock;
   
 err:  err:
     qemu_free(path);  
     closesocket(sock);      closesocket(sock);
     return -1;      return -1;
 }  }
   
 int unix_connect(const char *path)  int unix_connect_opts(QemuOpts *opts)
 {  {
     struct sockaddr_un un;      struct sockaddr_un un;
       const char *path = qemu_opt_get(opts, "path");
     int sock;      int sock;
   
     sock = socket(PF_UNIX, SOCK_STREAM, 0);      if (NULL == path) {
           fprintf(stderr, "unix connect: no path specified\n");
           return -1;
       }
   
       sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
     if (sock < 0) {      if (sock < 0) {
         perror("socket(unix)");          perror("socket(unix)");
         return -1;          return -1;
Line 400  int unix_connect(const char *path) Line 579  int unix_connect(const char *path)
     return sock;      return sock;
 }  }
   
   /* compatibility wrapper */
   int unix_listen(const char *str, char *ostr, int olen)
   {
       QemuOpts *opts;
       char *path, *optstr;
       int sock, len;
   
       opts = qemu_opts_create(&dummy_opts, NULL, 0);
   
       optstr = strchr(str, ',');
       if (optstr) {
           len = optstr - str;
           if (len) {
               path = qemu_malloc(len+1);
               snprintf(path, len+1, "%.*s", len, str);
               qemu_opt_set(opts, "path", path);
               qemu_free(path);
           }
       } else {
           qemu_opt_set(opts, "path", str);
       }
   
       sock = unix_listen_opts(opts);
   
       if (sock != -1 && ostr)
           snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
       qemu_opts_del(opts);
       return sock;
   }
   
   int unix_connect(const char *path)
   {
       QemuOpts *opts;
       int sock;
   
       opts = qemu_opts_create(&dummy_opts, NULL, 0);
       qemu_opt_set(opts, "path", path);
       sock = unix_connect_opts(opts);
       qemu_opts_del(opts);
       return sock;
   }
   
 #else  #else
   
   int unix_listen_opts(QemuOpts *opts)
   {
       fprintf(stderr, "unix sockets are not available on windows\n");
       return -1;
   }
   
   int unix_connect_opts(QemuOpts *opts)
   {
       fprintf(stderr, "unix sockets are not available on windows\n");
       return -1;
   }
   
 int unix_listen(const char *path, char *ostr, int olen)  int unix_listen(const char *path, char *ostr, int olen)
 {  {
     fprintf(stderr, "unix sockets are not available on windows\n");      fprintf(stderr, "unix sockets are not available on windows\n");

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


unix.superglobalmegacorp.com