backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / virnetsockettest.c
blobbb8357f7cd1fb452b574fe3cb274e0591c87fd3c
1 /*
2 * Copyright (C) 2011, 2014 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
19 #include <config.h>
21 #include <signal.h>
22 #ifdef HAVE_IFADDRS_H
23 # include <ifaddrs.h>
24 #endif
25 #include <netdb.h>
27 #include "testutils.h"
28 #include "virutil.h"
29 #include "virerror.h"
30 #include "viralloc.h"
31 #include "virlog.h"
32 #include "virfile.h"
33 #include "virstring.h"
35 #include "rpc/virnetsocket.h"
37 #define VIR_FROM_THIS VIR_FROM_RPC
39 VIR_LOG_INIT("tests.netsockettest");
41 #if HAVE_IFADDRS_H
42 # define BASE_PORT 5672
44 static int
45 checkProtocols(bool *hasIPv4, bool *hasIPv6,
46 int *freePort)
48 struct sockaddr_in in4;
49 struct sockaddr_in6 in6;
50 int s4 = -1, s6 = -1;
51 size_t i;
52 int ret = -1;
54 *freePort = 0;
55 if (virNetSocketCheckProtocols(hasIPv4, hasIPv6) < 0)
56 return -1;
58 for (i = 0; i < 50; i++) {
59 int only = 1;
60 if ((s4 = socket(AF_INET, SOCK_STREAM, 0)) < 0)
61 goto cleanup;
63 if (*hasIPv6) {
64 if ((s6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
65 goto cleanup;
67 if (setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY, &only, sizeof(only)) < 0)
68 goto cleanup;
71 memset(&in4, 0, sizeof(in4));
72 memset(&in6, 0, sizeof(in6));
74 in4.sin_family = AF_INET;
75 in4.sin_port = htons(BASE_PORT + i);
76 in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
77 in6.sin6_family = AF_INET6;
78 in6.sin6_port = htons(BASE_PORT + i);
79 in6.sin6_addr = in6addr_loopback;
81 if (bind(s4, (struct sockaddr *)&in4, sizeof(in4)) < 0) {
82 if (errno == EADDRINUSE) {
83 VIR_FORCE_CLOSE(s4);
84 VIR_FORCE_CLOSE(s6);
85 continue;
87 goto cleanup;
90 if (*hasIPv6) {
91 if (bind(s6, (struct sockaddr *)&in6, sizeof(in6)) < 0) {
92 if (errno == EADDRINUSE) {
93 VIR_FORCE_CLOSE(s4);
94 VIR_FORCE_CLOSE(s6);
95 continue;
97 goto cleanup;
101 *freePort = BASE_PORT + i;
102 break;
105 VIR_DEBUG("Choose port %d", *freePort);
107 ret = 0;
109 cleanup:
110 VIR_FORCE_CLOSE(s4);
111 VIR_FORCE_CLOSE(s6);
112 return ret;
115 struct testClientData {
116 const char *path;
117 const char *cnode;
118 const char *portstr;
121 static void
122 testSocketClient(void *opaque)
124 struct testClientData *data = opaque;
125 char c;
126 virNetSocketPtr csock = NULL;
128 if (data->path) {
129 if (virNetSocketNewConnectUNIX(data->path, false,
130 NULL, &csock) < 0)
131 return;
132 } else {
133 if (virNetSocketNewConnectTCP(data->cnode, data->portstr,
134 AF_UNSPEC,
135 &csock) < 0)
136 return;
139 virNetSocketSetBlocking(csock, true);
141 if (virNetSocketRead(csock, &c, 1) != 1) {
142 VIR_DEBUG("Cannot read from server");
143 goto done;
145 if (virNetSocketWrite(csock, &c, 1) != 1) {
146 VIR_DEBUG("Cannot write to server");
147 goto done;
150 done:
151 virObjectUnref(csock);
155 static void
156 testSocketIncoming(virNetSocketPtr sock,
157 int events ATTRIBUTE_UNUSED,
158 void *opaque)
160 virNetSocketPtr *retsock = opaque;
161 VIR_DEBUG("Incoming sock=%p events=%d", sock, events);
162 *retsock = sock;
166 struct testSocketData {
167 const char *lnode;
168 int port;
169 const char *cnode;
173 static int
174 testSocketAccept(const void *opaque)
176 virNetSocketPtr *lsock = NULL; /* Listen socket */
177 size_t nlsock = 0, i;
178 virNetSocketPtr ssock = NULL; /* Server socket */
179 virNetSocketPtr rsock = NULL; /* Incoming client socket */
180 const struct testSocketData *data = opaque;
181 int ret = -1;
182 char portstr[100];
183 char *tmpdir = NULL;
184 char *path = NULL;
185 char template[] = "/tmp/libvirt_XXXXXX";
186 virThread th;
187 struct testClientData cdata = { 0 };
188 bool goodsock = false;
189 char a = 'a';
190 char b = '\0';
192 if (!data) {
193 virNetSocketPtr usock;
194 tmpdir = mkdtemp(template);
195 if (tmpdir == NULL) {
196 VIR_WARN("Failed to create temporary directory");
197 goto cleanup;
199 if (virAsprintf(&path, "%s/test.sock", tmpdir) < 0)
200 goto cleanup;
202 if (virNetSocketNewListenUNIX(path, 0700, -1, getegid(), &usock) < 0)
203 goto cleanup;
205 if (VIR_ALLOC_N(lsock, 1) < 0) {
206 virObjectUnref(usock);
207 goto cleanup;
210 lsock[0] = usock;
211 nlsock = 1;
213 cdata.path = path;
214 } else {
215 snprintf(portstr, sizeof(portstr), "%d", data->port);
216 if (virNetSocketNewListenTCP(data->lnode, portstr,
217 AF_UNSPEC,
218 &lsock, &nlsock) < 0)
219 goto cleanup;
221 cdata.cnode = data->cnode;
222 cdata.portstr = portstr;
225 for (i = 0; i < nlsock; i++) {
226 if (virNetSocketListen(lsock[i], 0) < 0)
227 goto cleanup;
229 if (virNetSocketAddIOCallback(lsock[i],
230 VIR_EVENT_HANDLE_READABLE,
231 testSocketIncoming,
232 &rsock,
233 NULL) < 0) {
234 goto cleanup;
238 if (virThreadCreate(&th, true,
239 testSocketClient,
240 &cdata) < 0)
241 goto cleanup;
243 while (rsock == NULL) {
244 if (virEventRunDefaultImpl() < 0)
245 break;
248 for (i = 0; i < nlsock; i++) {
249 if (lsock[i] == rsock) {
250 goodsock = true;
251 break;
255 if (!goodsock) {
256 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
257 "Unexpected server socket seen");
258 goto join;
261 if (virNetSocketAccept(rsock, &ssock) < 0)
262 goto join;
264 if (!ssock) {
265 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
266 "Client went away unexpectedly");
267 goto join;
270 virNetSocketSetBlocking(ssock, true);
272 if (virNetSocketWrite(ssock, &a, 1) < 0 ||
273 virNetSocketRead(ssock, &b, 1) < 0) {
274 goto join;
277 if (a != b) {
278 virReportError(VIR_ERR_INTERNAL_ERROR,
279 "Bad data received '%x' != '%x'", a, b);
280 goto join;
283 virObjectUnref(ssock);
284 ssock = NULL;
286 ret = 0;
288 join:
289 virThreadJoin(&th);
291 cleanup:
292 virObjectUnref(ssock);
293 for (i = 0; i < nlsock; i++) {
294 virNetSocketRemoveIOCallback(lsock[i]);
295 virNetSocketClose(lsock[i]);
296 virObjectUnref(lsock[i]);
298 VIR_FREE(lsock);
299 VIR_FREE(path);
300 if (tmpdir)
301 rmdir(tmpdir);
302 return ret;
304 #endif
307 #ifndef WIN32
308 static int testSocketUNIXAddrs(const void *data ATTRIBUTE_UNUSED)
310 virNetSocketPtr lsock = NULL; /* Listen socket */
311 virNetSocketPtr ssock = NULL; /* Server socket */
312 virNetSocketPtr csock = NULL; /* Client socket */
313 int ret = -1;
315 char *path = NULL;
316 char *tmpdir;
317 char template[] = "/tmp/libvirt_XXXXXX";
319 tmpdir = mkdtemp(template);
320 if (tmpdir == NULL) {
321 VIR_WARN("Failed to create temporary directory");
322 goto cleanup;
324 if (virAsprintf(&path, "%s/test.sock", tmpdir) < 0)
325 goto cleanup;
327 if (virNetSocketNewListenUNIX(path, 0700, -1, getegid(), &lsock) < 0)
328 goto cleanup;
330 if (STRNEQ(virNetSocketLocalAddrStringSASL(lsock), "127.0.0.1;0")) {
331 VIR_DEBUG("Unexpected local address");
332 goto cleanup;
335 if (virNetSocketRemoteAddrStringSASL(lsock) != NULL) {
336 VIR_DEBUG("Unexpected remote address");
337 goto cleanup;
340 if (virNetSocketListen(lsock, 0) < 0)
341 goto cleanup;
343 if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0)
344 goto cleanup;
346 if (STRNEQ(virNetSocketLocalAddrStringSASL(csock), "127.0.0.1;0")) {
347 VIR_DEBUG("Unexpected local address");
348 goto cleanup;
351 if (STRNEQ(virNetSocketRemoteAddrStringSASL(csock), "127.0.0.1;0")) {
352 VIR_DEBUG("Unexpected remote address");
353 goto cleanup;
356 if (STRNEQ(virNetSocketRemoteAddrStringURI(csock), "127.0.0.1:0")) {
357 VIR_DEBUG("Unexpected remote address");
358 goto cleanup;
362 if (virNetSocketAccept(lsock, &ssock) < 0) {
363 VIR_DEBUG("Unexpected client socket missing");
364 goto cleanup;
368 if (STRNEQ(virNetSocketLocalAddrStringSASL(ssock), "127.0.0.1;0")) {
369 VIR_DEBUG("Unexpected local address");
370 goto cleanup;
373 if (STRNEQ(virNetSocketRemoteAddrStringSASL(ssock), "127.0.0.1;0")) {
374 VIR_DEBUG("Unexpected remote address");
375 goto cleanup;
378 if (STRNEQ(virNetSocketRemoteAddrStringURI(ssock), "127.0.0.1:0")) {
379 VIR_DEBUG("Unexpected remote address");
380 goto cleanup;
384 ret = 0;
386 cleanup:
387 VIR_FREE(path);
388 virObjectUnref(lsock);
389 virObjectUnref(ssock);
390 virObjectUnref(csock);
391 if (tmpdir)
392 rmdir(tmpdir);
393 return ret;
396 static int testSocketCommandNormal(const void *data ATTRIBUTE_UNUSED)
398 virNetSocketPtr csock = NULL; /* Client socket */
399 char buf[100];
400 size_t i;
401 int ret = -1;
402 virCommandPtr cmd = virCommandNewArgList("/bin/cat", "/dev/zero", NULL);
403 virCommandAddEnvPassCommon(cmd);
405 if (virNetSocketNewConnectCommand(cmd, &csock) < 0)
406 goto cleanup;
408 virNetSocketSetBlocking(csock, true);
410 if (virNetSocketRead(csock, buf, sizeof(buf)) < 0)
411 goto cleanup;
413 for (i = 0; i < sizeof(buf); i++)
414 if (buf[i] != '\0')
415 goto cleanup;
417 ret = 0;
419 cleanup:
420 virObjectUnref(csock);
421 return ret;
424 static int testSocketCommandFail(const void *data ATTRIBUTE_UNUSED)
426 virNetSocketPtr csock = NULL; /* Client socket */
427 char buf[100];
428 int ret = -1;
429 virCommandPtr cmd = virCommandNewArgList("/bin/cat", "/dev/does-not-exist", NULL);
430 virCommandAddEnvPassCommon(cmd);
432 if (virNetSocketNewConnectCommand(cmd, &csock) < 0)
433 goto cleanup;
435 virNetSocketSetBlocking(csock, true);
437 if (virNetSocketRead(csock, buf, sizeof(buf)) == 0)
438 goto cleanup;
440 ret = 0;
442 cleanup:
443 virObjectUnref(csock);
444 return ret;
447 struct testSSHData {
448 const char *nodename;
449 const char *service;
450 const char *binary;
451 const char *username;
452 bool noTTY;
453 bool noVerify;
454 const char *netcat;
455 const char *keyfile;
456 const char *path;
458 const char *expectOut;
459 bool failConnect;
460 bool dieEarly;
463 static int testSocketSSH(const void *opaque)
465 const struct testSSHData *data = opaque;
466 virNetSocketPtr csock = NULL; /* Client socket */
467 int ret = -1;
468 char buf[1024];
470 if (virNetSocketNewConnectSSH(data->nodename,
471 data->service,
472 data->binary,
473 data->username,
474 data->noTTY,
475 data->noVerify,
476 data->netcat,
477 data->keyfile,
478 data->path,
479 &csock) < 0)
480 goto cleanup;
482 virNetSocketSetBlocking(csock, true);
484 if (data->failConnect) {
485 if (virNetSocketRead(csock, buf, sizeof(buf)-1) >= 0) {
486 VIR_DEBUG("Expected connect failure, but got some socket data");
487 goto cleanup;
489 } else {
490 ssize_t rv;
491 if ((rv = virNetSocketRead(csock, buf, sizeof(buf)-1)) < 0) {
492 VIR_DEBUG("Didn't get any socket data");
493 goto cleanup;
495 buf[rv] = '\0';
497 if (STRNEQ(buf, data->expectOut)) {
498 virTestDifference(stderr, data->expectOut, buf);
499 goto cleanup;
502 if (data->dieEarly &&
503 virNetSocketRead(csock, buf, sizeof(buf)-1) >= 0) {
504 VIR_DEBUG("Got too much socket data");
505 goto cleanup;
509 ret = 0;
511 cleanup:
512 virObjectUnref(csock);
513 return ret;
516 #endif
519 static int
520 mymain(void)
522 int ret = 0;
523 #ifdef HAVE_IFADDRS_H
524 bool hasIPv4, hasIPv6;
525 int freePort;
526 #endif
528 signal(SIGPIPE, SIG_IGN);
530 virEventRegisterDefaultImpl();
532 #ifdef HAVE_IFADDRS_H
533 if (checkProtocols(&hasIPv4, &hasIPv6, &freePort) < 0) {
534 fprintf(stderr, "Cannot identify IPv4/6 availability\n");
535 return EXIT_FAILURE;
538 if (hasIPv4) {
539 struct testSocketData tcpData = { "127.0.0.1", freePort, "127.0.0.1" };
540 if (virTestRun("Socket TCP/IPv4 Accept", testSocketAccept, &tcpData) < 0)
541 ret = -1;
543 if (hasIPv6) {
544 struct testSocketData tcpData = { "::1", freePort, "::1" };
545 if (virTestRun("Socket TCP/IPv6 Accept", testSocketAccept, &tcpData) < 0)
546 ret = -1;
548 if (hasIPv6 && hasIPv4) {
549 struct testSocketData tcpData = { NULL, freePort, "127.0.0.1" };
550 if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketAccept, &tcpData) < 0)
551 ret = -1;
553 tcpData.cnode = "::1";
554 if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketAccept, &tcpData) < 0)
555 ret = -1;
557 #endif
559 #ifndef WIN32
560 if (virTestRun("Socket UNIX Accept", testSocketAccept, NULL) < 0)
561 ret = -1;
563 if (virTestRun("Socket UNIX Addrs", testSocketUNIXAddrs, NULL) < 0)
564 ret = -1;
566 if (virTestRun("Socket External Command /dev/zero", testSocketCommandNormal, NULL) < 0)
567 ret = -1;
568 if (virTestRun("Socket External Command /dev/does-not-exist", testSocketCommandFail, NULL) < 0)
569 ret = -1;
571 struct testSSHData sshData1 = {
572 .nodename = "somehost",
573 .path = "/tmp/socket",
574 .expectOut = "-T -e none -- somehost sh -c '"
575 "if 'nc' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
576 "ARG=-q0;"
577 "else "
578 "ARG=;"
579 "fi;"
580 "'nc' $ARG -U /tmp/socket'\n",
582 if (virTestRun("SSH test 1", testSocketSSH, &sshData1) < 0)
583 ret = -1;
585 struct testSSHData sshData2 = {
586 .nodename = "somehost",
587 .service = "9000",
588 .username = "fred",
589 .netcat = "netcat",
590 .noTTY = true,
591 .noVerify = false,
592 .path = "/tmp/socket",
593 .expectOut = "-p 9000 -l fred -T -e none -o BatchMode=yes -- somehost sh -c '"
594 "if 'netcat' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
595 "ARG=-q0;"
596 "else "
597 "ARG=;"
598 "fi;"
599 "'netcat' $ARG -U /tmp/socket'\n",
601 if (virTestRun("SSH test 2", testSocketSSH, &sshData2) < 0)
602 ret = -1;
604 struct testSSHData sshData3 = {
605 .nodename = "somehost",
606 .service = "9000",
607 .username = "fred",
608 .netcat = "netcat",
609 .noTTY = false,
610 .noVerify = true,
611 .path = "/tmp/socket",
612 .expectOut = "-p 9000 -l fred -T -e none -o StrictHostKeyChecking=no -- somehost sh -c '"
613 "if 'netcat' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
614 "ARG=-q0;"
615 "else "
616 "ARG=;"
617 "fi;"
618 "'netcat' $ARG -U /tmp/socket'\n",
620 if (virTestRun("SSH test 3", testSocketSSH, &sshData3) < 0)
621 ret = -1;
623 struct testSSHData sshData4 = {
624 .nodename = "nosuchhost",
625 .path = "/tmp/socket",
626 .failConnect = true,
628 if (virTestRun("SSH test 4", testSocketSSH, &sshData4) < 0)
629 ret = -1;
631 struct testSSHData sshData5 = {
632 .nodename = "crashyhost",
633 .path = "/tmp/socket",
634 .expectOut = "-T -e none -- crashyhost sh -c "
635 "'if 'nc' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
636 "ARG=-q0;"
637 "else "
638 "ARG=;"
639 "fi;"
640 "'nc' $ARG -U /tmp/socket'\n",
641 .dieEarly = true,
643 if (virTestRun("SSH test 5", testSocketSSH, &sshData5) < 0)
644 ret = -1;
646 struct testSSHData sshData6 = {
647 .nodename = "example.com",
648 .path = "/tmp/socket",
649 .keyfile = "/root/.ssh/example_key",
650 .noVerify = true,
651 .expectOut = "-i /root/.ssh/example_key -T -e none -o StrictHostKeyChecking=no -- example.com sh -c '"
652 "if 'nc' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
653 "ARG=-q0;"
654 "else "
655 "ARG=;"
656 "fi;"
657 "'nc' $ARG -U /tmp/socket'\n",
659 if (virTestRun("SSH test 6", testSocketSSH, &sshData6) < 0)
660 ret = -1;
662 struct testSSHData sshData7 = {
663 .nodename = "somehost",
664 .netcat = "nc -4",
665 .path = "/tmp/socket",
666 .expectOut = "-T -e none -- somehost sh -c '"
667 "if ''nc -4'' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
668 "ARG=-q0;"
669 "else "
670 "ARG=;"
671 "fi;"
672 "''nc -4'' $ARG -U /tmp/socket'\n",
674 if (virTestRun("SSH test 7", testSocketSSH, &sshData7) < 0)
675 ret = -1;
677 #endif
679 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
682 VIR_TEST_MAIN(mymain)