Fix a few GCC warnings
[nbd.git] / tests / run / nbd-tester-client.c
blobeab57a1b093815a623507078bce32800460d44bd
1 /*
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
18 * more details.
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
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/un.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <fcntl.h>
35 #include <syslog.h>
36 #include <unistd.h>
37 #include "config.h"
38 #include "lfs.h"
39 #include <netinet/in.h>
40 #include <glib.h>
42 #define MY_NAME "nbd-tester-client"
43 #include "cliserv.h"
45 #if HAVE_GNUTLS
46 #include "crypto-gnutls.h"
47 #endif
49 static gchar errstr[1024];
50 const static int errstr_len = 1023;
52 static uint64_t size;
54 static int looseordering = 0;
56 static gchar *transactionlog = "nbd-tester-client.tr";
57 static gchar *certfile = NULL;
58 static gchar *keyfile = NULL;
59 static gchar *cacertfile = NULL;
60 static gchar *tlshostname = NULL;
62 typedef enum {
63 CONNECTION_TYPE_NONE,
64 CONNECTION_TYPE_CONNECT,
65 CONNECTION_TYPE_INIT_PASSWD,
66 CONNECTION_TYPE_CLISERV,
67 CONNECTION_TYPE_FULL,
68 } CONNECTION_TYPE;
70 typedef enum {
71 CONNECTION_CLOSE_PROPERLY,
72 CONNECTION_CLOSE_FAST,
73 } CLOSE_TYPE;
75 struct reqcontext {
76 uint64_t seq;
77 char orighandle[8];
78 struct nbd_request req;
79 struct reqcontext *next;
80 struct reqcontext *prev;
83 struct rclist {
84 struct reqcontext *head;
85 struct reqcontext *tail;
86 int numitems;
89 struct chunk {
90 char *buffer;
91 char *readptr;
92 char *writeptr;
93 uint64_t space;
94 uint64_t length;
95 struct chunk *next;
96 struct chunk *prev;
99 struct chunklist {
100 struct chunk *head;
101 struct chunk *tail;
102 int numitems;
105 struct blkitem {
106 uint32_t seq;
107 int32_t inflightr;
108 int32_t inflightw;
111 void rclist_unlink(struct rclist *l, struct reqcontext *p)
113 if (p && l) {
114 struct reqcontext *prev = p->prev;
115 struct reqcontext *next = p->next;
117 /* Fix link to previous */
118 if (prev)
119 prev->next = next;
120 else
121 l->head = next;
123 if (next)
124 next->prev = prev;
125 else
126 l->tail = prev;
128 p->prev = NULL;
129 p->next = NULL;
130 l->numitems--;
134 /* Add a new list item to the tail */
135 void rclist_addtail(struct rclist *l, struct reqcontext *p)
137 if (!p || !l)
138 return;
139 if (l->tail) {
140 if (l->tail->next)
141 g_warning("addtail found list tail has a next pointer");
142 l->tail->next = p;
143 p->next = NULL;
144 p->prev = l->tail;
145 l->tail = p;
146 } else {
147 if (l->head)
148 g_warning("addtail found no list tail but a list head");
149 l->head = p;
150 l->tail = p;
151 p->prev = NULL;
152 p->next = NULL;
154 l->numitems++;
157 void chunklist_unlink(struct chunklist *l, struct chunk *p)
159 if (p && l) {
160 struct chunk *prev = p->prev;
161 struct chunk *next = p->next;
163 /* Fix link to previous */
164 if (prev)
165 prev->next = next;
166 else
167 l->head = next;
169 if (next)
170 next->prev = prev;
171 else
172 l->tail = prev;
174 p->prev = NULL;
175 p->next = NULL;
176 l->numitems--;
180 /* Add a new list item to the tail */
181 void chunklist_addtail(struct chunklist *l, struct chunk *p)
183 if (!p || !l)
184 return;
185 if (l->tail) {
186 if (l->tail->next)
187 g_warning("addtail found list tail has a next pointer");
188 l->tail->next = p;
189 p->next = NULL;
190 p->prev = l->tail;
191 l->tail = p;
192 } else {
193 if (l->head)
194 g_warning("addtail found no list tail but a list head");
195 l->head = p;
196 l->tail = p;
197 p->prev = NULL;
198 p->next = NULL;
200 l->numitems++;
203 /* Add some new bytes to a chunklist */
204 void addbuffer(struct chunklist *l, void *data, uint64_t len)
206 void *buf;
207 uint64_t size = 64 * 1024;
208 struct chunk *pchunk;
210 while (len > 0) {
211 /* First see if there is a current chunk, and if it has space */
212 if (l->tail && l->tail->space) {
213 uint64_t towrite = len;
214 if (towrite > l->tail->space)
215 towrite = l->tail->space;
216 memcpy(l->tail->writeptr, data, towrite);
217 l->tail->length += towrite;
218 l->tail->space -= towrite;
219 l->tail->writeptr += towrite;
220 len -= towrite;
221 data += towrite;
224 if (len > 0) {
225 /* We still need to write more, so prepare a new chunk */
226 if ((NULL == (buf = malloc(size)))
227 || (NULL ==
228 (pchunk = calloc(1, sizeof(struct chunk))))) {
229 g_critical("Out of memory");
230 exit(1);
233 pchunk->buffer = buf;
234 pchunk->readptr = buf;
235 pchunk->writeptr = buf;
236 pchunk->space = size;
237 chunklist_addtail(l, pchunk);
243 /* returns 0 on success, -1 on failure */
244 int writebuffer(int fd, struct chunklist *l)
247 struct chunk *pchunk = NULL;
248 int res;
249 if (!l)
250 return 0;
252 while (!pchunk) {
253 pchunk = l->head;
254 if (!pchunk)
255 return 0;
256 if (!(pchunk->length) || !(pchunk->readptr)) {
257 chunklist_unlink(l, pchunk);
258 free(pchunk->buffer);
259 free(pchunk);
260 pchunk = NULL;
264 /* OK we have a chunk with some data in */
265 res = write(fd, pchunk->readptr, pchunk->length);
266 if (res == 0)
267 errno = EAGAIN;
268 if (res <= 0)
269 return -1;
270 pchunk->length -= res;
271 pchunk->readptr += res;
272 if (!pchunk->length) {
273 chunklist_unlink(l, pchunk);
274 free(pchunk->buffer);
275 free(pchunk);
277 return 0;
280 #define TEST_WRITE (1<<0)
281 #define TEST_FLUSH (1<<1)
282 #define TEST_EXPECT_ERROR (1<<2)
283 #define TEST_HANDSHAKE (1<<3)
285 int timeval_subtract(struct timeval *result, struct timeval *x,
286 struct timeval *y)
288 if (x->tv_usec < y->tv_usec) {
289 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
290 y->tv_usec -= 1000000 * nsec;
291 y->tv_sec += nsec;
294 if (x->tv_usec - y->tv_usec > 1000000) {
295 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
296 y->tv_usec += 1000000 * nsec;
297 y->tv_sec -= nsec;
300 result->tv_sec = x->tv_sec - y->tv_sec;
301 result->tv_usec = x->tv_usec - y->tv_usec;
303 return x->tv_sec < y->tv_sec;
306 double timeval_diff_to_double(struct timeval *x, struct timeval *y)
308 struct timeval r;
309 timeval_subtract(&r, x, y);
310 return r.tv_sec * 1.0 + r.tv_usec / 1000000.0;
313 static inline int read_all(int f, void *buf, size_t len)
315 ssize_t res;
316 size_t retval = 0;
318 while (len > 0) {
319 if ((res = read(f, buf, len)) <= 0) {
320 if (!res)
321 errno = EAGAIN;
322 snprintf(errstr, errstr_len, "Read failed: %s",
323 strerror(errno));
324 return -1;
326 len -= res;
327 buf += res;
328 retval += res;
330 return retval;
333 static inline int write_all(int f, void *buf, size_t len)
335 ssize_t res;
336 size_t retval = 0;
338 while (len > 0) {
339 if ((res = write(f, buf, len)) <= 0) {
340 if (!res)
341 errno = EAGAIN;
342 snprintf(errstr, errstr_len, "Write failed: %s",
343 strerror(errno));
344 return -1;
346 len -= res;
347 buf += res;
348 retval += res;
350 return retval;
353 static int tlserrout (void *opaque, const char *format, va_list ap) {
354 return vfprintf(stderr, format, ap);
357 #define READ_ALL_ERRCHK(f, buf, len, whereto, errmsg...) if((read_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); goto whereto; }
358 #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; }
360 #define WRITE_ALL_ERRCHK(f, buf, len, whereto, errmsg...) if((write_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); goto whereto; }
361 #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; }
363 int setup_connection_common(int sock, char *name, CONNECTION_TYPE ctype,
364 int *serverflags, int testflags)
366 char buf[256];
367 u64 tmp64;
368 uint64_t mymagic = (name ? opts_magic : cliserv_magic);
369 uint32_t tmp32 = 0;
370 uint16_t handshakeflags = 0;
371 uint32_t negotiationflags = 0;
373 if (ctype < CONNECTION_TYPE_INIT_PASSWD)
374 goto end;
375 READ_ALL_ERRCHK(sock, buf, strlen(INIT_PASSWD), err,
376 "Could not read INIT_PASSWD: %s", strerror(errno));
377 if (strlen(buf) == 0) {
378 snprintf(errstr, errstr_len, "Server closed connection");
379 goto err;
381 if (strncmp(buf, INIT_PASSWD, strlen(INIT_PASSWD))) {
382 snprintf(errstr, errstr_len, "INIT_PASSWD does not match");
383 goto err;
385 if (ctype < CONNECTION_TYPE_CLISERV)
386 goto end;
387 READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
388 "Could not read cliserv_magic: %s", strerror(errno));
389 tmp64 = ntohll(tmp64);
390 if (tmp64 != mymagic) {
391 strncpy(errstr, "mymagic does not match", errstr_len);
392 goto err;
394 if (ctype < CONNECTION_TYPE_FULL)
395 goto end;
396 if (!name) {
397 READ_ALL_ERRCHK(sock, &size, sizeof(size), err,
398 "Could not read size: %s", strerror(errno));
399 size = ntohll(size);
400 uint32_t flags;
401 READ_ALL_ERRCHK(sock, &flags, sizeof(uint32_t), err,
402 "Could not read flags: %s", strerror(errno));
403 flags = ntohl(flags);
404 *serverflags = flags;
405 READ_ALL_ERRCHK(sock, buf, 124, err, "Could not read data: %s",
406 strerror(errno));
407 goto end;
409 /* handshake flags */
410 READ_ALL_ERRCHK(sock, &handshakeflags, sizeof(handshakeflags), err,
411 "Could not read reserved field: %s", strerror(errno));
412 handshakeflags = ntohs(handshakeflags);
413 /* negotiation flags */
414 if (handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)
415 negotiationflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
416 else if (keyfile) {
417 snprintf(errstr, errstr_len, "Cannot negotiate TLS without NBD_FLAG_FIXED_NEWSTYLE");
418 goto err;
420 negotiationflags = htonl(negotiationflags);
421 WRITE_ALL_ERRCHK(sock, &negotiationflags, sizeof(negotiationflags), err,
422 "Could not write reserved field: %s", strerror(errno));
423 if (testflags & TEST_HANDSHAKE) {
424 /* Server must support newstyle for this test */
425 if (!(handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)) {
426 strncpy(errstr, "server does not support handshake", errstr_len);
427 goto err;
429 goto end;
431 #if HAVE_GNUTLS
432 /* TLS */
433 if (keyfile) {
434 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
435 tlssession_t *s = NULL;
436 int ret;
438 /* magic */
439 tmp64 = htonll(opts_magic);
440 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
441 "Could not write magic: %s", strerror(errno));
442 /* starttls */
443 tmp32 = htonl(NBD_OPT_STARTTLS);
444 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
445 "Could not write option: %s", strerror(errno));
446 /* length of data */
447 tmp32 = htonl(0);
448 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
449 "Could not write option length: %s", strerror(errno));
451 READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
452 "Could not read cliserv_magic: %s", strerror(errno));
453 tmp64 = ntohll(tmp64);
454 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
455 strncpy(errstr, "reply magic does not match", errstr_len);
456 goto err;
458 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
459 "Could not read option type: %s", strerror(errno));
460 tmp32 = ntohl(tmp32);
461 if (tmp32 != NBD_OPT_STARTTLS) {
462 strncpy(errstr, "Reply to wrong option", errstr_len);
463 goto err;
465 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
466 "Could not read option reply type: %s", strerror(errno));
467 tmp32 = ntohl(tmp32);
468 if (tmp32 != NBD_REP_ACK) {
469 if(tmp32 & NBD_REP_FLAG_ERROR) {
470 snprintf(errstr, errstr_len, "Received error %d", tmp32 & ~NBD_REP_FLAG_ERROR);
471 } else {
472 snprintf(errstr, errstr_len, "Option reply type %d != NBD_REP_ACK", tmp32);
474 goto err;
476 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
477 "Could not read option data length: %s", strerror(errno));
478 tmp32 = ntohl(tmp32);
479 if (tmp32 != 0) {
480 strncpy(errstr, "Option reply data length != 0", errstr_len);
481 goto err;
484 s = tlssession_new(FALSE,
485 keyfile,
486 certfile,
487 cacertfile,
488 tlshostname,
489 !cacertfile || !tlshostname, // insecure flag
490 #ifdef DODBG
491 1, // debug
492 #else
493 0, // debug
494 #endif
495 NULL, // quitfn
496 tlserrout, // erroutfn
497 NULL // opaque
499 if (!s) {
500 strncpy(errstr, "Cannot establish TLS session", errstr_len);
501 goto err;
504 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0) {
505 strncpy(errstr, "Cannot get socket pair", errstr_len);
506 goto err;
509 if (set_nonblocking(plainfd[0], 0) <0 ||
510 set_nonblocking(plainfd[1], 0) <0 ||
511 set_nonblocking(sock, 0) <0) {
512 close(plainfd[0]);
513 close(plainfd[1]);
514 strncpy(errstr, "Cannot set socket options", errstr_len);
515 goto err;
518 ret = fork();
519 if (ret < 0)
520 err("Could not fork");
521 else if (ret == 0) {
522 // we are the child
523 signal (SIGPIPE, SIG_IGN);
524 close(plainfd[1]);
525 tlssession_mainloop(sock, plainfd[0], s);
526 close(sock);
527 close(plainfd[0]);
528 exit(0);
530 close(plainfd[0]);
531 close(sock);
532 sock = plainfd[1]; /* use the decrypted FD from now on */
534 #else
535 if (keyfile) {
536 strncpy(errstr, "TLS requested but support not compiled in", errstr_len);
537 goto err;
539 #endif
540 if(testflags & TEST_EXPECT_ERROR) {
541 struct sigaction act;
542 memset(&act, '0', sizeof act);
543 act.sa_handler = SIG_IGN;
544 sigaction(SIGPIPE, &act, NULL);
546 /* magic */
547 tmp64 = htonll(opts_magic);
548 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
549 "Could not write magic: %s", strerror(errno));
550 /* name */
551 tmp32 = htonl(NBD_OPT_EXPORT_NAME);
552 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
553 "Could not write option: %s", strerror(errno));
554 tmp32 = htonl((uint32_t) strlen(name));
555 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
556 "Could not write name length: %s", strerror(errno));
557 WRITE_ALL_ERRCHK(sock, name, strlen(name), err,
558 "Could not write name:: %s", strerror(errno));
559 READ_ALL_ERRCHK(sock, &size, sizeof(size), err,
560 "Could not read size: %s", strerror(errno));
561 size = ntohll(size);
562 uint16_t flags;
563 READ_ALL_ERRCHK(sock, &flags, sizeof(uint16_t), err,
564 "Could not read flags: %s", strerror(errno));
565 flags = ntohs(flags);
566 *serverflags = flags;
567 READ_ALL_ERRCHK(sock, buf, 124, err,
568 "Could not read reserved zeroes: %s", strerror(errno));
569 goto end;
570 err:
571 close(sock);
572 sock = -1;
573 end:
574 return sock;
577 int setup_unix_connection(gchar * unixsock, gchar * name, CONNECTION_TYPE ctype,
578 int *serverflags, int testflags)
580 struct sockaddr_un addr;
581 int sock;
583 sock = 0;
584 if (ctype < CONNECTION_TYPE_CONNECT) {
585 goto end;
587 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
588 strncpy(errstr, strerror(errno), errstr_len);
589 goto err;
592 setmysockopt(sock);
593 memset(&addr, 0, sizeof(struct sockaddr_un));
594 addr.sun_family = AF_UNIX;
595 strncpy(addr.sun_path, unixsock, sizeof addr.sun_path);
596 addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
597 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
598 strncpy(errstr, strerror(errno), errstr_len);
599 goto err_open;
601 sock = setup_connection_common(sock, name, ctype, serverflags, testflags);
602 goto end;
603 err_open:
604 close(sock);
605 err:
606 sock = -1;
607 end:
608 return sock;
611 int setup_inet_connection(gchar * hostname, int port, gchar * name,
612 CONNECTION_TYPE ctype, int *serverflags, int testflags)
614 int sock;
615 struct hostent *host;
616 struct sockaddr_in addr;
618 sock = 0;
619 if (ctype < CONNECTION_TYPE_CONNECT)
620 goto end;
621 if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
622 strncpy(errstr, strerror(errno), errstr_len);
623 goto err;
625 setmysockopt(sock);
626 if (!(host = gethostbyname(hostname))) {
627 strncpy(errstr, hstrerror(h_errno), errstr_len);
628 goto err_open;
630 addr.sin_family = AF_INET;
631 addr.sin_port = htons(port);
632 addr.sin_addr.s_addr = *((int *)host->h_addr);
633 if ((connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)) {
634 strncpy(errstr, strerror(errno), errstr_len);
635 goto err_open;
637 sock = setup_connection_common(sock, name, ctype, serverflags, testflags);
638 goto end;
639 err_open:
640 close(sock);
641 err:
642 sock = -1;
643 end:
644 return sock;
647 int setup_connection(gchar * hostname, gchar * unixsock, int port, gchar * name,
648 CONNECTION_TYPE ctype, int *serverflags, int testflags)
650 if (hostname != NULL) {
651 return setup_inet_connection(hostname, port, name, ctype,
652 serverflags, testflags);
653 } else if (unixsock != NULL) {
654 return setup_unix_connection(unixsock, name, ctype,
655 serverflags, testflags);
656 } else {
657 g_error("need a hostname or a unix domain socket!");
658 return -1;
662 int close_connection(int sock, CLOSE_TYPE type)
664 struct nbd_request req;
665 u64 counter = 0;
667 switch (type) {
668 case CONNECTION_CLOSE_PROPERLY:
669 req.magic = htonl(NBD_REQUEST_MAGIC);
670 req.type = htonl(NBD_CMD_DISC);
671 memcpy(&(req.handle), &(counter), sizeof(counter));
672 counter++;
673 req.from = 0;
674 req.len = 0;
675 if (write(sock, &req, sizeof(req)) < 0) {
676 snprintf(errstr, errstr_len,
677 "Could not write to socket: %s",
678 strerror(errno));
679 return -1;
681 case CONNECTION_CLOSE_FAST:
682 if (close(sock) < 0) {
683 snprintf(errstr, errstr_len,
684 "Could not close socket: %s", strerror(errno));
685 return -1;
687 break;
688 default:
689 g_critical("Your compiler is on crack!"); /* or I am buggy */
690 return -1;
692 return 0;
695 int read_packet_check_header(int sock, size_t datasize, long long int curhandle)
697 struct nbd_reply rep;
698 int retval = 0;
699 char buf[datasize];
701 READ_ALL_ERR_RT(sock, &rep, sizeof(rep), end, -1,
702 "Could not read reply header: %s", strerror(errno));
703 rep.magic = ntohl(rep.magic);
704 rep.error = ntohl(rep.error);
705 if (rep.magic != NBD_REPLY_MAGIC) {
706 snprintf(errstr, errstr_len,
707 "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",
708 (long long int)curhandle,
709 (long long unsigned int)curhandle,
710 (long long int)*((u64 *) rep.handle),
711 (long long unsigned int)*((u64 *) rep.handle),
712 (long unsigned int)rep.magic,
713 (long unsigned int)NBD_REPLY_MAGIC);
714 retval = -1;
715 goto end;
717 if (rep.error) {
718 snprintf(errstr, errstr_len,
719 "Received error from server: %ld (0x%lX). Handle is %lld (0x%llX).",
720 (long int)rep.error, (long unsigned int)rep.error,
721 (long long int)(*((u64 *) rep.handle)),
722 (long long unsigned int)*((u64 *) rep.handle));
723 retval = -2;
724 goto end;
726 if (datasize)
727 READ_ALL_ERR_RT(sock, &buf, datasize, end, -1,
728 "Could not read data: %s", strerror(errno));
730 end:
731 return retval;
734 int oversize_test(gchar * hostname, gchar * unixsock, int port, char *name,
735 int sock, char sock_is_open, char close_sock, int testflags)
737 int retval = 0;
738 struct nbd_request req;
739 struct nbd_reply rep;
740 int i = 0;
741 int serverflags = 0;
742 pid_t G_GNUC_UNUSED mypid = getpid();
743 char buf[((1024 * 1024) + sizeof(struct nbd_request) / 2) << 1];
744 bool got_err;
746 /* This should work */
747 if (!sock_is_open) {
748 if ((sock =
749 setup_connection(hostname, unixsock, port, name,
750 CONNECTION_TYPE_FULL,
751 &serverflags, testflags)) < 0) {
752 g_warning("Could not open socket: %s", errstr);
753 retval = -1;
754 goto err;
757 req.magic = htonl(NBD_REQUEST_MAGIC);
758 req.type = htonl(NBD_CMD_READ);
759 req.len = htonl(1024 * 1024);
760 memcpy(&(req.handle), &i, sizeof(i));
761 req.from = htonll(i);
762 WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1,
763 "Could not write request: %s", strerror(errno));
764 printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len));
765 READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1,
766 "Could not read reply header: %s", strerror(errno));
767 READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1,
768 "Could not read data: %s", strerror(errno));
769 if (rep.error) {
770 snprintf(errstr, errstr_len, "Received unexpected error: %d",
771 rep.error);
772 retval = -1;
773 goto err;
774 } else {
775 printf("OK\n");
777 /* This probably should not work */
778 i++;
779 req.from = htonll(i);
780 req.len = htonl(ntohl(req.len) + sizeof(struct nbd_request) / 2);
781 WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1,
782 "Could not write request: %s", strerror(errno));
783 printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len));
784 READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1,
785 "Could not read reply header: %s", strerror(errno));
786 READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1,
787 "Could not read data: %s", strerror(errno));
788 if (rep.error) {
789 printf("Received expected error\n");
790 got_err = true;
791 } else {
792 printf("OK\n");
793 got_err = false;
795 /* ... unless this works, too */
796 i++;
797 req.from = htonll(i);
798 req.len = htonl(ntohl(req.len) << 1);
799 WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1,
800 "Could not write request: %s", strerror(errno));
801 printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len));
802 READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1,
803 "Could not read reply header: %s", strerror(errno));
804 READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1,
805 "Could not read data: %s", strerror(errno));
806 if (rep.error) {
807 printf("error\n");
808 } else {
809 printf("OK\n");
811 if ((rep.error && !got_err) || (!rep.error && got_err)) {
812 printf("Received unexpected error\n");
813 retval = -1;
815 err:
816 return retval;
819 int handshake_test(gchar * hostname, gchar * unixsock, int port, char *name,
820 int sock, char sock_is_open, char close_sock, int testflags)
822 int retval = -1;
823 int serverflags = 0;
824 u64 tmp64;
825 uint32_t tmp32 = 0;
827 /* This should work */
828 if (!sock_is_open) {
829 if ((sock =
830 setup_connection(hostname, unixsock, port, name,
831 CONNECTION_TYPE_FULL,
832 &serverflags, testflags)) < 0) {
833 g_warning("Could not open socket: %s", errstr);
834 goto err;
838 /* Intentionally throw an unknown option at the server */
839 tmp64 = htonll(opts_magic);
840 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
841 "Could not write magic: %s", strerror(errno));
842 tmp32 = htonl(0x7654321);
843 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
844 "Could not write option: %s", strerror(errno));
845 tmp32 = htonl((uint32_t) sizeof(tmp32));
846 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
847 "Could not write option length: %s", strerror(errno));
848 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
849 "Could not write option payload: %s", strerror(errno));
850 /* Expect proper error from server */
851 READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
852 "Could not read magic: %s", strerror(errno));
853 tmp64 = ntohll(tmp64);
854 if (tmp64 != 0x3e889045565a9LL) {
855 strncpy(errstr, "magic does not match", errstr_len);
856 goto err;
858 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
859 "Could not read option: %s", strerror(errno));
860 tmp32 = ntohl(tmp32);
861 if (tmp32 != 0x7654321) {
862 strncpy(errstr, "option does not match", errstr_len);
863 goto err;
865 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
866 "Could not read status: %s", strerror(errno));
867 tmp32 = ntohl(tmp32);
868 if (tmp32 != NBD_REP_ERR_UNSUP) {
869 strncpy(errstr, "status does not match", errstr_len);
870 goto err;
872 READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
873 "Could not read length: %s", strerror(errno));
874 tmp32 = ntohl(tmp32);
875 while (tmp32) {
876 char buf[1024];
877 size_t len = tmp32 < sizeof(buf) ? tmp32 : sizeof(buf);
878 READ_ALL_ERRCHK(sock, buf, len, err,
879 "Could not read payload: %s", strerror(errno));
880 tmp32 -= len;
884 /* Send NBD_OPT_ABORT to close the connection */
885 tmp64 = htonll(opts_magic);
886 WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
887 "Could not write magic: %s", strerror(errno));
888 tmp32 = htonl(NBD_OPT_ABORT);
889 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
890 "Could not write option: %s", strerror(errno));
891 tmp32 = htonl((uint32_t) 0);
892 WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
893 "Could not write option length: %s", strerror(errno));
895 retval = 0;
897 g_message("Handshake test completed. No errors encountered.");
898 err:
899 return retval;
902 int throughput_test(gchar * hostname, gchar * unixsock, int port, char *name,
903 int sock, char sock_is_open, char close_sock, int testflags)
905 long long int i;
906 char writebuf[1024];
907 struct nbd_request req;
908 int requests = 0;
909 fd_set set;
910 struct timeval tv;
911 struct timeval start;
912 struct timeval stop;
913 double timespan;
914 double speed;
915 char speedchar[2] = { '\0', '\0' };
916 int retval = 0;
917 int serverflags = 0;
918 signed int do_write = TRUE;
919 pid_t mypid = getpid();
920 char *print = getenv("NBD_TEST_SILENT");
922 if (!(testflags & TEST_WRITE))
923 testflags &= ~TEST_FLUSH;
925 memset(writebuf, 'X', 1024);
926 size = 0;
927 if (!sock_is_open) {
928 if ((sock =
929 setup_connection(hostname, unixsock, port, name,
930 CONNECTION_TYPE_FULL,
931 &serverflags, testflags)) < 0) {
932 g_warning("Could not open socket: %s", errstr);
933 if(testflags & TEST_EXPECT_ERROR) {
934 g_message("Test failed, as expected");
935 retval = 0;
936 } else {
937 retval = -1;
939 goto err;
942 if ((testflags & TEST_FLUSH)
943 && ((serverflags & (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))
944 != (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))) {
945 snprintf(errstr, errstr_len,
946 "Server did not supply flush capability flags");
947 retval = -1;
948 goto err_open;
950 req.magic = htonl(NBD_REQUEST_MAGIC);
951 req.len = htonl(1024);
952 if (gettimeofday(&start, NULL) < 0) {
953 retval = -1;
954 snprintf(errstr, errstr_len, "Could not measure start time: %s",
955 strerror(errno));
956 goto err_open;
958 for (i = 0; i + 1024 <= size; i += 1024) {
959 if (do_write) {
960 int sendfua = (testflags & TEST_FLUSH)
961 && (((i >> 10) & 15) == 3);
962 int sendflush = (testflags & TEST_FLUSH)
963 && (((i >> 10) & 15) == 11);
964 req.type =
965 htonl((testflags & TEST_WRITE) ? NBD_CMD_WRITE :
966 NBD_CMD_READ);
967 if (sendfua)
968 req.type =
969 htonl(NBD_CMD_WRITE | NBD_CMD_FLAG_FUA);
970 memcpy(&(req.handle), &i, sizeof(i));
971 req.from = htonll(i);
972 if (write_all(sock, &req, sizeof(req)) < 0) {
973 retval = -1;
974 goto err_open;
976 if (testflags & TEST_WRITE) {
977 if (write_all(sock, writebuf, 1024) < 0) {
978 retval = -1;
979 goto err_open;
982 ++requests;
983 if (sendflush) {
984 long long int j = i ^ (1LL << 63);
985 req.type = htonl(NBD_CMD_FLUSH);
986 memcpy(&(req.handle), &j, sizeof(j));
987 req.from = 0;
988 req.len = 0;
989 if (write_all(sock, &req, sizeof(req)) < 0) {
990 retval = -1;
991 goto err_open;
993 req.len = htonl(1024);
994 ++requests;
997 do {
998 FD_ZERO(&set);
999 FD_SET(sock, &set);
1000 tv.tv_sec = 0;
1001 tv.tv_usec = 0;
1002 select(sock + 1, &set, NULL, NULL, &tv);
1003 if (FD_ISSET(sock, &set)) {
1004 /* Okay, there's something ready for
1005 * reading here */
1006 int rv;
1007 if ((rv =
1008 read_packet_check_header(sock,
1009 (testflags &
1010 TEST_WRITE) ? 0 :
1011 1024, i)) < 0) {
1012 if (!(testflags & TEST_EXPECT_ERROR)
1013 || rv != -2) {
1014 retval = -1;
1015 } else {
1016 printf("\n");
1018 goto err_open;
1019 } else {
1020 if (testflags & TEST_EXPECT_ERROR) {
1021 retval = -1;
1022 goto err_open;
1025 --requests;
1027 } while (FD_ISSET(sock, &set));
1028 /* Now wait until we can write again or until a second have
1029 * passed, whichever comes first*/
1030 FD_ZERO(&set);
1031 FD_SET(sock, &set);
1032 tv.tv_sec = 1;
1033 tv.tv_usec = 0;
1034 do_write = select(sock + 1, NULL, &set, NULL, &tv);
1035 if (!do_write)
1036 printf("Select finished\n");
1037 if (do_write < 0) {
1038 snprintf(errstr, errstr_len, "select: %s",
1039 strerror(errno));
1040 retval = -1;
1041 goto err_open;
1043 if(print == NULL) {
1044 printf("%d: Requests: %d \r", (int)mypid, requests);
1047 /* Now empty the read buffer */
1048 do {
1049 FD_ZERO(&set);
1050 FD_SET(sock, &set);
1051 tv.tv_sec = 0;
1052 tv.tv_usec = 0;
1053 select(sock + 1, &set, NULL, NULL, &tv);
1054 if (FD_ISSET(sock, &set)) {
1055 /* Okay, there's something ready for
1056 * reading here */
1057 read_packet_check_header(sock,
1058 (testflags & TEST_WRITE) ? 0 :
1059 1024, i);
1060 --requests;
1062 if(print == NULL) {
1063 printf("%d: Requests: %d \r", (int)mypid, requests);
1065 } while (requests);
1066 printf("%d: Requests: %d \n", (int)mypid, requests);
1067 if (gettimeofday(&stop, NULL) < 0) {
1068 retval = -1;
1069 snprintf(errstr, errstr_len, "Could not measure end time: %s",
1070 strerror(errno));
1071 goto err_open;
1073 timespan = timeval_diff_to_double(&stop, &start);
1074 speed = size / timespan;
1075 if (speed > 1024) {
1076 speed = speed / 1024.0;
1077 speedchar[0] = 'K';
1079 if (speed > 1024) {
1080 speed = speed / 1024.0;
1081 speedchar[0] = 'M';
1083 if (speed > 1024) {
1084 speed = speed / 1024.0;
1085 speedchar[0] = 'G';
1087 g_message
1088 ("%d: Throughput %s test (%s flushes) complete. Took %.3f seconds to complete, %.3f%sib/s",
1089 (int)getpid(), (testflags & TEST_WRITE) ? "write" : "read",
1090 (testflags & TEST_FLUSH) ? "with" : "without", timespan, speed,
1091 speedchar);
1093 err_open:
1094 if (close_sock) {
1095 close_connection(sock, CONNECTION_CLOSE_PROPERLY);
1097 err:
1098 return retval;
1102 * fill 512 byte buffer 'buf' with a hashed selection of interesting data based
1103 * only on handle and blknum. The first word is blknum, and the second handle, for ease
1104 * of understanding. Things with handle 0 are blank.
1106 static inline void makebuf(char *buf, uint64_t seq, uint64_t blknum)
1108 uint64_t x = ((uint64_t) blknum) ^ (seq << 32) ^ (seq >> 32);
1109 uint64_t *p = (uint64_t *) buf;
1110 int i;
1111 if (!seq) {
1112 bzero(buf, 512);
1113 return;
1115 for (i = 0; i < 512 / sizeof(uint64_t); i++) {
1116 int s;
1117 *(p++) = x;
1118 x += 0xFEEDA1ECDEADBEEFULL + i + (((uint64_t) i) << 56);
1119 s = x & 63;
1120 x = x ^ (x << s) ^ (x >> (64 - s)) ^ 0xAA55AA55AA55AA55ULL ^
1121 seq;
1125 static inline int checkbuf(char *buf, uint64_t seq, uint64_t blknum)
1127 uint64_t cmp[64]; // 512/8 = 64
1128 makebuf((char *)cmp, seq, blknum);
1129 return memcmp(cmp, buf, 512) ? -1 : 0;
1132 static inline void dumpcommand(char *text, uint32_t command)
1134 #ifdef DEBUG_COMMANDS
1135 command = ntohl(command);
1136 char *ctext;
1137 switch (command & NBD_CMD_MASK_COMMAND) {
1138 case NBD_CMD_READ:
1139 ctext = "NBD_CMD_READ";
1140 break;
1141 case NBD_CMD_WRITE:
1142 ctext = "NBD_CMD_WRITE";
1143 break;
1144 case NBD_CMD_DISC:
1145 ctext = "NBD_CMD_DISC";
1146 break;
1147 case NBD_CMD_FLUSH:
1148 ctext = "NBD_CMD_FLUSH";
1149 break;
1150 default:
1151 ctext = "UNKNOWN";
1152 break;
1154 printf("%s: %s [%s] (0x%08x)\n",
1155 text,
1156 ctext, (command & NBD_CMD_FLAG_FUA) ? "FUA" : "NONE", command);
1157 #endif
1160 /* return an unused handle */
1161 uint64_t getrandomhandle(GHashTable * phash)
1163 uint64_t handle = 0;
1164 int i;
1165 do {
1166 /* RAND_MAX may be as low as 2^15 */
1167 for (i = 1; i <= 5; i++)
1168 handle ^= random() ^ (handle << 15);
1169 } while (g_hash_table_lookup(phash, &handle));
1170 return handle;
1173 int integrity_test(gchar * hostname, gchar * unixsock, int port, char *name,
1174 int sock, char sock_is_open, char close_sock, int testflags)
1176 struct nbd_reply rep;
1177 fd_set rset;
1178 fd_set wset;
1179 struct timeval tv;
1180 struct timeval start;
1181 struct timeval stop;
1182 double timespan;
1183 double speed;
1184 char speedchar[2] = { '\0', '\0' };
1185 int retval = -1;
1186 int serverflags = 0;
1187 pid_t G_GNUC_UNUSED mypid = getpid();
1188 int blkhashfd = -1;
1189 char *blkhashname = NULL;
1190 struct blkitem *blkhash = NULL;
1191 int logfd = -1;
1192 uint64_t seq = 1;
1193 uint64_t processed = 0;
1194 uint64_t printer = 0;
1195 char *do_print = getenv("NBD_TEST_SILENT");
1196 uint64_t xfer = 0;
1197 int readtransactionfile = 1;
1198 int blocked = 0;
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);
1205 size = 0;
1206 if (!sock_is_open) {
1207 if ((sock =
1208 setup_connection(hostname, unixsock, port, name,
1209 CONNECTION_TYPE_FULL,
1210 &serverflags, testflags)) < 0) {
1211 g_warning("Could not open socket: %s", errstr);
1212 goto err;
1216 if ((serverflags & (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))
1217 != (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))
1218 g_warning
1219 ("Server flags do not support FLUSH and FUA - these may error");
1221 #ifdef HAVE_MKSTEMP
1222 blkhashname = strdup("/tmp/blkarray-XXXXXX");
1223 if (!blkhashname || (-1 == (blkhashfd = mkstemp(blkhashname)))) {
1224 g_warning("Could not open temp file: %s", strerror(errno));
1225 goto err;
1227 #else
1228 /* use tmpnam here to avoid further feature test nightmare */
1229 if (-1 == (blkhashfd = open(blkhashname = strdup(tmpnam(NULL)),
1230 O_CREAT | O_RDWR,
1231 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
1232 g_warning("Could not open temp file: %s", strerror(errno));
1233 goto err;
1235 #endif
1236 /* Ensure space freed if we die */
1237 if (-1 == unlink(blkhashname)) {
1238 g_warning("Could not unlink temp file: %s", strerror(errno));
1239 goto err;
1242 if (-1 ==
1243 lseek(blkhashfd, (off_t) ((size >> 9) * sizeof(struct blkitem)),
1244 SEEK_SET)) {
1245 g_warning("Could not llseek temp file: %s", strerror(errno));
1246 goto err;
1249 if (-1 == write(blkhashfd, "\0", 1)) {
1250 g_warning("Could not write temp file: %s", strerror(errno));
1251 goto err;
1254 if (NULL == (blkhash = mmap(NULL,
1255 (size >> 9) * sizeof(struct blkitem),
1256 PROT_READ | PROT_WRITE,
1257 MAP_SHARED, blkhashfd, 0))) {
1258 g_warning("Could not mmap temp file: %s", strerror(errno));
1259 goto err;
1262 if (-1 == (logfd = open(transactionlog, O_RDONLY))) {
1263 g_warning("Could open log file: %s", strerror(errno));
1264 goto err;
1267 if (gettimeofday(&start, NULL) < 0) {
1268 snprintf(errstr, errstr_len, "Could not measure start time: %s",
1269 strerror(errno));
1270 goto err_open;
1273 while (readtransactionfile || txqueue.numitems || txbuf.numitems
1274 || inflight.numitems) {
1275 int ret;
1277 uint32_t magic;
1278 uint32_t command;
1279 uint64_t from;
1280 uint32_t len;
1281 struct reqcontext *prc;
1283 *errstr = 0;
1285 FD_ZERO(&wset);
1286 FD_ZERO(&rset);
1287 if (readtransactionfile)
1288 FD_SET(logfd, &rset);
1289 if ((!blocked && txqueue.numitems) || txbuf.numitems)
1290 FD_SET(sock, &wset);
1291 if (inflight.numitems)
1292 FD_SET(sock, &rset);
1293 tv.tv_sec = 5;
1294 tv.tv_usec = 0;
1295 ret =
1296 select(1 + ((sock > logfd) ? sock : logfd), &rset, &wset,
1297 NULL, &tv);
1298 if (ret == 0) {
1299 snprintf(errstr, errstr_len,
1300 "Timeout reading from socket");
1301 goto err_open;
1302 } else if (ret < 0) {
1303 g_warning("Could not mmap temp file: %s", errstr);
1304 goto err;
1306 /* We know we've got at least one thing to do here then */
1308 /* Get a command from the transaction log */
1309 if (FD_ISSET(logfd, &rset)) {
1311 /* Read a request or reply from the transaction file */
1312 READ_ALL_ERRCHK(logfd,
1313 &magic,
1314 sizeof(magic),
1315 err_open,
1316 "Could not read transaction log: %s",
1317 strerror(errno));
1318 magic = ntohl(magic);
1319 switch (magic) {
1320 case NBD_REQUEST_MAGIC:
1321 if (NULL ==
1322 (prc =
1323 calloc(1, sizeof(struct reqcontext)))) {
1324 snprintf(errstr, errstr_len,
1325 "Could not allocate request");
1326 goto err_open;
1328 READ_ALL_ERRCHK(logfd,
1329 sizeof(magic) +
1330 (char *)&(prc->req),
1331 sizeof(struct nbd_request) -
1332 sizeof(magic), err_open,
1333 "Could not read transaction log: %s",
1334 strerror(errno));
1335 prc->req.magic = htonl(NBD_REQUEST_MAGIC);
1336 memcpy(prc->orighandle, prc->req.handle, 8);
1337 prc->seq = seq++;
1338 if ((ntohl(prc->req.type) &
1339 NBD_CMD_MASK_COMMAND) == NBD_CMD_DISC) {
1340 /* no more to read; don't enqueue as no reply
1341 * we will disconnect manually at the end
1343 readtransactionfile = 0;
1344 free(prc);
1345 } else {
1346 dumpcommand("Enqueuing command",
1347 prc->req.type);
1348 rclist_addtail(&txqueue, prc);
1350 prc = NULL;
1351 break;
1352 case NBD_REPLY_MAGIC:
1353 READ_ALL_ERRCHK(logfd,
1354 sizeof(magic) + (char *)(&rep),
1355 sizeof(struct nbd_reply) -
1356 sizeof(magic), err_open,
1357 "Could not read transaction log: %s",
1358 strerror(errno));
1360 if (rep.error) {
1361 snprintf(errstr, errstr_len,
1362 "Transaction log file contained errored transaction");
1363 goto err_open;
1366 /* We do not need to consume data on a read reply as there is
1367 * none in the log */
1368 break;
1369 default:
1370 snprintf(errstr, errstr_len,
1371 "Could not measure start time: %08x",
1372 magic);
1373 goto err_open;
1377 /* See if we have a write we can do */
1378 if (FD_ISSET(sock, &wset)) {
1379 if ((!(txqueue.head) && !(txbuf.head)) || blocked)
1380 g_warning
1381 ("Socket write FD set but we shouldn't have been interested");
1383 /* If there is no buffered data, generate some */
1384 if (!blocked && !(txbuf.head)
1385 && (NULL != (prc = txqueue.head))) {
1386 if (ntohl(prc->req.magic) != NBD_REQUEST_MAGIC) {
1387 g_warning
1388 ("Asked to write a request without a magic number");
1389 goto err_open;
1392 command = ntohl(prc->req.type);
1393 from = ntohll(prc->req.from);
1394 len = ntohl(prc->req.len);
1396 /* First check whether we can touch this command at all. If this
1397 * command is a read, and there is an inflight write, OR if this
1398 * command is a write, and there is an inflight read or write, then
1399 * we need to leave the command alone and signal that we are blocked
1402 if (!looseordering) {
1403 uint64_t cfrom;
1404 uint32_t clen;
1405 cfrom = from;
1406 clen = len;
1407 while (clen > 0) {
1408 uint64_t blknum = cfrom >> 9;
1409 if (cfrom >= size) {
1410 snprintf(errstr,
1411 errstr_len,
1412 "offset %llx beyond size %llx",
1413 (long long int)
1414 cfrom,
1415 (long long int)
1416 size);
1417 goto err_open;
1419 if (blkhash[blknum].inflightw ||
1420 (blkhash[blknum].inflightr
1422 ((command &
1423 NBD_CMD_MASK_COMMAND) ==
1424 NBD_CMD_WRITE))) {
1425 blocked = 1;
1426 break;
1428 cfrom += 512;
1429 clen -= 512;
1433 if (blocked)
1434 goto skipdequeue;
1436 rclist_unlink(&txqueue, prc);
1437 rclist_addtail(&inflight, prc);
1439 dumpcommand("Sending command", prc->req.type);
1440 /* we rewrite the handle as they otherwise may not be unique */
1441 *((uint64_t *) (prc->req.handle)) =
1442 getrandomhandle(handlehash);
1443 g_hash_table_insert(handlehash, prc->req.handle,
1444 prc);
1445 addbuffer(&txbuf, &(prc->req),
1446 sizeof(struct nbd_request));
1447 switch (command & NBD_CMD_MASK_COMMAND) {
1448 case NBD_CMD_WRITE:
1449 xfer += len;
1450 while (len > 0) {
1451 uint64_t blknum = from >> 9;
1452 char dbuf[512];
1453 if (from >= size) {
1454 snprintf(errstr,
1455 errstr_len,
1456 "offset %llx beyond size %llx",
1457 (long long int)
1458 from,
1459 (long long int)
1460 size);
1461 goto err_open;
1463 (blkhash[blknum].inflightw)++;
1464 /* work out what we should be writing */
1465 makebuf(dbuf, prc->seq, blknum);
1466 addbuffer(&txbuf, dbuf, 512);
1467 from += 512;
1468 len -= 512;
1470 break;
1471 case NBD_CMD_READ:
1472 xfer += len;
1473 while (len > 0) {
1474 uint64_t blknum = from >> 9;
1475 if (from >= size) {
1476 snprintf(errstr,
1477 errstr_len,
1478 "offset %llx beyond size %llx",
1479 (long long int)
1480 from,
1481 (long long int)
1482 size);
1483 goto err_open;
1485 (blkhash[blknum].inflightr)++;
1486 from += 512;
1487 len -= 512;
1489 break;
1490 case NBD_CMD_DISC:
1491 case NBD_CMD_FLUSH:
1492 break;
1493 default:
1494 snprintf(errstr, errstr_len,
1495 "Incomprehensible command: %08x",
1496 command);
1497 goto err_open;
1498 break;
1501 prc = NULL;
1503 skipdequeue:
1505 /* there should be some now */
1506 if (writebuffer(sock, &txbuf) < 0) {
1507 snprintf(errstr, errstr_len,
1508 "Failed to write to socket buffer: %s",
1509 strerror(errno));
1510 goto err_open;
1515 /* See if there is a reply to be processed from the socket */
1516 if (FD_ISSET(sock, &rset)) {
1517 /* Okay, there's something ready for
1518 * reading here */
1520 READ_ALL_ERRCHK(sock,
1521 &rep,
1522 sizeof(struct nbd_reply),
1523 err_open,
1524 "Could not read from server socket: %s",
1525 strerror(errno));
1527 if (rep.magic != htonl(NBD_REPLY_MAGIC)) {
1528 snprintf(errstr, errstr_len,
1529 "Bad magic from server");
1530 goto err_open;
1533 if (rep.error) {
1534 snprintf(errstr, errstr_len,
1535 "Server errored a transaction");
1536 goto err_open;
1539 uint64_t handle;
1540 memcpy(&handle, rep.handle, 8);
1541 prc = g_hash_table_lookup(handlehash, &handle);
1542 if (!prc) {
1543 snprintf(errstr, errstr_len,
1544 "Unrecognised handle in reply: 0x%llX",
1545 *(long long unsigned int *)(rep.
1546 handle));
1547 goto err_open;
1549 if (!g_hash_table_remove(handlehash, &handle)) {
1550 snprintf(errstr, errstr_len,
1551 "Could not remove handle from hash: 0x%llX",
1552 *(long long unsigned int *)(rep.
1553 handle));
1554 goto err_open;
1557 if (prc->req.magic != htonl(NBD_REQUEST_MAGIC)) {
1558 snprintf(errstr, errstr_len,
1559 "Bad magic in inflight data: %08x",
1560 prc->req.magic);
1561 goto err_open;
1564 dumpcommand("Processing reply to command",
1565 prc->req.type);
1566 command = ntohl(prc->req.type);
1567 from = ntohll(prc->req.from);
1568 len = ntohl(prc->req.len);
1570 switch (command & NBD_CMD_MASK_COMMAND) {
1571 case NBD_CMD_READ:
1572 while (len > 0) {
1573 uint64_t blknum = from >> 9;
1574 char dbuf[512];
1575 if (from >= size) {
1576 snprintf(errstr, errstr_len,
1577 "offset %llx beyond size %llx",
1578 (long long int)from,
1579 (long long int)size);
1580 goto err_open;
1582 READ_ALL_ERRCHK(sock,
1583 dbuf,
1584 512,
1585 err_open,
1586 "Could not read data: %s",
1587 strerror(errno));
1588 if (--(blkhash[blknum].inflightr) < 0) {
1589 snprintf(errstr, errstr_len,
1590 "Received a read reply for offset %llx when not in flight",
1591 (long long int)from);
1592 goto err_open;
1594 /* work out what we was written */
1595 if (checkbuf
1596 (dbuf, blkhash[blknum].seq,
1597 blknum)) {
1598 snprintf(errstr, errstr_len,
1599 "Bad reply data: I wanted blk %08x, seq %08x but I got (at a guess) blk %08x, seq %08x",
1600 (unsigned int)blknum,
1601 blkhash[blknum].seq,
1602 ((uint32_t
1603 *) (dbuf))[0],
1604 ((uint32_t
1605 *) (dbuf))[1]
1607 goto err_open;
1610 from += 512;
1611 len -= 512;
1613 break;
1614 case NBD_CMD_WRITE:
1615 /* subsequent reads should get data with this seq */
1616 while (len > 0) {
1617 uint64_t blknum = from >> 9;
1618 if (--(blkhash[blknum].inflightw) < 0) {
1619 snprintf(errstr, errstr_len,
1620 "Received a write reply for offset %llx when not in flight",
1621 (long long int)from);
1622 goto err_open;
1624 blkhash[blknum].seq =
1625 (uint32_t) (prc->seq);
1626 from += 512;
1627 len -= 512;
1629 break;
1630 default:
1631 break;
1633 blocked = 0;
1634 processed++;
1635 rclist_unlink(&inflight, prc);
1636 prc->req.magic = 0; /* so a duplicate reply is detected */
1637 free(prc);
1640 if ((do_print == NULL && !(printer++ % 5000))
1641 || !(readtransactionfile || txqueue.numitems
1642 || inflight.numitems))
1643 printf
1644 ("%d: Seq %08lld Queued: %08d Inflight: %08d Done: %08lld\r",
1645 (int)mypid, (long long int)seq, txqueue.numitems,
1646 inflight.numitems, (long long int)processed);
1650 printf("\n");
1652 if (gettimeofday(&stop, NULL) < 0) {
1653 snprintf(errstr, errstr_len, "Could not measure end time: %s",
1654 strerror(errno));
1655 goto err_open;
1657 timespan = timeval_diff_to_double(&stop, &start);
1658 speed = xfer / timespan;
1659 if (speed > 1024) {
1660 speed = speed / 1024.0;
1661 speedchar[0] = 'K';
1663 if (speed > 1024) {
1664 speed = speed / 1024.0;
1665 speedchar[0] = 'M';
1667 if (speed > 1024) {
1668 speed = speed / 1024.0;
1669 speedchar[0] = 'G';
1671 g_message
1672 ("%d: Integrity %s test complete. Took %.3f seconds to complete, %.3f%sib/s",
1673 (int)getpid(), (testflags & TEST_WRITE) ? "write" : "read",
1674 timespan, speed, speedchar);
1676 retval = 0;
1678 err_open:
1679 if (close_sock) {
1680 close_connection(sock, CONNECTION_CLOSE_PROPERLY);
1682 err:
1683 if (size && blkhash)
1684 munmap(blkhash, (size >> 9) * sizeof(struct blkitem));
1686 if (blkhashfd != -1)
1687 close(blkhashfd);
1689 if (logfd != -1)
1690 close(logfd);
1692 if (blkhashname)
1693 free(blkhashname);
1695 if (*errstr)
1696 g_warning("%s", errstr);
1698 g_hash_table_destroy(handlehash);
1700 return retval;
1703 void handle_nonopt(char *opt, gchar ** hostname, long int *p)
1705 static int nonopt = 0;
1707 switch (nonopt) {
1708 case 0:
1709 *hostname = g_strdup(opt);
1710 nonopt++;
1711 break;
1712 case 1:
1713 *p = (strtol(opt, NULL, 0));
1714 if (*p == LONG_MIN || *p == LONG_MAX) {
1715 g_critical("Could not parse port number: %s",
1716 strerror(errno));
1717 exit(EXIT_FAILURE);
1719 break;
1723 typedef int (*testfunc) (gchar *, gchar *, int, char *, int, char, char, int);
1725 int main(int argc, char **argv)
1727 gchar *hostname = NULL, *unixsock = NULL;
1728 long int p = 0;
1729 char *name = NULL;
1730 int sock = 0;
1731 int c;
1732 int testflags = 0;
1733 testfunc test = throughput_test;
1735 #if HAVE_GNUTLS
1736 tlssession_init();
1737 #endif
1739 /* Ignore SIGPIPE as we want to pick up the error from write() */
1740 signal(SIGPIPE, SIG_IGN);
1742 errstr[errstr_len] = '\0';
1744 if (argc < 3) {
1745 g_message("%d: Not enough arguments", (int)getpid());
1746 g_message("%d: Usage: %s <hostname> <port>", (int)getpid(),
1747 argv[0]);
1748 g_message("%d: Or: %s <hostname> -N <exportname> [<port>]",
1749 (int)getpid(), argv[0]);
1750 g_message("%d: Or: %s -u <unix socket> -N <exportname>",
1751 (int)getpid(), argv[0]);
1752 exit(EXIT_FAILURE);
1754 logging(MY_NAME);
1755 while ((c = getopt(argc, argv, "FN:t:owfilu:hC:K:A:H:")) >= 0) {
1756 switch (c) {
1757 case 1:
1758 handle_nonopt(optarg, &hostname, &p);
1759 break;
1760 case 'N':
1761 name = g_strdup(optarg);
1762 if (!p) {
1763 p = 10809;
1765 break;
1766 case 'F':
1767 testflags |= TEST_EXPECT_ERROR;
1768 break;
1769 case 't':
1770 transactionlog = g_strdup(optarg);
1771 break;
1772 case 'o':
1773 test = oversize_test;
1774 break;
1775 case 'l':
1776 looseordering = 1;
1777 break;
1778 case 'w':
1779 testflags |= TEST_WRITE;
1780 break;
1781 case 'f':
1782 testflags |= TEST_FLUSH;
1783 break;
1784 case 'i':
1785 test = integrity_test;
1786 break;
1787 case 'u':
1788 unixsock = g_strdup(optarg);
1789 break;
1790 case 'h':
1791 test = handshake_test;
1792 testflags |= TEST_HANDSHAKE;
1793 break;
1794 #if HAVE_GNUTLS
1795 case 'C':
1796 certfile=g_strdup(optarg);
1797 break;
1798 case 'K':
1799 keyfile=g_strdup(optarg);
1800 break;
1801 case 'A':
1802 cacertfile=g_strdup(optarg);
1803 break;
1804 case 'H':
1805 tlshostname=g_strdup(optarg);
1806 break;
1807 #else
1808 case 'C':
1809 case 'K':
1810 case 'H':
1811 case 'A':
1812 g_warning("TLS support not compiled in");
1813 /* Do not change this - looked for by test suite */
1814 exit(77);
1815 #endif
1819 while (optind < argc) {
1820 handle_nonopt(argv[optind++], &hostname, &p);
1823 if (keyfile && !certfile)
1824 certfile = g_strdup(keyfile);
1826 if (!tlshostname && hostname)
1827 tlshostname = g_strdup(hostname);
1829 if (test(hostname, unixsock, (int)p, name, sock, FALSE, TRUE, testflags)
1830 < 0) {
1831 g_warning("Could not run test: %s", errstr);
1832 exit(EXIT_FAILURE);
1835 return 0;