1 /* 2 * inet and unix socket functions for qemu 3 * 4 * (c) 2008 Gerd Hoffmann <kraxel (at) 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/sockets.h" 23 #include "qemu-common.h" /* for qemu_isdigit */ 24 25 #ifndef AI_ADDRCONFIG 26 # define AI_ADDRCONFIG 0 27 #endif 28 29 static int sockets_debug = 0; 30 static const int on=1, off=0; 31 32 /* used temporarely until all users are converted to QemuOpts */ 33 static QemuOptsList dummy_opts = { 34 .name = "dummy", 35 .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head), 36 .desc = { 37 { 38 .name = "path", 39 .type = QEMU_OPT_STRING, 40 },{ 41 .name = "host", 42 .type = QEMU_OPT_STRING, 43 },{ 44 .name = "port", 45 .type = QEMU_OPT_STRING, 46 },{ 47 .name = "to", 48 .type = QEMU_OPT_NUMBER, 49 },{ 50 .name = "ipv4", 51 .type = QEMU_OPT_BOOL, 52 },{ 53 .name = "ipv6", 54 .type = QEMU_OPT_BOOL, 55 #ifdef CONFIG_ANDROID 56 },{ 57 .name = "socket", 58 .type = QEMU_OPT_NUMBER, 59 #endif 60 }, 61 { /* end if list */ } 62 }, 63 }; 64 65 static int inet_getport(struct addrinfo *e) 66 { 67 struct sockaddr_in *i4; 68 struct sockaddr_in6 *i6; 69 70 switch (e->ai_family) { 71 case PF_INET6: 72 i6 = (void*)e->ai_addr; 73 return ntohs(i6->sin6_port); 74 case PF_INET: 75 i4 = (void*)e->ai_addr; 76 return ntohs(i4->sin_port); 77 default: 78 return 0; 79 } 80 } 81 82 static void inet_setport(struct addrinfo *e, int port) 83 { 84 struct sockaddr_in *i4; 85 struct sockaddr_in6 *i6; 86 87 switch (e->ai_family) { 88 case PF_INET6: 89 i6 = (void*)e->ai_addr; 90 i6->sin6_port = htons(port); 91 break; 92 case PF_INET: 93 i4 = (void*)e->ai_addr; 94 i4->sin_port = htons(port); 95 break; 96 } 97 } 98 99 const char *inet_strfamily(int family) 100 { 101 switch (family) { 102 case PF_INET6: return "ipv6"; 103 case PF_INET: return "ipv4"; 104 case PF_UNIX: return "unix"; 105 } 106 return "unknown"; 107 } 108 109 static void inet_print_addrinfo(const char *tag, struct addrinfo *res) 110 { 111 struct addrinfo *e; 112 char uaddr[INET6_ADDRSTRLEN+1]; 113 char uport[33]; 114 115 for (e = res; e != NULL; e = e->ai_next) { 116 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 117 uaddr,INET6_ADDRSTRLEN,uport,32, 118 NI_NUMERICHOST | NI_NUMERICSERV); 119 fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", 120 tag, inet_strfamily(e->ai_family), uaddr, uport); 121 } 122 } 123 124 int inet_listen_opts(QemuOpts *opts, int port_offset) 125 { 126 struct addrinfo ai,*res,*e; 127 const char *addr; 128 char port[33]; 129 char uaddr[INET6_ADDRSTRLEN+1]; 130 char uport[33]; 131 int slisten,rc,to,try_next; 132 133 memset(&ai,0, sizeof(ai)); 134 ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; 135 ai.ai_family = PF_UNSPEC; 136 ai.ai_socktype = SOCK_STREAM; 137 138 #ifdef CONFIG_ANDROID 139 const char* socket_fd = qemu_opt_get(opts, "socket"); 140 if (socket_fd) { 141 return atoi(socket_fd); 142 } 143 #endif 144 145 if ((qemu_opt_get(opts, "host") == NULL) || 146 (qemu_opt_get(opts, "port") == NULL)) { 147 fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__); 148 return -1; 149 } 150 pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); 151 addr = qemu_opt_get(opts, "host"); 152 153 to = qemu_opt_get_number(opts, "to", 0); 154 if (qemu_opt_get_bool(opts, "ipv4", 0)) 155 ai.ai_family = PF_INET; 156 if (qemu_opt_get_bool(opts, "ipv6", 0)) 157 ai.ai_family = PF_INET6; 158 159 /* lookup */ 160 if (port_offset) 161 snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); 162 rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); 163 if (rc != 0) { 164 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 165 gai_strerror(rc)); 166 return -1; 167 } 168 if (sockets_debug) 169 inet_print_addrinfo(__FUNCTION__, res); 170 171 /* create socket + bind */ 172 for (e = res; e != NULL; e = e->ai_next) { 173 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 174 uaddr,INET6_ADDRSTRLEN,uport,32, 175 NI_NUMERICHOST | NI_NUMERICSERV); 176 slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); 177 if (slisten < 0) { 178 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 179 inet_strfamily(e->ai_family), strerror(errno)); 180 continue; 181 } 182 183 qemu_setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 184 #ifdef IPV6_V6ONLY 185 if (e->ai_family == PF_INET6) { 186 /* listen on both ipv4 and ipv6 */ 187 qemu_setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, 188 sizeof(off)); 189 } 190 #endif 191 192 for (;;) { 193 if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { 194 if (sockets_debug) 195 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 196 inet_strfamily(e->ai_family), uaddr, inet_getport(e)); 197 goto listen; 198 } 199 try_next = to && (inet_getport(e) <= to + port_offset); 200 if (!try_next || sockets_debug) 201 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, 202 inet_strfamily(e->ai_family), uaddr, inet_getport(e), 203 strerror(errno)); 204 if (try_next) { 205 inet_setport(e, inet_getport(e) + 1); 206 continue; 207 } 208 break; 209 } 210 closesocket(slisten); 211 } 212 fprintf(stderr, "%s: FAILED\n", __FUNCTION__); 213 freeaddrinfo(res); 214 return -1; 215 216 listen: 217 if (listen(slisten,1) != 0) { 218 perror("listen"); 219 closesocket(slisten); 220 freeaddrinfo(res); 221 return -1; 222 } 223 snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset); 224 qemu_opt_set(opts, "host", uaddr); 225 qemu_opt_set(opts, "port", uport); 226 qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off"); 227 qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off"); 228 freeaddrinfo(res); 229 return slisten; 230 } 231 232 int inet_connect_opts(QemuOpts *opts) 233 { 234 struct addrinfo ai,*res,*e; 235 const char *addr; 236 const char *port; 237 char uaddr[INET6_ADDRSTRLEN+1]; 238 char uport[33]; 239 int sock,rc; 240 241 #ifdef CONFIG_ANDROID 242 const char* socket_fd = qemu_opt_get(opts, "socket"); 243 if (socket_fd) { 244 return atoi(socket_fd); 245 } 246 #endif 247 248 memset(&ai,0, sizeof(ai)); 249 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 250 ai.ai_family = PF_UNSPEC; 251 ai.ai_socktype = SOCK_STREAM; 252 253 addr = qemu_opt_get(opts, "host"); 254 port = qemu_opt_get(opts, "port"); 255 if (addr == NULL || port == NULL) { 256 fprintf(stderr, "inet_connect: host and/or port not specified\n"); 257 return -1; 258 } 259 260 if (qemu_opt_get_bool(opts, "ipv4", 0)) 261 ai.ai_family = PF_INET; 262 if (qemu_opt_get_bool(opts, "ipv6", 0)) 263 ai.ai_family = PF_INET6; 264 265 /* lookup */ 266 if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { 267 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 268 gai_strerror(rc)); 269 return -1; 270 } 271 if (sockets_debug) 272 inet_print_addrinfo(__FUNCTION__, res); 273 274 for (e = res; e != NULL; e = e->ai_next) { 275 if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 276 uaddr,INET6_ADDRSTRLEN,uport,32, 277 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 278 fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); 279 continue; 280 } 281 sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); 282 if (sock < 0) { 283 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 284 inet_strfamily(e->ai_family), strerror(errno)); 285 continue; 286 } 287 qemu_setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 288 289 /* connect to peer */ 290 if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { 291 if (sockets_debug || NULL == e->ai_next) 292 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 293 inet_strfamily(e->ai_family), 294 e->ai_canonname, uaddr, uport, strerror(errno)); 295 closesocket(sock); 296 continue; 297 } 298 if (sockets_debug) 299 fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, 300 inet_strfamily(e->ai_family), 301 e->ai_canonname, uaddr, uport); 302 freeaddrinfo(res); 303 return sock; 304 } 305 freeaddrinfo(res); 306 return -1; 307 } 308 309 int inet_dgram_opts(QemuOpts *opts) 310 { 311 struct addrinfo ai, *peer = NULL, *local = NULL; 312 const char *addr; 313 const char *port; 314 char uaddr[INET6_ADDRSTRLEN+1]; 315 char uport[33]; 316 int sock = -1, rc; 317 318 /* lookup peer addr */ 319 memset(&ai,0, sizeof(ai)); 320 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 321 ai.ai_family = PF_UNSPEC; 322 ai.ai_socktype = SOCK_DGRAM; 323 324 addr = qemu_opt_get(opts, "host"); 325 port = qemu_opt_get(opts, "port"); 326 if (addr == NULL || strlen(addr) == 0) { 327 addr = "localhost"; 328 } 329 if (port == NULL || strlen(port) == 0) { 330 fprintf(stderr, "inet_dgram: port not specified\n"); 331 return -1; 332 } 333 334 if (qemu_opt_get_bool(opts, "ipv4", 0)) 335 ai.ai_family = PF_INET; 336 if (qemu_opt_get_bool(opts, "ipv6", 0)) 337 ai.ai_family = PF_INET6; 338 339 if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { 340 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 341 gai_strerror(rc)); 342 return -1; 343 } 344 if (sockets_debug) { 345 fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port); 346 inet_print_addrinfo(__FUNCTION__, peer); 347 } 348 349 /* lookup local addr */ 350 memset(&ai,0, sizeof(ai)); 351 ai.ai_flags = AI_PASSIVE; 352 ai.ai_family = peer->ai_family; 353 ai.ai_socktype = SOCK_DGRAM; 354 355 addr = qemu_opt_get(opts, "localaddr"); 356 port = qemu_opt_get(opts, "localport"); 357 if (addr == NULL || strlen(addr) == 0) { 358 addr = NULL; 359 } 360 if (!port || strlen(port) == 0) 361 port = "0"; 362 363 if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { 364 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 365 gai_strerror(rc)); 366 return -1; 367 } 368 if (sockets_debug) { 369 fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port); 370 inet_print_addrinfo(__FUNCTION__, local); 371 } 372 373 /* create socket */ 374 sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); 375 if (sock < 0) { 376 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 377 inet_strfamily(peer->ai_family), strerror(errno)); 378 goto err; 379 } 380 qemu_setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 381 382 /* bind socket */ 383 if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen, 384 uaddr,INET6_ADDRSTRLEN,uport,32, 385 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 386 fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); 387 goto err; 388 } 389 if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { 390 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 391 inet_strfamily(local->ai_family), uaddr, inet_getport(local)); 392 goto err; 393 } 394 395 /* connect to peer */ 396 if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen, 397 uaddr, INET6_ADDRSTRLEN, uport, 32, 398 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 399 fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); 400 goto err; 401 } 402 if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { 403 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 404 inet_strfamily(peer->ai_family), 405 peer->ai_canonname, uaddr, uport, strerror(errno)); 406 goto err; 407 } 408 409 freeaddrinfo(local); 410 freeaddrinfo(peer); 411 return sock; 412 413 err: 414 if (-1 != sock) 415 closesocket(sock); 416 if (local) 417 freeaddrinfo(local); 418 if (peer) 419 freeaddrinfo(peer); 420 return -1; 421 } 422 423 /* compatibility wrapper */ 424 static int inet_parse(QemuOpts *opts, const char *str) 425 { 426 const char *optstr, *h; 427 char addr[64]; 428 char port[33]; 429 int pos; 430 431 /* parse address */ 432 if (str[0] == ':') { 433 /* no host given */ 434 addr[0] = '\0'; 435 if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { 436 fprintf(stderr, "%s: portonly parse error (%s)\n", 437 __FUNCTION__, str); 438 return -1; 439 } 440 } else if (str[0] == '[') { 441 /* IPv6 addr */ 442 if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { 443 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 444 __FUNCTION__, str); 445 return -1; 446 } 447 qemu_opt_set(opts, "ipv6", "on"); 448 } else if (qemu_isdigit(str[0])) { 449 /* IPv4 addr */ 450 if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { 451 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 452 __FUNCTION__, str); 453 return -1; 454 } 455 qemu_opt_set(opts, "ipv4", "on"); 456 } else { 457 /* hostname */ 458 if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { 459 fprintf(stderr, "%s: hostname parse error (%s)\n", 460 __FUNCTION__, str); 461 return -1; 462 } 463 } 464 qemu_opt_set(opts, "host", addr); 465 qemu_opt_set(opts, "port", port); 466 467 /* parse options */ 468 optstr = str + pos; 469 h = strstr(optstr, ",to="); 470 if (h) 471 qemu_opt_set(opts, "to", h+4); 472 if (strstr(optstr, ",ipv4")) 473 qemu_opt_set(opts, "ipv4", "on"); 474 if (strstr(optstr, ",ipv6")) 475 qemu_opt_set(opts, "ipv6", "on"); 476 #ifdef CONFIG_ANDROID 477 h = strstr(optstr, ",socket="); 478 if (h) { 479 int socket_fd; 480 char str_fd[12]; 481 if (1 != sscanf(h+7,"%d",&socket_fd)) { 482 fprintf(stderr,"%s: socket fd parse error (%s)\n", 483 __FUNCTION__, h+7); 484 return -1; 485 } 486 if (socket_fd < 0 || socket_fd >= INT_MAX) { 487 fprintf(stderr,"%s: socket fd range error (%d)\n", 488 __FUNCTION__, socket_fd); 489 return -1; 490 } 491 snprintf(str_fd, sizeof str_fd, "%d", socket_fd); 492 qemu_opt_set(opts, "socket", str_fd); 493 } 494 #endif 495 return 0; 496 } 497 498 int inet_listen(const char *str, char *ostr, int olen, 499 int socktype, int port_offset) 500 { 501 QemuOpts *opts; 502 char *optstr; 503 int sock = -1; 504 505 opts = qemu_opts_create(&dummy_opts, NULL, 0); 506 if (inet_parse(opts, str) == 0) { 507 sock = inet_listen_opts(opts, port_offset); 508 if (sock != -1 && ostr) { 509 optstr = strchr(str, ','); 510 if (qemu_opt_get_bool(opts, "ipv6", 0)) { 511 snprintf(ostr, olen, "[%s]:%s%s", 512 qemu_opt_get(opts, "host"), 513 qemu_opt_get(opts, "port"), 514 optstr ? optstr : ""); 515 } else { 516 snprintf(ostr, olen, "%s:%s%s", 517 qemu_opt_get(opts, "host"), 518 qemu_opt_get(opts, "port"), 519 optstr ? optstr : ""); 520 } 521 } 522 } 523 qemu_opts_del(opts); 524 return sock; 525 } 526 527 int inet_connect(const char *str, int socktype) 528 { 529 QemuOpts *opts; 530 int sock = -1; 531 532 opts = qemu_opts_create(&dummy_opts, NULL, 0); 533 if (inet_parse(opts, str) == 0) 534 sock = inet_connect_opts(opts); 535 qemu_opts_del(opts); 536 return sock; 537 } 538 539 #ifndef _WIN32 540 541 int unix_listen_opts(QemuOpts *opts) 542 { 543 struct sockaddr_un un; 544 const char *path = qemu_opt_get(opts, "path"); 545 int sock, fd; 546 547 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 548 if (sock < 0) { 549 perror("socket(unix)"); 550 return -1; 551 } 552 553 memset(&un, 0, sizeof(un)); 554 un.sun_family = AF_UNIX; 555 if (path && strlen(path)) { 556 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 557 } else { 558 char *tmpdir = getenv("TMPDIR"); 559 snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", 560 tmpdir ? tmpdir : "/tmp"); 561 /* 562 * This dummy fd usage silences the mktemp() unsecure warning. 563 * Using mkstemp() doesn't make things more secure here 564 * though. bind() complains about existing files, so we have 565 * to unlink first and thus re-open the race window. The 566 * worst case possible is bind() failing, i.e. a DoS attack. 567 */ 568 fd = mkstemp(un.sun_path); close(fd); 569 qemu_opt_set(opts, "path", un.sun_path); 570 } 571 572 unlink(un.sun_path); 573 if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 574 fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); 575 goto err; 576 } 577 if (listen(sock, 1) < 0) { 578 fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); 579 goto err; 580 } 581 582 if (sockets_debug) 583 fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); 584 return sock; 585 586 err: 587 closesocket(sock); 588 return -1; 589 } 590 591 int unix_connect_opts(QemuOpts *opts) 592 { 593 struct sockaddr_un un; 594 const char *path = qemu_opt_get(opts, "path"); 595 int sock; 596 597 if (NULL == path) { 598 fprintf(stderr, "unix connect: no path specified\n"); 599 return -1; 600 } 601 602 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 603 if (sock < 0) { 604 perror("socket(unix)"); 605 return -1; 606 } 607 608 memset(&un, 0, sizeof(un)); 609 un.sun_family = AF_UNIX; 610 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 611 if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 612 fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); 613 return -1; 614 } 615 616 if (sockets_debug) 617 fprintf(stderr, "connect(unix:%s): OK\n", path); 618 return sock; 619 } 620 621 /* compatibility wrapper */ 622 int unix_listen(const char *str, char *ostr, int olen) 623 { 624 QemuOpts *opts; 625 char *path, *optstr; 626 int sock, len; 627 628 opts = qemu_opts_create(&dummy_opts, NULL, 0); 629 630 optstr = strchr(str, ','); 631 if (optstr) { 632 len = optstr - str; 633 if (len) { 634 path = g_malloc(len+1); 635 snprintf(path, len+1, "%.*s", len, str); 636 qemu_opt_set(opts, "path", path); 637 g_free(path); 638 } 639 } else { 640 qemu_opt_set(opts, "path", str); 641 } 642 643 sock = unix_listen_opts(opts); 644 645 if (sock != -1 && ostr) 646 snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : ""); 647 qemu_opts_del(opts); 648 return sock; 649 } 650 651 int unix_connect(const char *path) 652 { 653 QemuOpts *opts; 654 int sock; 655 656 opts = qemu_opts_create(&dummy_opts, NULL, 0); 657 qemu_opt_set(opts, "path", path); 658 sock = unix_connect_opts(opts); 659 qemu_opts_del(opts); 660 return sock; 661 } 662 663 #else 664 665 int unix_listen_opts(QemuOpts *opts) 666 { 667 fprintf(stderr, "unix sockets are not available on windows\n"); 668 errno = ENOTSUP; 669 return -1; 670 } 671 672 int unix_connect_opts(QemuOpts *opts) 673 { 674 fprintf(stderr, "unix sockets are not available on windows\n"); 675 errno = ENOTSUP; 676 return -1; 677 } 678 679 int unix_listen(const char *path, char *ostr, int olen) 680 { 681 fprintf(stderr, "unix sockets are not available on windows\n"); 682 errno = ENOTSUP; 683 return -1; 684 } 685 686 int unix_connect(const char *path) 687 { 688 fprintf(stderr, "unix sockets are not available on windows\n"); 689 errno = ENOTSUP; 690 return -1; 691 } 692 693 #endif 694 695 #ifdef _WIN32 696 static void socket_cleanup(void) 697 { 698 WSACleanup(); 699 } 700 #endif 701 702 int socket_init(void) 703 { 704 #ifdef _WIN32 705 WSADATA Data; 706 int ret, err; 707 708 ret = WSAStartup(MAKEWORD(2,2), &Data); 709 if (ret != 0) { 710 err = WSAGetLastError(); 711 fprintf(stderr, "WSAStartup: %d\n", err); 712 return -1; 713 } 714 atexit(socket_cleanup); 715 #endif 716 return 0; 717 } 718