xref: /openbmc/qemu/util/qemu-sockets.c (revision b8bcf811)
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  * Contributions after 2012-01-13 are licensed under the terms of the
16  * GNU GPL, version 2 or (at your option) any later version.
17  */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <unistd.h>
24 
25 #include "monitor/monitor.h"
26 #include "qemu/sockets.h"
27 #include "qemu/main-loop.h"
28 
29 #ifndef AI_ADDRCONFIG
30 # define AI_ADDRCONFIG 0
31 #endif
32 
33 static const int on=1, off=0;
34 
35 /* used temporarily until all users are converted to QemuOpts */
36 QemuOptsList socket_optslist = {
37     .name = "socket",
38     .head = QTAILQ_HEAD_INITIALIZER(socket_optslist.head),
39     .desc = {
40         {
41             .name = "path",
42             .type = QEMU_OPT_STRING,
43         },{
44             .name = "host",
45             .type = QEMU_OPT_STRING,
46         },{
47             .name = "port",
48             .type = QEMU_OPT_STRING,
49         },{
50             .name = "to",
51             .type = QEMU_OPT_NUMBER,
52         },{
53             .name = "ipv4",
54             .type = QEMU_OPT_BOOL,
55         },{
56             .name = "ipv6",
57             .type = QEMU_OPT_BOOL,
58         },
59         { /* end if list */ }
60     },
61 };
62 
63 static int inet_getport(struct addrinfo *e)
64 {
65     struct sockaddr_in *i4;
66     struct sockaddr_in6 *i6;
67 
68     switch (e->ai_family) {
69     case PF_INET6:
70         i6 = (void*)e->ai_addr;
71         return ntohs(i6->sin6_port);
72     case PF_INET:
73         i4 = (void*)e->ai_addr;
74         return ntohs(i4->sin_port);
75     default:
76         return 0;
77     }
78 }
79 
80 static void inet_setport(struct addrinfo *e, int port)
81 {
82     struct sockaddr_in *i4;
83     struct sockaddr_in6 *i6;
84 
85     switch (e->ai_family) {
86     case PF_INET6:
87         i6 = (void*)e->ai_addr;
88         i6->sin6_port = htons(port);
89         break;
90     case PF_INET:
91         i4 = (void*)e->ai_addr;
92         i4->sin_port = htons(port);
93         break;
94     }
95 }
96 
97 const char *inet_strfamily(int family)
98 {
99     switch (family) {
100     case PF_INET6: return "ipv6";
101     case PF_INET:  return "ipv4";
102     case PF_UNIX:  return "unix";
103     }
104     return "unknown";
105 }
106 
107 int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
108 {
109     struct addrinfo ai,*res,*e;
110     const char *addr;
111     char port[33];
112     char uaddr[INET6_ADDRSTRLEN+1];
113     char uport[33];
114     int slisten, rc, to, port_min, port_max, p;
115 
116     memset(&ai,0, sizeof(ai));
117     ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
118     ai.ai_family = PF_UNSPEC;
119     ai.ai_socktype = SOCK_STREAM;
120 
121     if ((qemu_opt_get(opts, "host") == NULL) ||
122         (qemu_opt_get(opts, "port") == NULL)) {
123         error_setg(errp, "host and/or port not specified");
124         return -1;
125     }
126     pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
127     addr = qemu_opt_get(opts, "host");
128 
129     to = qemu_opt_get_number(opts, "to", 0);
130     if (qemu_opt_get_bool(opts, "ipv4", 0))
131         ai.ai_family = PF_INET;
132     if (qemu_opt_get_bool(opts, "ipv6", 0))
133         ai.ai_family = PF_INET6;
134 
135     /* lookup */
136     if (port_offset)
137         snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
138     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
139     if (rc != 0) {
140         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
141                    gai_strerror(rc));
142         return -1;
143     }
144 
145     /* create socket + bind */
146     for (e = res; e != NULL; e = e->ai_next) {
147         getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
148 		        uaddr,INET6_ADDRSTRLEN,uport,32,
149 		        NI_NUMERICHOST | NI_NUMERICSERV);
150         slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
151         if (slisten < 0) {
152             if (!e->ai_next) {
153                 error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
154             }
155             continue;
156         }
157 
158         socket_set_fast_reuse(slisten);
159 #ifdef IPV6_V6ONLY
160         if (e->ai_family == PF_INET6) {
161             /* listen on both ipv4 and ipv6 */
162             qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off,
163                             sizeof(off));
164         }
165 #endif
166 
167         port_min = inet_getport(e);
168         port_max = to ? to + port_offset : port_min;
169         for (p = port_min; p <= port_max; p++) {
170             inet_setport(e, p);
171             if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
172                 goto listen;
173             }
174             if (p == port_max) {
175                 if (!e->ai_next) {
176                     error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
177                 }
178             }
179         }
180         closesocket(slisten);
181     }
182     freeaddrinfo(res);
183     return -1;
184 
185 listen:
186     if (listen(slisten,1) != 0) {
187         error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED);
188         closesocket(slisten);
189         freeaddrinfo(res);
190         return -1;
191     }
192     snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
193     qemu_opt_set(opts, "host", uaddr);
194     qemu_opt_set(opts, "port", uport);
195     qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
196     qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
197     freeaddrinfo(res);
198     return slisten;
199 }
200 
201 #ifdef _WIN32
202 #define QEMU_SOCKET_RC_INPROGRESS(rc) \
203     ((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY)
204 #else
205 #define QEMU_SOCKET_RC_INPROGRESS(rc) \
206     ((rc) == -EINPROGRESS)
207 #endif
208 
209 /* Struct to store connect state for non blocking connect */
210 typedef struct ConnectState {
211     int fd;
212     struct addrinfo *addr_list;
213     struct addrinfo *current_addr;
214     NonBlockingConnectHandler *callback;
215     void *opaque;
216 } ConnectState;
217 
218 static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
219                              ConnectState *connect_state, Error **errp);
220 
221 static void wait_for_connect(void *opaque)
222 {
223     ConnectState *s = opaque;
224     int val = 0, rc = 0;
225     socklen_t valsize = sizeof(val);
226     bool in_progress;
227 
228     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
229 
230     do {
231         rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
232     } while (rc == -1 && socket_error() == EINTR);
233 
234     /* update rc to contain error */
235     if (!rc && val) {
236         rc = -1;
237     }
238 
239     /* connect error */
240     if (rc < 0) {
241         closesocket(s->fd);
242         s->fd = rc;
243     }
244 
245     /* try to connect to the next address on the list */
246     if (s->current_addr) {
247         while (s->current_addr->ai_next != NULL && s->fd < 0) {
248             s->current_addr = s->current_addr->ai_next;
249             s->fd = inet_connect_addr(s->current_addr, &in_progress, s, NULL);
250             /* connect in progress */
251             if (in_progress) {
252                 return;
253             }
254         }
255 
256         freeaddrinfo(s->addr_list);
257     }
258 
259     if (s->callback) {
260         s->callback(s->fd, s->opaque);
261     }
262     g_free(s);
263 }
264 
265 static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
266                              ConnectState *connect_state, Error **errp)
267 {
268     int sock, rc;
269 
270     *in_progress = false;
271 
272     sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
273     if (sock < 0) {
274         error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
275         return -1;
276     }
277     socket_set_fast_reuse(sock);
278     if (connect_state != NULL) {
279         qemu_set_nonblock(sock);
280     }
281     /* connect to peer */
282     do {
283         rc = 0;
284         if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
285             rc = -socket_error();
286         }
287     } while (rc == -EINTR);
288 
289     if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
290         connect_state->fd = sock;
291         qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
292                              connect_state);
293         *in_progress = true;
294     } else if (rc < 0) {
295         error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED);
296         closesocket(sock);
297         return -1;
298     }
299     return sock;
300 }
301 
302 static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
303 {
304     struct addrinfo ai, *res;
305     int rc;
306     const char *addr;
307     const char *port;
308 
309     memset(&ai, 0, sizeof(ai));
310 
311     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
312     ai.ai_family = PF_UNSPEC;
313     ai.ai_socktype = SOCK_STREAM;
314 
315     addr = qemu_opt_get(opts, "host");
316     port = qemu_opt_get(opts, "port");
317     if (addr == NULL || port == NULL) {
318         error_setg(errp, "host and/or port not specified");
319         return NULL;
320     }
321 
322     if (qemu_opt_get_bool(opts, "ipv4", 0)) {
323         ai.ai_family = PF_INET;
324     }
325     if (qemu_opt_get_bool(opts, "ipv6", 0)) {
326         ai.ai_family = PF_INET6;
327     }
328 
329     /* lookup */
330     rc = getaddrinfo(addr, port, &ai, &res);
331     if (rc != 0) {
332         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
333                    gai_strerror(rc));
334         return NULL;
335     }
336     return res;
337 }
338 
339 /**
340  * Create a socket and connect it to an address.
341  *
342  * @opts: QEMU options, recognized parameters strings "host" and "port",
343  *        bools "ipv4" and "ipv6".
344  * @errp: set on error
345  * @callback: callback function for non-blocking connect
346  * @opaque: opaque for callback function
347  *
348  * Returns: -1 on error, file descriptor on success.
349  *
350  * If @callback is non-null, the connect is non-blocking.  If this
351  * function succeeds, callback will be called when the connection
352  * completes, with the file descriptor on success, or -1 on error.
353  */
354 int inet_connect_opts(QemuOpts *opts, Error **errp,
355                       NonBlockingConnectHandler *callback, void *opaque)
356 {
357     struct addrinfo *res, *e;
358     int sock = -1;
359     bool in_progress;
360     ConnectState *connect_state = NULL;
361 
362     res = inet_parse_connect_opts(opts, errp);
363     if (!res) {
364         return -1;
365     }
366 
367     if (callback != NULL) {
368         connect_state = g_malloc0(sizeof(*connect_state));
369         connect_state->addr_list = res;
370         connect_state->callback = callback;
371         connect_state->opaque = opaque;
372     }
373 
374     for (e = res; e != NULL; e = e->ai_next) {
375         if (error_is_set(errp)) {
376             error_free(*errp);
377             *errp = NULL;
378         }
379         if (connect_state != NULL) {
380             connect_state->current_addr = e;
381         }
382         sock = inet_connect_addr(e, &in_progress, connect_state, errp);
383         if (in_progress) {
384             return sock;
385         } else if (sock >= 0) {
386             /* non blocking socket immediate success, call callback */
387             if (callback != NULL) {
388                 callback(sock, opaque);
389             }
390             break;
391         }
392     }
393     g_free(connect_state);
394     freeaddrinfo(res);
395     return sock;
396 }
397 
398 int inet_dgram_opts(QemuOpts *opts, Error **errp)
399 {
400     struct addrinfo ai, *peer = NULL, *local = NULL;
401     const char *addr;
402     const char *port;
403     int sock = -1, rc;
404 
405     /* lookup peer addr */
406     memset(&ai,0, sizeof(ai));
407     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
408     ai.ai_family = PF_UNSPEC;
409     ai.ai_socktype = SOCK_DGRAM;
410 
411     addr = qemu_opt_get(opts, "host");
412     port = qemu_opt_get(opts, "port");
413     if (addr == NULL || strlen(addr) == 0) {
414         addr = "localhost";
415     }
416     if (port == NULL || strlen(port) == 0) {
417         error_setg(errp, "remote port not specified");
418         return -1;
419     }
420 
421     if (qemu_opt_get_bool(opts, "ipv4", 0))
422         ai.ai_family = PF_INET;
423     if (qemu_opt_get_bool(opts, "ipv6", 0))
424         ai.ai_family = PF_INET6;
425 
426     if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
427         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
428                    gai_strerror(rc));
429 	return -1;
430     }
431 
432     /* lookup local addr */
433     memset(&ai,0, sizeof(ai));
434     ai.ai_flags = AI_PASSIVE;
435     ai.ai_family = peer->ai_family;
436     ai.ai_socktype = SOCK_DGRAM;
437 
438     addr = qemu_opt_get(opts, "localaddr");
439     port = qemu_opt_get(opts, "localport");
440     if (addr == NULL || strlen(addr) == 0) {
441         addr = NULL;
442     }
443     if (!port || strlen(port) == 0)
444         port = "0";
445 
446     if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
447         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
448                    gai_strerror(rc));
449         goto err;
450     }
451 
452     /* create socket */
453     sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
454     if (sock < 0) {
455         error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
456         goto err;
457     }
458     socket_set_fast_reuse(sock);
459 
460     /* bind socket */
461     if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
462         error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
463         goto err;
464     }
465 
466     /* connect to peer */
467     if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
468         error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED);
469         goto err;
470     }
471 
472     freeaddrinfo(local);
473     freeaddrinfo(peer);
474     return sock;
475 
476 err:
477     if (-1 != sock)
478         closesocket(sock);
479     if (local)
480         freeaddrinfo(local);
481     if (peer)
482         freeaddrinfo(peer);
483     return -1;
484 }
485 
486 /* compatibility wrapper */
487 InetSocketAddress *inet_parse(const char *str, Error **errp)
488 {
489     InetSocketAddress *addr;
490     const char *optstr, *h;
491     char host[64];
492     char port[33];
493     int to;
494     int pos;
495 
496     addr = g_new0(InetSocketAddress, 1);
497 
498     /* parse address */
499     if (str[0] == ':') {
500         /* no host given */
501         host[0] = '\0';
502         if (1 != sscanf(str, ":%32[^,]%n", port, &pos)) {
503             error_setg(errp, "error parsing port in address '%s'", str);
504             goto fail;
505         }
506     } else if (str[0] == '[') {
507         /* IPv6 addr */
508         if (2 != sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos)) {
509             error_setg(errp, "error parsing IPv6 address '%s'", str);
510             goto fail;
511         }
512         addr->ipv6 = addr->has_ipv6 = true;
513     } else {
514         /* hostname or IPv4 addr */
515         if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) {
516             error_setg(errp, "error parsing address '%s'", str);
517             goto fail;
518         }
519         if (host[strspn(host, "0123456789.")] == '\0') {
520             addr->ipv4 = addr->has_ipv4 = true;
521         }
522     }
523 
524     addr->host = g_strdup(host);
525     addr->port = g_strdup(port);
526 
527     /* parse options */
528     optstr = str + pos;
529     h = strstr(optstr, ",to=");
530     if (h) {
531         h += 4;
532         if (sscanf(h, "%d%n", &to, &pos) != 1 ||
533             (h[pos] != '\0' && h[pos] != ',')) {
534             error_setg(errp, "error parsing to= argument");
535             goto fail;
536         }
537         addr->has_to = true;
538         addr->to = to;
539     }
540     if (strstr(optstr, ",ipv4")) {
541         addr->ipv4 = addr->has_ipv4 = true;
542     }
543     if (strstr(optstr, ",ipv6")) {
544         addr->ipv6 = addr->has_ipv6 = true;
545     }
546     return addr;
547 
548 fail:
549     qapi_free_InetSocketAddress(addr);
550     return NULL;
551 }
552 
553 static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr)
554 {
555     bool ipv4 = addr->ipv4 || !addr->has_ipv4;
556     bool ipv6 = addr->ipv6 || !addr->has_ipv6;
557 
558     if (!ipv4 || !ipv6) {
559         qemu_opt_set_bool(opts, "ipv4", ipv4);
560         qemu_opt_set_bool(opts, "ipv6", ipv6);
561     }
562     if (addr->has_to) {
563         char to[20];
564         snprintf(to, sizeof(to), "%d", addr->to);
565         qemu_opt_set(opts, "to", to);
566     }
567     qemu_opt_set(opts, "host", addr->host);
568     qemu_opt_set(opts, "port", addr->port);
569 }
570 
571 int inet_listen(const char *str, char *ostr, int olen,
572                 int socktype, int port_offset, Error **errp)
573 {
574     QemuOpts *opts;
575     char *optstr;
576     int sock = -1;
577     InetSocketAddress *addr;
578 
579     addr = inet_parse(str, errp);
580     if (addr != NULL) {
581         opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
582         inet_addr_to_opts(opts, addr);
583         qapi_free_InetSocketAddress(addr);
584         sock = inet_listen_opts(opts, port_offset, errp);
585         if (sock != -1 && ostr) {
586             optstr = strchr(str, ',');
587             if (qemu_opt_get_bool(opts, "ipv6", 0)) {
588                 snprintf(ostr, olen, "[%s]:%s%s",
589                          qemu_opt_get(opts, "host"),
590                          qemu_opt_get(opts, "port"),
591                          optstr ? optstr : "");
592             } else {
593                 snprintf(ostr, olen, "%s:%s%s",
594                          qemu_opt_get(opts, "host"),
595                          qemu_opt_get(opts, "port"),
596                          optstr ? optstr : "");
597             }
598         }
599         qemu_opts_del(opts);
600     }
601     return sock;
602 }
603 
604 /**
605  * Create a blocking socket and connect it to an address.
606  *
607  * @str: address string
608  * @errp: set in case of an error
609  *
610  * Returns -1 in case of error, file descriptor on success
611  **/
612 int inet_connect(const char *str, Error **errp)
613 {
614     QemuOpts *opts;
615     int sock = -1;
616     InetSocketAddress *addr;
617 
618     addr = inet_parse(str, errp);
619     if (addr != NULL) {
620         opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
621         inet_addr_to_opts(opts, addr);
622         qapi_free_InetSocketAddress(addr);
623         sock = inet_connect_opts(opts, errp, NULL, NULL);
624         qemu_opts_del(opts);
625     }
626     return sock;
627 }
628 
629 /**
630  * Create a non-blocking socket and connect it to an address.
631  * Calls the callback function with fd in case of success or -1 in case of
632  * error.
633  *
634  * @str: address string
635  * @callback: callback function that is called when connect completes,
636  *            cannot be NULL.
637  * @opaque: opaque for callback function
638  * @errp: set in case of an error
639  *
640  * Returns: -1 on immediate error, file descriptor on success.
641  **/
642 int inet_nonblocking_connect(const char *str,
643                              NonBlockingConnectHandler *callback,
644                              void *opaque, Error **errp)
645 {
646     QemuOpts *opts;
647     int sock = -1;
648     InetSocketAddress *addr;
649 
650     g_assert(callback != NULL);
651 
652     addr = inet_parse(str, errp);
653     if (addr != NULL) {
654         opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
655         inet_addr_to_opts(opts, addr);
656         qapi_free_InetSocketAddress(addr);
657         sock = inet_connect_opts(opts, errp, callback, opaque);
658         qemu_opts_del(opts);
659     }
660     return sock;
661 }
662 
663 #ifndef _WIN32
664 
665 int unix_listen_opts(QemuOpts *opts, Error **errp)
666 {
667     struct sockaddr_un un;
668     const char *path = qemu_opt_get(opts, "path");
669     int sock, fd;
670 
671     sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
672     if (sock < 0) {
673         error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
674         return -1;
675     }
676 
677     memset(&un, 0, sizeof(un));
678     un.sun_family = AF_UNIX;
679     if (path && strlen(path)) {
680         snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
681     } else {
682         char *tmpdir = getenv("TMPDIR");
683         snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
684                  tmpdir ? tmpdir : "/tmp");
685         /*
686          * This dummy fd usage silences the mktemp() unsecure warning.
687          * Using mkstemp() doesn't make things more secure here
688          * though.  bind() complains about existing files, so we have
689          * to unlink first and thus re-open the race window.  The
690          * worst case possible is bind() failing, i.e. a DoS attack.
691          */
692         fd = mkstemp(un.sun_path); close(fd);
693         qemu_opt_set(opts, "path", un.sun_path);
694     }
695 
696     unlink(un.sun_path);
697     if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
698         error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
699         goto err;
700     }
701     if (listen(sock, 1) < 0) {
702         error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED);
703         goto err;
704     }
705 
706     return sock;
707 
708 err:
709     closesocket(sock);
710     return -1;
711 }
712 
713 int unix_connect_opts(QemuOpts *opts, Error **errp,
714                       NonBlockingConnectHandler *callback, void *opaque)
715 {
716     struct sockaddr_un un;
717     const char *path = qemu_opt_get(opts, "path");
718     ConnectState *connect_state = NULL;
719     int sock, rc;
720 
721     if (NULL == path) {
722         error_setg(errp, "unix connect: no path specified");
723         return -1;
724     }
725 
726     sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
727     if (sock < 0) {
728         error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
729         return -1;
730     }
731     if (callback != NULL) {
732         connect_state = g_malloc0(sizeof(*connect_state));
733         connect_state->callback = callback;
734         connect_state->opaque = opaque;
735         qemu_set_nonblock(sock);
736     }
737 
738     memset(&un, 0, sizeof(un));
739     un.sun_family = AF_UNIX;
740     snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
741 
742     /* connect to peer */
743     do {
744         rc = 0;
745         if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
746             rc = -socket_error();
747         }
748     } while (rc == -EINTR);
749 
750     if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
751         connect_state->fd = sock;
752         qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
753                              connect_state);
754         return sock;
755     } else if (rc >= 0) {
756         /* non blocking socket immediate success, call callback */
757         if (callback != NULL) {
758             callback(sock, opaque);
759         }
760     }
761 
762     if (rc < 0) {
763         error_set_errno(errp, -rc, QERR_SOCKET_CONNECT_FAILED);
764         close(sock);
765         sock = -1;
766     }
767 
768     g_free(connect_state);
769     return sock;
770 }
771 
772 #else
773 
774 int unix_listen_opts(QemuOpts *opts, Error **errp)
775 {
776     error_setg(errp, "unix sockets are not available on windows");
777     errno = ENOTSUP;
778     return -1;
779 }
780 
781 int unix_connect_opts(QemuOpts *opts, Error **errp,
782                       NonBlockingConnectHandler *callback, void *opaque)
783 {
784     error_setg(errp, "unix sockets are not available on windows");
785     errno = ENOTSUP;
786     return -1;
787 }
788 #endif
789 
790 /* compatibility wrapper */
791 int unix_listen(const char *str, char *ostr, int olen, Error **errp)
792 {
793     QemuOpts *opts;
794     char *path, *optstr;
795     int sock, len;
796 
797     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
798 
799     optstr = strchr(str, ',');
800     if (optstr) {
801         len = optstr - str;
802         if (len) {
803             path = g_malloc(len+1);
804             snprintf(path, len+1, "%.*s", len, str);
805             qemu_opt_set(opts, "path", path);
806             g_free(path);
807         }
808     } else {
809         qemu_opt_set(opts, "path", str);
810     }
811 
812     sock = unix_listen_opts(opts, errp);
813 
814     if (sock != -1 && ostr)
815         snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
816     qemu_opts_del(opts);
817     return sock;
818 }
819 
820 int unix_connect(const char *path, Error **errp)
821 {
822     QemuOpts *opts;
823     int sock;
824 
825     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
826     qemu_opt_set(opts, "path", path);
827     sock = unix_connect_opts(opts, errp, NULL, NULL);
828     qemu_opts_del(opts);
829     return sock;
830 }
831 
832 
833 int unix_nonblocking_connect(const char *path,
834                              NonBlockingConnectHandler *callback,
835                              void *opaque, Error **errp)
836 {
837     QemuOpts *opts;
838     int sock = -1;
839 
840     g_assert(callback != NULL);
841 
842     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
843     qemu_opt_set(opts, "path", path);
844     sock = unix_connect_opts(opts, errp, callback, opaque);
845     qemu_opts_del(opts);
846     return sock;
847 }
848 
849 SocketAddress *socket_parse(const char *str, Error **errp)
850 {
851     SocketAddress *addr;
852 
853     addr = g_new0(SocketAddress, 1);
854     if (strstart(str, "unix:", NULL)) {
855         if (str[5] == '\0') {
856             error_setg(errp, "invalid Unix socket address");
857             goto fail;
858         } else {
859             addr->kind = SOCKET_ADDRESS_KIND_UNIX;
860             addr->q_unix = g_new(UnixSocketAddress, 1);
861             addr->q_unix->path = g_strdup(str + 5);
862         }
863     } else if (strstart(str, "fd:", NULL)) {
864         if (str[3] == '\0') {
865             error_setg(errp, "invalid file descriptor address");
866             goto fail;
867         } else {
868             addr->kind = SOCKET_ADDRESS_KIND_FD;
869             addr->fd = g_new(String, 1);
870             addr->fd->str = g_strdup(str + 3);
871         }
872     } else {
873         addr->kind = SOCKET_ADDRESS_KIND_INET;
874         addr->inet = inet_parse(str, errp);
875         if (addr->inet == NULL) {
876             goto fail;
877         }
878     }
879     return addr;
880 
881 fail:
882     qapi_free_SocketAddress(addr);
883     return NULL;
884 }
885 
886 int socket_connect(SocketAddress *addr, Error **errp,
887                    NonBlockingConnectHandler *callback, void *opaque)
888 {
889     QemuOpts *opts;
890     int fd;
891 
892     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
893     switch (addr->kind) {
894     case SOCKET_ADDRESS_KIND_INET:
895         inet_addr_to_opts(opts, addr->inet);
896         fd = inet_connect_opts(opts, errp, callback, opaque);
897         break;
898 
899     case SOCKET_ADDRESS_KIND_UNIX:
900         qemu_opt_set(opts, "path", addr->q_unix->path);
901         fd = unix_connect_opts(opts, errp, callback, opaque);
902         break;
903 
904     case SOCKET_ADDRESS_KIND_FD:
905         fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
906         if (fd >= 0 && callback) {
907             qemu_set_nonblock(fd);
908             callback(fd, opaque);
909         }
910         break;
911 
912     default:
913         abort();
914     }
915     qemu_opts_del(opts);
916     return fd;
917 }
918 
919 int socket_listen(SocketAddress *addr, Error **errp)
920 {
921     QemuOpts *opts;
922     int fd;
923 
924     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
925     switch (addr->kind) {
926     case SOCKET_ADDRESS_KIND_INET:
927         inet_addr_to_opts(opts, addr->inet);
928         fd = inet_listen_opts(opts, 0, errp);
929         break;
930 
931     case SOCKET_ADDRESS_KIND_UNIX:
932         qemu_opt_set(opts, "path", addr->q_unix->path);
933         fd = unix_listen_opts(opts, errp);
934         break;
935 
936     case SOCKET_ADDRESS_KIND_FD:
937         fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
938         break;
939 
940     default:
941         abort();
942     }
943     qemu_opts_del(opts);
944     return fd;
945 }
946 
947 int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
948 {
949     QemuOpts *opts;
950     int fd;
951 
952     opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
953     switch (remote->kind) {
954     case SOCKET_ADDRESS_KIND_INET:
955         qemu_opt_set(opts, "host", remote->inet->host);
956         qemu_opt_set(opts, "port", remote->inet->port);
957         if (local) {
958             qemu_opt_set(opts, "localaddr", local->inet->host);
959             qemu_opt_set(opts, "localport", local->inet->port);
960         }
961         fd = inet_dgram_opts(opts, errp);
962         break;
963 
964     default:
965         error_setg(errp, "socket type unsupported for datagram");
966         fd = -1;
967     }
968     qemu_opts_del(opts);
969     return fd;
970 }
971