blob: 13c0b93492208de6ac081028f593153c9292dc4a [file] [log] [blame]
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001/*
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
29static int sockets_debug = 0;
30static const int on=1, off=0;
31
David Turner315ceb82010-09-10 14:15:17 +020032/* used temporarely until all users are converted to QemuOpts */
33static 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,
David 'Digit' Turner8423ffa2010-12-23 00:57:28 +010055#ifdef CONFIG_ANDROID
56 },{
57 .name = "socket",
58 .type = QEMU_OPT_NUMBER,
59#endif
David Turner315ceb82010-09-10 14:15:17 +020060 },
61 { /* end if list */ }
62 },
63};
64
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070065static 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
82static 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
David Turner315ceb82010-09-10 14:15:17 +020099const char *inet_strfamily(int family)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700100{
101 switch (family) {
102 case PF_INET6: return "ipv6";
103 case PF_INET: return "ipv4";
104 case PF_UNIX: return "unix";
105 }
David Turner315ceb82010-09-10 14:15:17 +0200106 return "unknown";
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700107}
108
109static 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
David Turner315ceb82010-09-10 14:15:17 +0200124int inet_listen_opts(QemuOpts *opts, int port_offset)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700125{
126 struct addrinfo ai,*res,*e;
David Turner315ceb82010-09-10 14:15:17 +0200127 const char *addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700128 char port[33];
129 char uaddr[INET6_ADDRSTRLEN+1];
130 char uport[33];
David Turner315ceb82010-09-10 14:15:17 +0200131 int slisten,rc,to,try_next;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700132
133 memset(&ai,0, sizeof(ai));
134 ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
135 ai.ai_family = PF_UNSPEC;
David Turner315ceb82010-09-10 14:15:17 +0200136 ai.ai_socktype = SOCK_STREAM;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700137
David 'Digit' Turner8423ffa2010-12-23 00:57:28 +0100138#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
David Turner315ceb82010-09-10 14:15:17 +0200145 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;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700149 }
David Turner315ceb82010-09-10 14:15:17 +0200150 pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
151 addr = qemu_opt_get(opts, "host");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700152
David Turner315ceb82010-09-10 14:15:17 +0200153 to = qemu_opt_get_number(opts, "to", 0);
154 if (qemu_opt_get_bool(opts, "ipv4", 0))
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700155 ai.ai_family = PF_INET;
David Turner315ceb82010-09-10 14:15:17 +0200156 if (qemu_opt_get_bool(opts, "ipv6", 0))
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700157 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) {
David Turner315ceb82010-09-10 14:15:17 +0200164 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
165 gai_strerror(rc));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700166 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);
David Turner315ceb82010-09-10 14:15:17 +0200176 slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700177 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 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 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
216listen:
217 if (listen(slisten,1) != 0) {
218 perror("listen");
219 closesocket(slisten);
220 freeaddrinfo(res);
221 return -1;
222 }
David Turner315ceb82010-09-10 14:15:17 +0200223 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");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700228 freeaddrinfo(res);
229 return slisten;
230}
231
David Turner315ceb82010-09-10 14:15:17 +0200232int inet_connect_opts(QemuOpts *opts)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700233{
234 struct addrinfo ai,*res,*e;
David Turner315ceb82010-09-10 14:15:17 +0200235 const char *addr;
236 const char *port;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700237 char uaddr[INET6_ADDRSTRLEN+1];
238 char uport[33];
239 int sock,rc;
240
David 'Digit' Turner8423ffa2010-12-23 00:57:28 +0100241#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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700248 memset(&ai,0, sizeof(ai));
249 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
250 ai.ai_family = PF_UNSPEC;
David Turner315ceb82010-09-10 14:15:17 +0200251 ai.ai_socktype = SOCK_STREAM;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700252
David Turner315ceb82010-09-10 14:15:17 +0200253 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;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700258 }
259
David Turner315ceb82010-09-10 14:15:17 +0200260 if (qemu_opt_get_bool(opts, "ipv4", 0))
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700261 ai.ai_family = PF_INET;
David Turner315ceb82010-09-10 14:15:17 +0200262 if (qemu_opt_get_bool(opts, "ipv6", 0))
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700263 ai.ai_family = PF_INET6;
264
265 /* lookup */
266 if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
David Turner315ceb82010-09-10 14:15:17 +0200267 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
268 gai_strerror(rc));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700269 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 }
David Turner315ceb82010-09-10 14:15:17 +0200281 sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700282 if (sock < 0) {
283 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
284 inet_strfamily(e->ai_family), strerror(errno));
285 continue;
286 }
287 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
David Turner315ceb82010-09-10 14:15:17 +0200309int 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 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
413err:
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 */
424static 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");
David 'Digit' Turner8423ffa2010-12-23 00:57:28 +0100476#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
David Turner315ceb82010-09-10 14:15:17 +0200495 return 0;
496}
497
498int 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
527int 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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700539#ifndef _WIN32
540
David Turner315ceb82010-09-10 14:15:17 +0200541int unix_listen_opts(QemuOpts *opts)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700542{
543 struct sockaddr_un un;
David Turner315ceb82010-09-10 14:15:17 +0200544 const char *path = qemu_opt_get(opts, "path");
545 int sock, fd;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700546
David Turner315ceb82010-09-10 14:15:17 +0200547 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700548 if (sock < 0) {
549 perror("socket(unix)");
550 return -1;
551 }
552
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700553 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);
David Turner315ceb82010-09-10 14:15:17 +0200569 qemu_opt_set(opts, "path", un.sun_path);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700570 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700571
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);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700584 return sock;
585
586err:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700587 closesocket(sock);
588 return -1;
589}
590
David Turner315ceb82010-09-10 14:15:17 +0200591int unix_connect_opts(QemuOpts *opts)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700592{
593 struct sockaddr_un un;
David Turner315ceb82010-09-10 14:15:17 +0200594 const char *path = qemu_opt_get(opts, "path");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700595 int sock;
596
David Turner315ceb82010-09-10 14:15:17 +0200597 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);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700603 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
David Turner315ceb82010-09-10 14:15:17 +0200621/* compatibility wrapper */
622int 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 = qemu_malloc(len+1);
635 snprintf(path, len+1, "%.*s", len, str);
636 qemu_opt_set(opts, "path", path);
637 qemu_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
651int 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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700663#else
664
David Turner315ceb82010-09-10 14:15:17 +0200665int unix_listen_opts(QemuOpts *opts)
666{
667 fprintf(stderr, "unix sockets are not available on windows\n");
David 'Digit' Turner488bfd52011-05-09 17:08:24 +0200668 errno = ENOTSUP;
David Turner315ceb82010-09-10 14:15:17 +0200669 return -1;
670}
671
672int unix_connect_opts(QemuOpts *opts)
673{
674 fprintf(stderr, "unix sockets are not available on windows\n");
David 'Digit' Turner488bfd52011-05-09 17:08:24 +0200675 errno = ENOTSUP;
David Turner315ceb82010-09-10 14:15:17 +0200676 return -1;
677}
678
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700679int unix_listen(const char *path, char *ostr, int olen)
680{
681 fprintf(stderr, "unix sockets are not available on windows\n");
David 'Digit' Turner488bfd52011-05-09 17:08:24 +0200682 errno = ENOTSUP;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700683 return -1;
684}
685
686int unix_connect(const char *path)
687{
688 fprintf(stderr, "unix sockets are not available on windows\n");
David 'Digit' Turner488bfd52011-05-09 17:08:24 +0200689 errno = ENOTSUP;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700690 return -1;
691}
692
693#endif
David Turner315ceb82010-09-10 14:15:17 +0200694
695#ifdef _WIN32
696static void socket_cleanup(void)
697{
698 WSACleanup();
699}
700#endif
701
702int 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}