symbian-qemu-0.9.1-12/qemu-symbian-svp/qemu-sockets.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  *  inet and unix socket functions for qemu
       
     3  *
       
     4  *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
       
     5  *
       
     6  *  This program is free software; you can redistribute it and/or modify
       
     7  *  it under the terms of the GNU General Public License as published by
       
     8  *  the Free Software Foundation; under version 2 of the License.
       
     9  *
       
    10  *  This program is distributed in the hope that it will be useful,
       
    11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13  *  GNU General Public License for more details.
       
    14  */
       
    15 #include <stdio.h>
       
    16 #include <stdlib.h>
       
    17 #include <string.h>
       
    18 #include <ctype.h>
       
    19 #include <errno.h>
       
    20 #include <unistd.h>
       
    21 
       
    22 #include "qemu_socket.h"
       
    23 #include "qemu-common.h" /* for qemu_isdigit */
       
    24 
       
    25 #ifndef AI_ADDRCONFIG
       
    26 # define AI_ADDRCONFIG 0
       
    27 #endif
       
    28 
       
    29 #ifdef __MINGW32__
       
    30 #if (__MINGW32_MAJOR_VERSION < 3) \
       
    31     || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION <= 7))
       
    32 /* Older versions of mingw32 don't provide gai_strerror.  */
       
    33 #undef gai_strerror
       
    34 static inline char*
       
    35 gai_strerror(int ecode)
       
    36 {
       
    37         static char message[1024+1];
       
    38         DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM
       
    39                       | FORMAT_MESSAGE_IGNORE_INSERTS
       
    40                       | FORMAT_MESSAGE_MAX_WIDTH_MASK;
       
    41         DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
       
    42         FormatMessage(dwFlags, NULL, ecode, dwLanguageId, (LPSTR)message, 1024, NULL);
       
    43         return message;
       
    44 }
       
    45 #endif
       
    46 #endif /* __MINGW32__ */
       
    47 
       
    48 static int sockets_debug = 0;
       
    49 static const int on=1, off=0;
       
    50 
       
    51 static int inet_getport(struct addrinfo *e)
       
    52 {
       
    53     struct sockaddr_in *i4;
       
    54     struct sockaddr_in6 *i6;
       
    55 
       
    56     switch (e->ai_family) {
       
    57     case PF_INET6:
       
    58         i6 = (void*)e->ai_addr;
       
    59         return ntohs(i6->sin6_port);
       
    60     case PF_INET:
       
    61         i4 = (void*)e->ai_addr;
       
    62         return ntohs(i4->sin_port);
       
    63     default:
       
    64         return 0;
       
    65     }
       
    66 }
       
    67 
       
    68 static void inet_setport(struct addrinfo *e, int port)
       
    69 {
       
    70     struct sockaddr_in *i4;
       
    71     struct sockaddr_in6 *i6;
       
    72 
       
    73     switch (e->ai_family) {
       
    74     case PF_INET6:
       
    75         i6 = (void*)e->ai_addr;
       
    76         i6->sin6_port = htons(port);
       
    77         break;
       
    78     case PF_INET:
       
    79         i4 = (void*)e->ai_addr;
       
    80         i4->sin_port = htons(port);
       
    81         break;
       
    82     }
       
    83 }
       
    84 
       
    85 static const char *inet_strfamily(int family)
       
    86 {
       
    87     switch (family) {
       
    88     case PF_INET6: return "ipv6";
       
    89     case PF_INET:  return "ipv4";
       
    90     case PF_UNIX:  return "unix";
       
    91     }
       
    92     return "????";
       
    93 }
       
    94 
       
    95 static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
       
    96 {
       
    97     struct addrinfo *e;
       
    98     char uaddr[INET6_ADDRSTRLEN+1];
       
    99     char uport[33];
       
   100 
       
   101     for (e = res; e != NULL; e = e->ai_next) {
       
   102         getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
       
   103                     uaddr,INET6_ADDRSTRLEN,uport,32,
       
   104                     NI_NUMERICHOST | NI_NUMERICSERV);
       
   105         fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
       
   106                 tag, inet_strfamily(e->ai_family), uaddr, uport);
       
   107     }
       
   108 }
       
   109 
       
   110 int inet_listen(const char *str, char *ostr, int olen,
       
   111                 int socktype, int port_offset)
       
   112 {
       
   113     struct addrinfo ai,*res,*e;
       
   114     char addr[64];
       
   115     char port[33];
       
   116     char uaddr[INET6_ADDRSTRLEN+1];
       
   117     char uport[33];
       
   118     const char *opts, *h;
       
   119     int slisten,rc,pos,to,try_next;
       
   120 
       
   121     memset(&ai,0, sizeof(ai));
       
   122     ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
       
   123     ai.ai_family = PF_UNSPEC;
       
   124     ai.ai_socktype = socktype;
       
   125 
       
   126     /* parse address */
       
   127     if (str[0] == ':') {
       
   128         /* no host given */
       
   129         strcpy(addr,"");
       
   130         if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
       
   131             fprintf(stderr, "%s: portonly parse error (%s)\n",
       
   132                     __FUNCTION__, str);
       
   133             return -1;
       
   134         }
       
   135     } else if (str[0] == '[') {
       
   136         /* IPv6 addr */
       
   137         if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
       
   138             fprintf(stderr, "%s: ipv6 parse error (%s)\n",
       
   139                     __FUNCTION__, str);
       
   140             return -1;
       
   141         }
       
   142         ai.ai_family = PF_INET6;
       
   143     } else if (qemu_isdigit(str[0])) {
       
   144         /* IPv4 addr */
       
   145         if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
       
   146             fprintf(stderr, "%s: ipv4 parse error (%s)\n",
       
   147                     __FUNCTION__, str);
       
   148             return -1;
       
   149         }
       
   150         ai.ai_family = PF_INET;
       
   151     } else {
       
   152         /* hostname */
       
   153         if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
       
   154             fprintf(stderr, "%s: hostname parse error (%s)\n",
       
   155                     __FUNCTION__, str);
       
   156             return -1;
       
   157         }
       
   158     }
       
   159 
       
   160     /* parse options */
       
   161     opts = str + pos;
       
   162     h = strstr(opts, ",to=");
       
   163     to = h ? atoi(h+4) : 0;
       
   164     if (strstr(opts, ",ipv4"))
       
   165         ai.ai_family = PF_INET;
       
   166     if (strstr(opts, ",ipv6"))
       
   167         ai.ai_family = PF_INET6;
       
   168 
       
   169     /* lookup */
       
   170     if (port_offset)
       
   171         snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
       
   172     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
       
   173     if (rc != 0) {
       
   174         fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
       
   175                 addr, port, gai_strerror(rc));
       
   176         return -1;
       
   177     }
       
   178     if (sockets_debug)
       
   179         inet_print_addrinfo(__FUNCTION__, res);
       
   180 
       
   181     /* create socket + bind */
       
   182     for (e = res; e != NULL; e = e->ai_next) {
       
   183 	getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
       
   184 		    uaddr,INET6_ADDRSTRLEN,uport,32,
       
   185 		    NI_NUMERICHOST | NI_NUMERICSERV);
       
   186         slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
       
   187 	if (slisten < 0) {
       
   188             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
       
   189                     inet_strfamily(e->ai_family), strerror(errno));
       
   190 	    continue;
       
   191 	}
       
   192 
       
   193         setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
       
   194 #ifdef IPV6_V6ONLY
       
   195         if (e->ai_family == PF_INET6) {
       
   196             /* listen on both ipv4 and ipv6 */
       
   197             setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off));
       
   198         }
       
   199 #endif
       
   200 
       
   201         for (;;) {
       
   202             if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
       
   203                 if (sockets_debug)
       
   204                     fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
       
   205                             inet_strfamily(e->ai_family), uaddr, inet_getport(e));
       
   206                 goto listen;
       
   207             }
       
   208             try_next = to && (inet_getport(e) <= to + port_offset);
       
   209             if (!try_next || sockets_debug)
       
   210                 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
       
   211                         inet_strfamily(e->ai_family), uaddr, inet_getport(e),
       
   212                         strerror(errno));
       
   213             if (try_next) {
       
   214                 inet_setport(e, inet_getport(e) + 1);
       
   215                 continue;
       
   216             }
       
   217             break;
       
   218         }
       
   219         closesocket(slisten);
       
   220     }
       
   221     fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
       
   222     freeaddrinfo(res);
       
   223     return -1;
       
   224 
       
   225 listen:
       
   226     if (listen(slisten,1) != 0) {
       
   227         perror("listen");
       
   228         closesocket(slisten);
       
   229         return -1;
       
   230     }
       
   231     if (ostr) {
       
   232         if (e->ai_family == PF_INET6) {
       
   233             snprintf(ostr, olen, "[%s]:%d%s", uaddr,
       
   234                      inet_getport(e) - port_offset, opts);
       
   235         } else {
       
   236             snprintf(ostr, olen, "%s:%d%s", uaddr,
       
   237                      inet_getport(e) - port_offset, opts);
       
   238         }
       
   239     }
       
   240     freeaddrinfo(res);
       
   241     return slisten;
       
   242 }
       
   243 
       
   244 int inet_connect(const char *str, int socktype)
       
   245 {
       
   246     struct addrinfo ai,*res,*e;
       
   247     char addr[64];
       
   248     char port[33];
       
   249     char uaddr[INET6_ADDRSTRLEN+1];
       
   250     char uport[33];
       
   251     int sock,rc;
       
   252 
       
   253     memset(&ai,0, sizeof(ai));
       
   254     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
       
   255     ai.ai_family = PF_UNSPEC;
       
   256     ai.ai_socktype = socktype;
       
   257 
       
   258     /* parse address */
       
   259     if (str[0] == '[') {
       
   260         /* IPv6 addr */
       
   261         if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
       
   262             fprintf(stderr, "%s: ipv6 parse error (%s)\n",
       
   263                     __FUNCTION__, str);
       
   264             return -1;
       
   265         }
       
   266         ai.ai_family = PF_INET6;
       
   267     } else if (qemu_isdigit(str[0])) {
       
   268         /* IPv4 addr */
       
   269         if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
       
   270             fprintf(stderr, "%s: ipv4 parse error (%s)\n",
       
   271                     __FUNCTION__, str);
       
   272             return -1;
       
   273         }
       
   274         ai.ai_family = PF_INET;
       
   275     } else {
       
   276         /* hostname */
       
   277         if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
       
   278             fprintf(stderr, "%s: hostname parse error (%s)\n",
       
   279                     __FUNCTION__, str);
       
   280             return -1;
       
   281         }
       
   282     }
       
   283 
       
   284     /* parse options */
       
   285     if (strstr(str, ",ipv4"))
       
   286         ai.ai_family = PF_INET;
       
   287     if (strstr(str, ",ipv6"))
       
   288         ai.ai_family = PF_INET6;
       
   289 
       
   290     /* lookup */
       
   291     if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
       
   292         fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc),
       
   293                 addr, port);
       
   294 	return -1;
       
   295     }
       
   296     if (sockets_debug)
       
   297         inet_print_addrinfo(__FUNCTION__, res);
       
   298 
       
   299     for (e = res; e != NULL; e = e->ai_next) {
       
   300 	if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
       
   301                         uaddr,INET6_ADDRSTRLEN,uport,32,
       
   302                         NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
       
   303             fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
       
   304 	    continue;
       
   305 	}
       
   306         sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
       
   307 	if (sock < 0) {
       
   308             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
       
   309                     inet_strfamily(e->ai_family), strerror(errno));
       
   310 	    continue;
       
   311 	}
       
   312         setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
       
   313 
       
   314 	/* connect to peer */
       
   315 	if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
       
   316             if (sockets_debug || NULL == e->ai_next)
       
   317                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
       
   318                         inet_strfamily(e->ai_family),
       
   319                         e->ai_canonname, uaddr, uport, strerror(errno));
       
   320             closesocket(sock);
       
   321 	    continue;
       
   322 	}
       
   323         if (sockets_debug)
       
   324             fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
       
   325                     inet_strfamily(e->ai_family),
       
   326                     e->ai_canonname, uaddr, uport);
       
   327         freeaddrinfo(res);
       
   328 	return sock;
       
   329     }
       
   330     freeaddrinfo(res);
       
   331     return -1;
       
   332 }
       
   333 
       
   334 #ifndef _WIN32
       
   335 
       
   336 int unix_listen(const char *str, char *ostr, int olen)
       
   337 {
       
   338     struct sockaddr_un un;
       
   339     char *path, *opts;
       
   340     int sock, fd, len;
       
   341 
       
   342     sock = socket(PF_UNIX, SOCK_STREAM, 0);
       
   343     if (sock < 0) {
       
   344 	perror("socket(unix)");
       
   345 	return -1;
       
   346     }
       
   347 
       
   348     opts = strchr(str, ',');
       
   349     if (opts) {
       
   350         len = opts - str;
       
   351         path = malloc(len+1);
       
   352         snprintf(path, len+1, "%.*s", len, str);
       
   353     } else
       
   354         path = strdup(str);
       
   355 
       
   356     memset(&un, 0, sizeof(un));
       
   357     un.sun_family = AF_UNIX;
       
   358     if (path && strlen(path)) {
       
   359         snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
       
   360     } else {
       
   361         char *tmpdir = getenv("TMPDIR");
       
   362         snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
       
   363                  tmpdir ? tmpdir : "/tmp");
       
   364         /*
       
   365          * This dummy fd usage silences the mktemp() unsecure warning.
       
   366          * Using mkstemp() doesn't make things more secure here
       
   367          * though.  bind() complains about existing files, so we have
       
   368          * to unlink first and thus re-open the race window.  The
       
   369          * worst case possible is bind() failing, i.e. a DoS attack.
       
   370          */
       
   371         fd = mkstemp(un.sun_path); close(fd);
       
   372     }
       
   373     snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : "");
       
   374 
       
   375     unlink(un.sun_path);
       
   376     if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
       
   377         fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
       
   378         goto err;
       
   379     }
       
   380     if (listen(sock, 1) < 0) {
       
   381         fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
       
   382         goto err;
       
   383     }
       
   384 
       
   385     if (sockets_debug)
       
   386         fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
       
   387     free(path);
       
   388     return sock;
       
   389 
       
   390 err:
       
   391     free(path);
       
   392     closesocket(sock);
       
   393     return -1;
       
   394 }
       
   395 
       
   396 int unix_connect(const char *path)
       
   397 {
       
   398     struct sockaddr_un un;
       
   399     int sock;
       
   400 
       
   401     sock = socket(PF_UNIX, SOCK_STREAM, 0);
       
   402     if (sock < 0) {
       
   403 	perror("socket(unix)");
       
   404 	return -1;
       
   405     }
       
   406 
       
   407     memset(&un, 0, sizeof(un));
       
   408     un.sun_family = AF_UNIX;
       
   409     snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
       
   410     if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
       
   411         fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
       
   412 	return -1;
       
   413     }
       
   414 
       
   415     if (sockets_debug)
       
   416         fprintf(stderr, "connect(unix:%s): OK\n", path);
       
   417     return sock;
       
   418 }
       
   419 
       
   420 #else
       
   421 
       
   422 int unix_listen(const char *path, char *ostr, int olen)
       
   423 {
       
   424     fprintf(stderr, "unix sockets are not available on windows\n");
       
   425     return -1;
       
   426 }
       
   427 
       
   428 int unix_connect(const char *path)
       
   429 {
       
   430     fprintf(stderr, "unix sockets are not available on windows\n");
       
   431     return -1;
       
   432 }
       
   433 
       
   434 #endif