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