2 * Test client to test the NBD server. Doesn't do anything useful, except
3 * checking that the server does, actually, work.
5 * Note that the only 'real' test is to check the client against a kernel. If
6 * it works here but does not work in the kernel, then that's most likely a bug
7 * in this program and/or in nbd-server.
9 * Copyright(c) 2006 Wouter Verhelst
11 * This program is Free Software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation, in version 2.
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along with
21 * this program; if not, write to the Free Software Foundation, Inc., 51
22 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <sys/types.h>
32 #include <sys/socket.h>
40 #include <netinet/in.h>
43 #define MY_NAME "nbd-tester-client"
47 #include "crypto-gnutls.h"
50 static gchar errstr[1024];
51 const static int errstr_len = 1023;
55 static int looseordering = 0;
57 static gchar *transactionlog = "nbd-tester-client.tr";
58 static gchar *certfile = NULL;
59 static gchar *keyfile = NULL;
60 static gchar *cacertfile = NULL;
61 static gchar *tlshostname = NULL;
64 CONNECTION_TYPE_INIT_PASSWD,
65 CONNECTION_TYPE_CLISERV,
70 CONNECTION_CLOSE_PROPERLY,
71 CONNECTION_CLOSE_FAST,
77 struct nbd_request req;
78 struct reqcontext *next;
79 struct reqcontext *prev;
83 struct reqcontext *head;
84 struct reqcontext *tail;
110 void rclist_unlink(struct rclist *l, struct reqcontext *p)
113 struct reqcontext *prev = p->prev;
114 struct reqcontext *next = p->next;
116 /* Fix link to previous */
133 /* Add a new list item to the tail */
134 void rclist_addtail(struct rclist *l, struct reqcontext *p)
140 g_warning("addtail found list tail has a next pointer");
147 g_warning("addtail found no list tail but a list head");
156 void chunklist_unlink(struct chunklist *l, struct chunk *p)
159 struct chunk *prev = p->prev;
160 struct chunk *next = p->next;
162 /* Fix link to previous */
179 /* Add a new list item to the tail */
180 void chunklist_addtail(struct chunklist *l, struct chunk *p)
186 g_warning("addtail found list tail has a next pointer");
193 g_warning("addtail found no list tail but a list head");
202 /* Add some new bytes to a chunklist */
203 void addbuffer(struct chunklist *l, void *data, uint64_t len)
206 uint64_t size = 64 * 1024;
207 struct chunk *pchunk;
210 /* First see if there is a current chunk, and if it has space */
211 if (l->tail && l->tail->space) {
212 uint64_t towrite = len;
213 if (towrite > l->tail->space)
214 towrite = l->tail->space;
215 memcpy(l->tail->writeptr, data, towrite);
216 l->tail->length += towrite;
217 l->tail->space -= towrite;
218 l->tail->writeptr += towrite;
224 /* We still need to write more, so prepare a new chunk */
225 if ((NULL == (buf = malloc(size)))
227 (pchunk = calloc(1, sizeof(struct chunk))))) {
228 g_critical("Out of memory");
232 pchunk->buffer = buf;
233 pchunk->readptr = buf;
234 pchunk->writeptr = buf;
235 pchunk->space = size;
236 chunklist_addtail(l, pchunk);
242 /* returns 0 on success, -1 on failure */
243 int writebuffer(int fd, struct chunklist *l)
246 struct chunk *pchunk = NULL;
255 if (!(pchunk->length) || !(pchunk->readptr)) {
256 chunklist_unlink(l, pchunk);
257 free(pchunk->buffer);
263 /* OK we have a chunk with some data in */
264 res = write(fd, pchunk->readptr, pchunk->length);
269 pchunk->length -= res;
270 pchunk->readptr += res;
271 if (!pchunk->length) {
272 chunklist_unlink(l, pchunk);
273 free(pchunk->buffer);
279 #define TEST_WRITE (1<<0)
280 #define TEST_FLUSH (1<<1)
281 #define TEST_EXPECT_ERROR (1<<2)
282 #define TEST_HANDSHAKE (1<<3)
284 int timeval_subtract(struct timeval *result, struct timeval *x,
287 if (x->tv_usec < y->tv_usec) {
288 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
289 y->tv_usec -= 1000000 * nsec;
293 if (x->tv_usec - y->tv_usec > 1000000) {
294 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
295 y->tv_usec += 1000000 * nsec;
299 result->tv_sec = x->tv_sec - y->tv_sec;
300 result->tv_usec = x->tv_usec - y->tv_usec;
302 return x->tv_sec < y->tv_sec;
305 double timeval_diff_to_double(struct timeval *x, struct timeval *y)
308 timeval_subtract(&r, x, y);
309 return r.tv_sec * 1.0 + r.tv_usec / 1000000.0;
312 static inline int read_all(int f, void *buf, size_t len)
318 if ((res = read(f, buf, len)) <= 0) {
321 snprintf(errstr, errstr_len, "Read failed: %s",
332 static inline int write_all(int f, void *buf, size_t len)
338 if ((res = write(f, buf, len)) <= 0) {
341 snprintf(errstr, errstr_len, "Write failed: %s",
352 static int tlserrout (void *opaque, const char *format, va_list ap) {
353 return vfprintf(stderr, format, ap);
356 #define READ_ALL_ERRCHK(f, buf, len, whereto, errmsg...) if((read_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); goto whereto; }
357 #define READ_ALL_ERR_RT(f, buf, len, whereto, rval, errmsg...) if((read_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); retval = rval; goto whereto; }
359 #define WRITE_ALL_ERRCHK(f, buf, len, whereto, errmsg...) if((write_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); goto whereto; }
360 #define WRITE_ALL_ERR_RT(f, buf, len, whereto, rval, errmsg...) if((write_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); retval = rval; goto whereto; }
362 int setup_connection_common(int sock, char *name, CONNECTION_TYPE ctype,
363 int *serverflags, int testflags)
367 uint64_t mymagic = (name ? opts_magic : cliserv_magic);
369 uint16_t handshakeflags = 0;
370 uint32_t negotiationflags = 0;
372 if (ctype < CONNECTION_TYPE_INIT_PASSWD)
374 READ_ALL_ERRCHK(sock, buf, strlen(INIT_PASSWD), err,
375 "Could not read INIT_PASSWD: %s", strerror(errno));
376 if (strlen(buf) == 0) {
377 snprintf(errstr, errstr_len, "Server closed connection");
380 if (strncmp(buf, INIT_PASSWD, strlen(INIT_PASSWD))) {
381 snprintf(errstr, errstr_len, "INIT_PASSWD does not match");
384 if (ctype < CONNECTION_TYPE_CLISERV)
386 READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
387 "Could not read cliserv_magic: %s", strerror(errno));
388 tmp64 = ntohll(tmp64);
389 if (tmp64 != mymagic) {
390 strncpy(errstr, "mymagic does not match", errstr_len);
393 if (ctype < CONNECTION_TYPE_FULL)
396 READ_ALL_ERRCHK(sock, &size, sizeof(size), err,
397 "Could not read size: %s", strerror(errno));
400 READ_ALL_ERRCHK(sock, &flags, sizeof(uint32_t), err,
401 "Could not read flags: %s", strerror(errno));
402 flags = ntohl(flags);
403 *serverflags = flags;
404 READ_ALL_ERRCHK(sock, buf, 124, err, "Could not read data: %s",
408 /* handshake flags */
409 READ_ALL_ERRCHK(sock, &handshakeflags, sizeof(handshakeflags), err,
410 "Could not read reserved field: %s", strerror(errno));
411 handshakeflags = ntohs(handshakeflags);
412 /* negotiation flags */
413 if (handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)
414 negotiationflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
416 snprintf(errstr, errstr_len, "Cannot negotiate TLS without NBD_FLAG_FIXED_NEWSTYLE");
419 negotiationflags = htonl(negotiationflags);
420 WRITE_ALL_ERRCHK(sock, &negotiationflags, sizeof(negotiationflags), err,
421 "Could not write reserved field: %s", strerror(errno));
422 if (testflags & TEST_HANDSHAKE) {
423 /* Server must support newstyle for this test */
424 if (!(handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)) {
425 strncpy(errstr, "server does not support handshake", errstr_len);
433 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
434 tlssession_t *s = NULL;
438 tmp64 = htonll(opts_magic);
439 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
440 "Could not write magic: %s", strerror(errno));
442 tmp32 = htonl(NBD_OPT_STARTTLS);
443 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
444 "Could not write option: %s", strerror(errno));
447 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
448 "Could not write option length: %s", strerror(errno));
450 READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
451 "Could not read cliserv_magic: %s", strerror(errno));
452 tmp64 = ntohll(tmp64);
453 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
454 strncpy(errstr, "reply magic does not match", errstr_len);
457 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
458 "Could not read option type: %s", strerror(errno));
459 tmp32 = ntohl(tmp32);
460 if (tmp32 != NBD_OPT_STARTTLS) {
461 strncpy(errstr, "Reply to wrong option", errstr_len);
464 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
465 "Could not read option reply type: %s", strerror(errno));
466 tmp32 = ntohl(tmp32);
467 if (tmp32 != NBD_REP_ACK) {
468 if(tmp32 & NBD_REP_FLAG_ERROR) {
469 snprintf(errstr, errstr_len, "Received error %d", tmp32 & ~NBD_REP_FLAG_ERROR);
471 snprintf(errstr, errstr_len, "Option reply type %d != NBD_REP_ACK", tmp32);
475 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
476 "Could not read option data length: %s", strerror(errno));
477 tmp32 = ntohl(tmp32);
479 strncpy(errstr, "Option reply data length != 0", errstr_len);
483 s = tlssession_new(FALSE,
488 !cacertfile || !tlshostname, // insecure flag
495 tlserrout, // erroutfn
499 strncpy(errstr, "Cannot establish TLS session", errstr_len);
503 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0) {
504 strncpy(errstr, "Cannot get socket pair", errstr_len);
508 if (set_nonblocking(plainfd[0], 0) <0 ||
509 set_nonblocking(plainfd[1], 0) <0 ||
510 set_nonblocking(sock, 0) <0) {
513 strncpy(errstr, "Cannot set socket options", errstr_len);
519 err("Could not fork");
522 signal (SIGPIPE, SIG_IGN);
524 tlssession_mainloop(sock, plainfd[0], s);
531 sock = plainfd[1]; /* use the decrypted FD from now on */
535 strncpy(errstr, "TLS requested but support not compiled in", errstr_len);
539 if(testflags & TEST_EXPECT_ERROR) {
540 struct sigaction act;
541 memset(&act, '0', sizeof act);
542 act.sa_handler = SIG_IGN;
543 sigaction(SIGPIPE, &act, NULL);
546 tmp64 = htonll(opts_magic);
547 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
548 "Could not write magic: %s", strerror(errno));
550 tmp32 = htonl(NBD_OPT_EXPORT_NAME);
551 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
552 "Could not write option: %s", strerror(errno));
553 tmp32 = htonl((uint32_t) strlen(name));
554 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
555 "Could not write name length: %s", strerror(errno));
556 WRITE_ALL_ERRCHK(sock, name, strlen(name), err,
557 "Could not write name:: %s", strerror(errno));
558 READ_ALL_ERRCHK(sock, &size, sizeof(size), err,
559 "Could not read size: %s", strerror(errno));
562 READ_ALL_ERRCHK(sock, &flags, sizeof(uint16_t), err,
563 "Could not read flags: %s", strerror(errno));
564 flags = ntohs(flags);
565 *serverflags = flags;
566 READ_ALL_ERRCHK(sock, buf, 124, err,
567 "Could not read reserved zeroes: %s", strerror(errno));
576 int setup_unix_connection(gchar * unixsock)
578 struct sockaddr_un addr;
582 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
583 strncpy(errstr, strerror(errno), errstr_len);
588 memset(&addr, 0, sizeof(struct sockaddr_un));
589 addr.sun_family = AF_UNIX;
590 strncpy(addr.sun_path, unixsock, sizeof addr.sun_path);
591 addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
592 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
593 strncpy(errstr, strerror(errno), errstr_len);
605 int setup_inet_connection(gchar * hostname, int port)
608 struct hostent *host;
609 struct sockaddr_in addr;
612 if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
613 strncpy(errstr, strerror(errno), errstr_len);
617 if (!(host = gethostbyname(hostname))) {
618 strncpy(errstr, hstrerror(h_errno), errstr_len);
621 addr.sin_family = AF_INET;
622 addr.sin_port = htons(port);
623 addr.sin_addr.s_addr = *((int *)host->h_addr);
624 if ((connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)) {
625 strncpy(errstr, strerror(errno), errstr_len);
637 int setup_inetd_connection(gchar **argv)
642 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
643 strncpy(errstr, strerror(errno), errstr_len);
652 execvp(argv[0], argv);
655 } else if (child == -1) {
658 strncpy(errstr, strerror(errno), errstr_len);
663 if (waitpid(child, &status, WNOHANG)) {
672 int close_connection(int sock, CLOSE_TYPE type)
674 struct nbd_request req;
678 case CONNECTION_CLOSE_PROPERLY:
679 req.magic = htonl(NBD_REQUEST_MAGIC);
680 req.type = htonl(NBD_CMD_DISC);
681 memcpy(&(req.handle), &(counter), sizeof(counter));
685 if (write(sock, &req, sizeof(req)) < 0) {
686 snprintf(errstr, errstr_len,
687 "Could not write to socket: %s",
691 case CONNECTION_CLOSE_FAST:
692 if (close(sock) < 0) {
693 snprintf(errstr, errstr_len,
694 "Could not close socket: %s", strerror(errno));
699 g_critical("Your compiler is on crack!"); /* or I am buggy */
705 int read_packet_check_header(int sock, size_t datasize, long long int curhandle)
707 struct nbd_reply rep;
711 READ_ALL_ERR_RT(sock, &rep, sizeof(rep), end, -1,
712 "Could not read reply header: %s", strerror(errno));
713 rep.magic = ntohl(rep.magic);
714 rep.error = ntohl(rep.error);
715 if (rep.magic != NBD_REPLY_MAGIC) {
716 snprintf(errstr, errstr_len,
717 "Received package with incorrect reply_magic. Index of sent packages is %lld (0x%llX), received handle is %lld (0x%llX). Received magic 0x%lX, expected 0x%lX",
718 (long long int)curhandle,
719 (long long unsigned int)curhandle,
720 (long long int)*((u64 *) rep.handle),
721 (long long unsigned int)*((u64 *) rep.handle),
722 (long unsigned int)rep.magic,
723 (long unsigned int)NBD_REPLY_MAGIC);
728 snprintf(errstr, errstr_len,
729 "Received error from server: %ld (0x%lX). Handle is %lld (0x%llX).",
730 (long int)rep.error, (long unsigned int)rep.error,
731 (long long int)(*((u64 *) rep.handle)),
732 (long long unsigned int)*((u64 *) rep.handle));
737 READ_ALL_ERR_RT(sock, &buf, datasize, end, -1,
738 "Could not read data: %s", strerror(errno));
744 int oversize_test(char *name, int sock, char close_sock, int testflags)
747 struct nbd_request req;
748 struct nbd_reply rep;
751 pid_t G_GNUC_UNUSED mypid = getpid();
752 char buf[((1024 * 1024) + sizeof(struct nbd_request) / 2) << 1];
755 /* This should work */
757 setup_connection_common(sock, name,
758 CONNECTION_TYPE_FULL,
759 &serverflags, testflags)) < 0) {
760 g_warning("Could not open socket: %s", errstr);
764 req.magic = htonl(NBD_REQUEST_MAGIC);
765 req.type = htonl(NBD_CMD_READ);
766 req.len = htonl(1024 * 1024);
767 memcpy(&(req.handle), &i, sizeof(i));
768 req.from = htonll(i);
769 WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1,
770 "Could not write request: %s", strerror(errno));
771 printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len));
772 READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1,
773 "Could not read reply header: %s", strerror(errno));
774 READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1,
775 "Could not read data: %s", strerror(errno));
777 snprintf(errstr, errstr_len, "Received unexpected error: %d",
784 /* This probably should not work */
786 req.from = htonll(i);
787 req.len = htonl(ntohl(req.len) + sizeof(struct nbd_request) / 2);
788 WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1,
789 "Could not write request: %s", strerror(errno));
790 printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len));
791 READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1,
792 "Could not read reply header: %s", strerror(errno));
793 READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1,
794 "Could not read data: %s", strerror(errno));
796 printf("Received expected error\n");
802 /* ... unless this works, too */
804 req.from = htonll(i);
805 req.len = htonl(ntohl(req.len) << 1);
806 WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1,
807 "Could not write request: %s", strerror(errno));
808 printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len));
809 READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1,
810 "Could not read reply header: %s", strerror(errno));
811 READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1,
812 "Could not read data: %s", strerror(errno));
818 if ((rep.error && !got_err) || (!rep.error && got_err)) {
819 printf("Received unexpected error\n");
826 int handshake_test(char *name, int sock, char close_sock, int testflags)
833 /* This should work */
835 setup_connection_common(sock, name,
836 CONNECTION_TYPE_FULL,
837 &serverflags, testflags)) < 0) {
838 g_warning("Could not open socket: %s", errstr);
842 /* Intentionally throw an unknown option at the server */
843 tmp64 = htonll(opts_magic);
844 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
845 "Could not write magic: %s", strerror(errno));
846 tmp32 = htonl(0x7654321);
847 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
848 "Could not write option: %s", strerror(errno));
849 tmp32 = htonl((uint32_t) sizeof(tmp32));
850 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
851 "Could not write option length: %s", strerror(errno));
852 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
853 "Could not write option payload: %s", strerror(errno));
854 /* Expect proper error from server */
855 READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
856 "Could not read magic: %s", strerror(errno));
857 tmp64 = ntohll(tmp64);
858 if (tmp64 != 0x3e889045565a9LL) {
859 strncpy(errstr, "magic does not match", errstr_len);
862 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
863 "Could not read option: %s", strerror(errno));
864 tmp32 = ntohl(tmp32);
865 if (tmp32 != 0x7654321) {
866 strncpy(errstr, "option does not match", errstr_len);
869 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
870 "Could not read status: %s", strerror(errno));
871 tmp32 = ntohl(tmp32);
872 if (tmp32 != NBD_REP_ERR_UNSUP) {
873 strncpy(errstr, "status does not match", errstr_len);
876 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
877 "Could not read length: %s", strerror(errno));
878 tmp32 = ntohl(tmp32);
881 size_t len = tmp32 < sizeof(buf) ? tmp32 : sizeof(buf);
882 READ_ALL_ERRCHK(sock, buf, len, err,
883 "Could not read payload: %s", strerror(errno));
888 /* Send NBD_OPT_ABORT to close the connection */
889 tmp64 = htonll(opts_magic);
890 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
891 "Could not write magic: %s", strerror(errno));
892 tmp32 = htonl(NBD_OPT_ABORT);
893 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
894 "Could not write option: %s", strerror(errno));
895 tmp32 = htonl((uint32_t) 0);
896 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
897 "Could not write option length: %s", strerror(errno));
901 g_message("Handshake test completed. No errors encountered.");
906 int throughput_test(char *name, int sock, char close_sock, int testflags)
910 struct nbd_request req;
914 struct timeval start;
918 char speedchar[2] = { '\0', '\0' };
921 signed int do_write = TRUE;
922 pid_t mypid = getpid();
923 char *print = getenv("NBD_TEST_SILENT");
925 if (!(testflags & TEST_WRITE))
926 testflags &= ~TEST_FLUSH;
928 memset(writebuf, 'X', 1024);
931 setup_connection_common(sock, name,
932 CONNECTION_TYPE_FULL,
933 &serverflags, testflags)) < 0) {
934 g_warning("Could not open socket: %s", errstr);
935 if(testflags & TEST_EXPECT_ERROR) {
936 g_message("Test failed, as expected");
943 if ((testflags & TEST_FLUSH)
944 && ((serverflags & (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))
945 != (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))) {
946 snprintf(errstr, errstr_len,
947 "Server did not supply flush capability flags");
951 req.magic = htonl(NBD_REQUEST_MAGIC);
952 req.len = htonl(1024);
953 if (gettimeofday(&start, NULL) < 0) {
955 snprintf(errstr, errstr_len, "Could not measure start time: %s",
959 for (i = 0; i + 1024 <= size; i += 1024) {
961 int sendfua = (testflags & TEST_FLUSH)
962 && (((i >> 10) & 15) == 3);
963 int sendflush = (testflags & TEST_FLUSH)
964 && (((i >> 10) & 15) == 11);
966 htonl((testflags & TEST_WRITE) ? NBD_CMD_WRITE :
970 htonl(NBD_CMD_WRITE | NBD_CMD_FLAG_FUA);
971 memcpy(&(req.handle), &i, sizeof(i));
972 req.from = htonll(i);
973 if (write_all(sock, &req, sizeof(req)) < 0) {
977 if (testflags & TEST_WRITE) {
978 if (write_all(sock, writebuf, 1024) < 0) {
985 long long int j = i ^ (1LL << 63);
986 req.type = htonl(NBD_CMD_FLUSH);
987 memcpy(&(req.handle), &j, sizeof(j));
990 if (write_all(sock, &req, sizeof(req)) < 0) {
994 req.len = htonl(1024);
1003 select(sock + 1, &set, NULL, NULL, &tv);
1004 if (FD_ISSET(sock, &set)) {
1005 /* Okay, there's something ready for
1009 read_packet_check_header(sock,
1013 if (!(testflags & TEST_EXPECT_ERROR)
1021 if (testflags & TEST_EXPECT_ERROR) {
1028 } while (FD_ISSET(sock, &set));
1029 /* Now wait until we can write again or until a second have
1030 * passed, whichever comes first*/
1035 do_write = select(sock + 1, NULL, &set, NULL, &tv);
1037 printf("Select finished\n");
1039 snprintf(errstr, errstr_len, "select: %s",
1045 printf("%d: Requests: %d \r", (int)mypid, requests);
1048 /* Now empty the read buffer */
1054 select(sock + 1, &set, NULL, NULL, &tv);
1055 if (FD_ISSET(sock, &set)) {
1056 /* Okay, there's something ready for
1058 read_packet_check_header(sock,
1059 (testflags & TEST_WRITE) ? 0 :
1064 printf("%d: Requests: %d \r", (int)mypid, requests);
1067 printf("%d: Requests: %d \n", (int)mypid, requests);
1068 if (gettimeofday(&stop, NULL) < 0) {
1070 snprintf(errstr, errstr_len, "Could not measure end time: %s",
1074 timespan = timeval_diff_to_double(&stop, &start);
1075 speed = size / timespan;
1077 speed = speed / 1024.0;
1081 speed = speed / 1024.0;
1085 speed = speed / 1024.0;
1089 ("%d: Throughput %s test (%s flushes) complete. Took %.3f seconds to complete, %.3f%sib/s",
1090 (int)getpid(), (testflags & TEST_WRITE) ? "write" : "read",
1091 (testflags & TEST_FLUSH) ? "with" : "without", timespan, speed,
1096 close_connection(sock, CONNECTION_CLOSE_PROPERLY);
1103 * fill 512 byte buffer 'buf' with a hashed selection of interesting data based
1104 * only on handle and blknum. The first word is blknum, and the second handle, for ease
1105 * of understanding. Things with handle 0 are blank.
1107 static inline void makebuf(char *buf, uint64_t seq, uint64_t blknum)
1109 uint64_t x = ((uint64_t) blknum) ^ (seq << 32) ^ (seq >> 32);
1110 uint64_t *p = (uint64_t *) buf;
1116 for (i = 0; i < 512 / sizeof(uint64_t); i++) {
1119 x += 0xFEEDA1ECDEADBEEFULL + i + (((uint64_t) i) << 56);
1121 x = x ^ (x << s) ^ (x >> (64 - s)) ^ 0xAA55AA55AA55AA55ULL ^
1126 static inline int checkbuf(char *buf, uint64_t seq, uint64_t blknum)
1128 uint64_t cmp[64]; // 512/8 = 64
1129 makebuf((char *)cmp, seq, blknum);
1130 return memcmp(cmp, buf, 512) ? -1 : 0;
1133 static inline void dumpcommand(char *text, uint32_t command)
1135 #ifdef DEBUG_COMMANDS
1136 command = ntohl(command);
1138 switch (command & NBD_CMD_MASK_COMMAND) {
1140 ctext = "NBD_CMD_READ";
1143 ctext = "NBD_CMD_WRITE";
1146 ctext = "NBD_CMD_DISC";
1149 ctext = "NBD_CMD_FLUSH";
1155 printf("%s: %s [%s] (0x%08x)\n",
1157 ctext, (command & NBD_CMD_FLAG_FUA) ? "FUA" : "NONE", command);
1161 /* return an unused handle */
1162 uint64_t getrandomhandle(GHashTable * phash)
1164 uint64_t handle = 0;
1167 /* RAND_MAX may be as low as 2^15 */
1168 for (i = 1; i <= 5; i++)
1169 handle ^= random() ^ (handle << 15);
1170 } while (g_hash_table_lookup(phash, &handle));
1174 int integrity_test(char *name, int sock, char close_sock, int testflags)
1176 struct nbd_reply rep;
1180 struct timeval start;
1181 struct timeval stop;
1184 char speedchar[2] = { '\0', '\0' };
1186 int serverflags = 0;
1187 pid_t G_GNUC_UNUSED mypid = getpid();
1189 char *blkhashname = NULL;
1190 struct blkitem *blkhash = NULL;
1193 uint64_t processed = 0;
1194 uint64_t printer = 0;
1195 char *do_print = getenv("NBD_TEST_SILENT");
1197 int readtransactionfile = 1;
1199 struct rclist txqueue = { NULL, NULL, 0 };
1200 struct rclist inflight = { NULL, NULL, 0 };
1201 struct chunklist txbuf = { NULL, NULL, 0 };
1203 GHashTable *handlehash = g_hash_table_new(g_int64_hash, g_int64_equal);
1207 setup_connection_common(sock, name,
1208 CONNECTION_TYPE_FULL,
1209 &serverflags, testflags)) < 0) {
1210 g_warning("Could not open socket: %s", errstr);
1214 if ((serverflags & (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))
1215 != (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))
1217 ("Server flags do not support FLUSH and FUA - these may error");
1220 blkhashname = strdup("/tmp/blkarray-XXXXXX");
1221 if (!blkhashname || (-1 == (blkhashfd = mkstemp(blkhashname)))) {
1222 g_warning("Could not open temp file: %s", strerror(errno));
1226 /* use tmpnam here to avoid further feature test nightmare */
1227 if (-1 == (blkhashfd = open(blkhashname = strdup(tmpnam(NULL)),
1229 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
1230 g_warning("Could not open temp file: %s", strerror(errno));
1234 /* Ensure space freed if we die */
1235 if (-1 == unlink(blkhashname)) {
1236 g_warning("Could not unlink temp file: %s", strerror(errno));
1241 lseek(blkhashfd, (off_t) ((size >> 9) * sizeof(struct blkitem)),
1243 g_warning("Could not llseek temp file: %s", strerror(errno));
1247 if (-1 == write(blkhashfd, "\0", 1)) {
1248 g_warning("Could not write temp file: %s", strerror(errno));
1252 if (NULL == (blkhash = mmap(NULL,
1253 (size >> 9) * sizeof(struct blkitem),
1254 PROT_READ | PROT_WRITE,
1255 MAP_SHARED, blkhashfd, 0))) {
1256 g_warning("Could not mmap temp file: %s", strerror(errno));
1260 if (-1 == (logfd = open(transactionlog, O_RDONLY))) {
1261 g_warning("Could open log file: %s", strerror(errno));
1265 if (gettimeofday(&start, NULL) < 0) {
1266 snprintf(errstr, errstr_len, "Could not measure start time: %s",
1271 while (readtransactionfile || txqueue.numitems || txbuf.numitems
1272 || inflight.numitems) {
1279 struct reqcontext *prc;
1285 if (readtransactionfile)
1286 FD_SET(logfd, &rset);
1287 if ((!blocked && txqueue.numitems) || txbuf.numitems)
1288 FD_SET(sock, &wset);
1289 if (inflight.numitems)
1290 FD_SET(sock, &rset);
1294 select(1 + ((sock > logfd) ? sock : logfd), &rset, &wset,
1297 snprintf(errstr, errstr_len,
1298 "Timeout reading from socket");
1300 } else if (ret < 0) {
1301 g_warning("Could not mmap temp file: %s", errstr);
1304 /* We know we've got at least one thing to do here then */
1306 /* Get a command from the transaction log */
1307 if (FD_ISSET(logfd, &rset)) {
1309 /* Read a request or reply from the transaction file */
1310 READ_ALL_ERRCHK(logfd,
1314 "Could not read transaction log: %s",
1316 magic = ntohl(magic);
1318 case NBD_REQUEST_MAGIC:
1321 calloc(1, sizeof(struct reqcontext)))) {
1322 snprintf(errstr, errstr_len,
1323 "Could not allocate request");
1326 READ_ALL_ERRCHK(logfd,
1328 (char *)&(prc->req),
1329 sizeof(struct nbd_request) -
1330 sizeof(magic), err_open,
1331 "Could not read transaction log: %s",
1333 prc->req.magic = htonl(NBD_REQUEST_MAGIC);
1334 memcpy(prc->orighandle, prc->req.handle, 8);
1336 if ((ntohl(prc->req.type) &
1337 NBD_CMD_MASK_COMMAND) == NBD_CMD_DISC) {
1338 /* no more to read; don't enqueue as no reply
1339 * we will disconnect manually at the end
1341 readtransactionfile = 0;
1344 dumpcommand("Enqueuing command",
1346 rclist_addtail(&txqueue, prc);
1350 case NBD_REPLY_MAGIC:
1351 READ_ALL_ERRCHK(logfd,
1352 sizeof(magic) + (char *)(&rep),
1353 sizeof(struct nbd_reply) -
1354 sizeof(magic), err_open,
1355 "Could not read transaction log: %s",
1359 snprintf(errstr, errstr_len,
1360 "Transaction log file contained errored transaction");
1364 /* We do not need to consume data on a read reply as there is
1365 * none in the log */
1368 snprintf(errstr, errstr_len,
1369 "Could not measure start time: %08x",
1375 /* See if we have a write we can do */
1376 if (FD_ISSET(sock, &wset)) {
1377 if ((!(txqueue.head) && !(txbuf.head)) || blocked)
1379 ("Socket write FD set but we shouldn't have been interested");
1381 /* If there is no buffered data, generate some */
1382 if (!blocked && !(txbuf.head)
1383 && (NULL != (prc = txqueue.head))) {
1384 if (ntohl(prc->req.magic) != NBD_REQUEST_MAGIC) {
1386 ("Asked to write a request without a magic number");
1390 command = ntohl(prc->req.type);
1391 from = ntohll(prc->req.from);
1392 len = ntohl(prc->req.len);
1394 /* First check whether we can touch this command at all. If this
1395 * command is a read, and there is an inflight write, OR if this
1396 * command is a write, and there is an inflight read or write, then
1397 * we need to leave the command alone and signal that we are blocked
1400 if (!looseordering) {
1406 uint64_t blknum = cfrom >> 9;
1407 if (cfrom >= size) {
1410 "offset %llx beyond size %llx",
1417 if (blkhash[blknum].inflightw ||
1418 (blkhash[blknum].inflightr
1421 NBD_CMD_MASK_COMMAND) ==
1434 rclist_unlink(&txqueue, prc);
1435 rclist_addtail(&inflight, prc);
1437 dumpcommand("Sending command", prc->req.type);
1438 /* we rewrite the handle as they otherwise may not be unique */
1439 *((uint64_t *) (prc->req.handle)) =
1440 getrandomhandle(handlehash);
1441 g_hash_table_insert(handlehash, prc->req.handle,
1443 addbuffer(&txbuf, &(prc->req),
1444 sizeof(struct nbd_request));
1445 switch (command & NBD_CMD_MASK_COMMAND) {
1449 uint64_t blknum = from >> 9;
1454 "offset %llx beyond size %llx",
1461 (blkhash[blknum].inflightw)++;
1462 /* work out what we should be writing */
1463 makebuf(dbuf, prc->seq, blknum);
1464 addbuffer(&txbuf, dbuf, 512);
1472 uint64_t blknum = from >> 9;
1476 "offset %llx beyond size %llx",
1483 (blkhash[blknum].inflightr)++;
1492 snprintf(errstr, errstr_len,
1493 "Incomprehensible command: %08x",
1503 /* there should be some now */
1504 if (writebuffer(sock, &txbuf) < 0) {
1505 snprintf(errstr, errstr_len,
1506 "Failed to write to socket buffer: %s",
1513 /* See if there is a reply to be processed from the socket */
1514 if (FD_ISSET(sock, &rset)) {
1515 /* Okay, there's something ready for
1518 READ_ALL_ERRCHK(sock,
1520 sizeof(struct nbd_reply),
1522 "Could not read from server socket: %s",
1525 if (rep.magic != htonl(NBD_REPLY_MAGIC)) {
1526 snprintf(errstr, errstr_len,
1527 "Bad magic from server");
1532 snprintf(errstr, errstr_len,
1533 "Server errored a transaction");
1538 memcpy(&handle, rep.handle, 8);
1539 prc = g_hash_table_lookup(handlehash, &handle);
1541 snprintf(errstr, errstr_len,
1542 "Unrecognised handle in reply: 0x%llX",
1543 *(long long unsigned int *)(rep.
1547 if (!g_hash_table_remove(handlehash, &handle)) {
1548 snprintf(errstr, errstr_len,
1549 "Could not remove handle from hash: 0x%llX",
1550 *(long long unsigned int *)(rep.
1555 if (prc->req.magic != htonl(NBD_REQUEST_MAGIC)) {
1556 snprintf(errstr, errstr_len,
1557 "Bad magic in inflight data: %08x",
1562 dumpcommand("Processing reply to command",
1564 command = ntohl(prc->req.type);
1565 from = ntohll(prc->req.from);
1566 len = ntohl(prc->req.len);
1568 switch (command & NBD_CMD_MASK_COMMAND) {
1571 uint64_t blknum = from >> 9;
1574 snprintf(errstr, errstr_len,
1575 "offset %llx beyond size %llx",
1576 (long long int)from,
1577 (long long int)size);
1580 READ_ALL_ERRCHK(sock,
1584 "Could not read data: %s",
1586 if (--(blkhash[blknum].inflightr) < 0) {
1587 snprintf(errstr, errstr_len,
1588 "Received a read reply for offset %llx when not in flight",
1589 (long long int)from);
1592 /* work out what we was written */
1594 (dbuf, blkhash[blknum].seq,
1596 snprintf(errstr, errstr_len,
1597 "Bad reply data: I wanted blk %08x, seq %08x but I got (at a guess) blk %08x, seq %08x",
1598 (unsigned int)blknum,
1599 blkhash[blknum].seq,
1613 /* subsequent reads should get data with this seq */
1615 uint64_t blknum = from >> 9;
1616 if (--(blkhash[blknum].inflightw) < 0) {
1617 snprintf(errstr, errstr_len,
1618 "Received a write reply for offset %llx when not in flight",
1619 (long long int)from);
1622 blkhash[blknum].seq =
1623 (uint32_t) (prc->seq);
1633 rclist_unlink(&inflight, prc);
1634 prc->req.magic = 0; /* so a duplicate reply is detected */
1638 if ((do_print == NULL && !(printer++ % 5000))
1639 || !(readtransactionfile || txqueue.numitems
1640 || inflight.numitems))
1642 ("%d: Seq %08lld Queued: %08d Inflight: %08d Done: %08lld\r",
1643 (int)mypid, (long long int)seq, txqueue.numitems,
1644 inflight.numitems, (long long int)processed);
1650 if (gettimeofday(&stop, NULL) < 0) {
1651 snprintf(errstr, errstr_len, "Could not measure end time: %s",
1655 timespan = timeval_diff_to_double(&stop, &start);
1656 speed = xfer / timespan;
1658 speed = speed / 1024.0;
1662 speed = speed / 1024.0;
1666 speed = speed / 1024.0;
1670 ("%d: Integrity %s test complete. Took %.3f seconds to complete, %.3f%sib/s",
1671 (int)getpid(), (testflags & TEST_WRITE) ? "write" : "read",
1672 timespan, speed, speedchar);
1678 close_connection(sock, CONNECTION_CLOSE_PROPERLY);
1681 if (size && blkhash)
1682 munmap(blkhash, (size >> 9) * sizeof(struct blkitem));
1684 if (blkhashfd != -1)
1694 g_warning("%s", errstr);
1696 g_hash_table_destroy(handlehash);
1701 void handle_nonopt(char *opt, gchar ** hostname, long int *p)
1703 static int nonopt = 0;
1707 *hostname = g_strdup(opt);
1711 *p = (strtol(opt, NULL, 0));
1712 if (*p == LONG_MIN || *p == LONG_MAX) {
1713 g_critical("Could not parse port number: %s",
1721 typedef int (*testfunc) (char *, int, char, int);
1723 int main(int argc, char **argv)
1725 gchar *hostname = NULL, *unixsock = NULL;
1731 testfunc test = throughput_test;
1737 /* Ignore SIGPIPE as we want to pick up the error from write() */
1738 signal(SIGPIPE, SIG_IGN);
1740 errstr[errstr_len] = '\0';
1743 g_message("%d: Not enough arguments", (int)getpid());
1744 g_message("%d: Usage: %s <hostname> <port>", (int)getpid(),
1746 g_message("%d: Or: %s <hostname> -N <exportname> [<port>]",
1747 (int)getpid(), argv[0]);
1748 g_message("%d: Or: %s -u <unix socket> -N <exportname>",
1749 (int)getpid(), argv[0]);
1753 while ((c = getopt(argc, argv, "FN:t:owfilu:hC:K:A:H:I")) >= 0) {
1756 handle_nonopt(optarg, &hostname, &p);
1759 name = g_strdup(optarg);
1762 testflags |= TEST_EXPECT_ERROR;
1765 transactionlog = g_strdup(optarg);
1768 test = oversize_test;
1774 testflags |= TEST_WRITE;
1777 testflags |= TEST_FLUSH;
1781 err_nonfatal("inetd mode not supported without syslog support");
1787 test = integrity_test;
1790 unixsock = g_strdup(optarg);
1793 test = handshake_test;
1794 testflags |= TEST_HANDSHAKE;
1798 certfile=g_strdup(optarg);
1801 keyfile=g_strdup(optarg);
1804 cacertfile=g_strdup(optarg);
1807 tlshostname=g_strdup(optarg);
1814 g_warning("TLS support not compiled in");
1815 /* Do not change this - looked for by test suite */
1822 while (optind < argc) {
1823 handle_nonopt(argv[optind++], &hostname, &p);
1827 if (keyfile && !certfile)
1828 certfile = g_strdup(keyfile);
1830 if (!tlshostname && hostname)
1831 tlshostname = g_strdup(hostname);
1833 if (hostname != NULL) {
1834 sock = setup_inet_connection(hostname, p);
1835 } else if (unixsock != NULL) {
1836 sock = setup_unix_connection(unixsock);
1837 } else if (p == -1) {
1838 sock = setup_inetd_connection(argv + optind);
1840 g_error("need a hostname, a unix domain socket or inetd-mode command line!");
1845 g_warning("Could not establish a connection: %s", errstr);
1849 if (test(name, sock, TRUE, testflags)
1851 g_warning("Could not run test: %s", errstr);