int setup_inet_connection(gchar *hostname, int port, gchar* name, CONNECTION_TYPE ctype, int* serverflags) { int sock; struct hostent *host; struct sockaddr_in addr; sock=0; if(ctype<CONNECTION_TYPE_CONNECT) goto end; if((sock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0) { strncpy(errstr, strerror(errno), errstr_len); goto err; } setmysockopt(sock); if(!(host=gethostbyname(hostname))) { strncpy(errstr, hstrerror(h_errno), errstr_len); goto err_open; } addr.sin_family=AF_INET; addr.sin_port=htons(port); addr.sin_addr.s_addr=*((int *) host->h_addr); if((connect(sock, (struct sockaddr *)&addr, sizeof(addr))<0)) { strncpy(errstr, strerror(errno), errstr_len); goto err_open; } sock=setup_connection_common(sock, name, ctype, serverflags); goto end; err_open: close(sock); err: sock=-1; end: return sock; }
int setup_unix_connection(gchar* unixsock, gchar* name, CONNECTION_TYPE ctype, int* serverflags) { struct sockaddr_un addr; int sock; sock = 0; if(ctype<CONNECTION_TYPE_CONNECT) { goto end; } if((sock=socket(AF_UNIX, SOCK_STREAM, 0))<0) { strncpy(errstr, strerror(errno), errstr_len); goto err; } setmysockopt(sock); memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, unixsock, 107); if(connect(sock, (struct sockaddr*)&addr, sizeof(addr))<0) { strncpy(errstr, strerror(errno), errstr_len); goto err_open; } sock = setup_connection_common(sock, name, ctype, serverflags); goto end; err_open: close(sock); err: sock=-1; end: return sock; }
int throughput_test(char *name, int sock, char close_sock, int testflags) { long long int i; char writebuf[1024]; struct nbd_request req; int requests = 0; fd_set set; struct timeval tv; struct timeval start; struct timeval stop; double timespan; double speed; char speedchar[2] = { '\0', '\0' }; int retval = 0; int serverflags = 0; signed int do_write = TRUE; pid_t mypid = getpid(); char *print = getenv("NBD_TEST_SILENT"); if (!(testflags & TEST_WRITE)) testflags &= ~TEST_FLUSH; memset(writebuf, 'X', 1024); size = 0; if ((sock = setup_connection_common(sock, name, CONNECTION_TYPE_FULL, &serverflags, testflags)) < 0) { g_warning("Could not open socket: %s", errstr); if(testflags & TEST_EXPECT_ERROR) { g_message("Test failed, as expected"); retval = 0; } else { retval = -1; } goto err; } if ((testflags & TEST_FLUSH) && ((serverflags & (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA)) != (NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA))) { snprintf(errstr, errstr_len, "Server did not supply flush capability flags"); retval = -1; goto err_open; } req.magic = htonl(NBD_REQUEST_MAGIC); req.len = htonl(1024); if (gettimeofday(&start, NULL) < 0) { retval = -1; snprintf(errstr, errstr_len, "Could not measure start time: %s", strerror(errno)); goto err_open; } for (i = 0; i + 1024 <= size; i += 1024) { if (do_write) { int sendfua = (testflags & TEST_FLUSH) && (((i >> 10) & 15) == 3); int sendflush = (testflags & TEST_FLUSH) && (((i >> 10) & 15) == 11); req.type = htonl((testflags & TEST_WRITE) ? NBD_CMD_WRITE : NBD_CMD_READ); if (sendfua) req.type = htonl(NBD_CMD_WRITE | NBD_CMD_FLAG_FUA); memcpy(&(req.handle), &i, sizeof(i)); req.from = htonll(i); if (write_all(sock, &req, sizeof(req)) < 0) { retval = -1; goto err_open; } if (testflags & TEST_WRITE) { if (write_all(sock, writebuf, 1024) < 0) { retval = -1; goto err_open; } } ++requests; if (sendflush) { long long int j = i ^ (1LL << 63); req.type = htonl(NBD_CMD_FLUSH); memcpy(&(req.handle), &j, sizeof(j)); req.from = 0; req.len = 0; if (write_all(sock, &req, sizeof(req)) < 0) { retval = -1; goto err_open; } req.len = htonl(1024); ++requests; } } do { FD_ZERO(&set); FD_SET(sock, &set); tv.tv_sec = 0; tv.tv_usec = 0; select(sock + 1, &set, NULL, NULL, &tv); if (FD_ISSET(sock, &set)) { /* Okay, there's something ready for * reading here */ int rv; if ((rv = read_packet_check_header(sock, (testflags & TEST_WRITE) ? 0 : 1024, i)) < 0) { if (!(testflags & TEST_EXPECT_ERROR) || rv != -2) { retval = -1; } else { printf("\n"); } goto err_open; } else { if (testflags & TEST_EXPECT_ERROR) { retval = -1; goto err_open; } } --requests; } } while (FD_ISSET(sock, &set)); /* Now wait until we can write again or until a second have * passed, whichever comes first*/ FD_ZERO(&set); FD_SET(sock, &set); tv.tv_sec = 1; tv.tv_usec = 0; do_write = select(sock + 1, NULL, &set, NULL, &tv); if (!do_write) printf("Select finished\n"); if (do_write < 0) { snprintf(errstr, errstr_len, "select: %s", strerror(errno)); retval = -1; goto err_open; } if(print == NULL) { printf("%d: Requests: %d \r", (int)mypid, requests); } } /* Now empty the read buffer */ do { FD_ZERO(&set); FD_SET(sock, &set); tv.tv_sec = 0; tv.tv_usec = 0; select(sock + 1, &set, NULL, NULL, &tv); if (FD_ISSET(sock, &set)) { /* Okay, there's something ready for * reading here */ read_packet_check_header(sock, (testflags & TEST_WRITE) ? 0 : 1024, i); --requests; } if(print == NULL) { printf("%d: Requests: %d \r", (int)mypid, requests); } } while (requests); printf("%d: Requests: %d \n", (int)mypid, requests); if (gettimeofday(&stop, NULL) < 0) { retval = -1; snprintf(errstr, errstr_len, "Could not measure end time: %s", strerror(errno)); goto err_open; } timespan = timeval_diff_to_double(&stop, &start); speed = size / timespan; if (speed > 1024) { speed = speed / 1024.0; speedchar[0] = 'K'; } if (speed > 1024) { speed = speed / 1024.0; speedchar[0] = 'M'; } if (speed > 1024) { speed = speed / 1024.0; speedchar[0] = 'G'; } g_message ("%d: Throughput %s test (%s flushes) complete. Took %.3f seconds to complete, %.3f%sib/s", (int)getpid(), (testflags & TEST_WRITE) ? "write" : "read", (testflags & TEST_FLUSH) ? "with" : "without", timespan, speed, speedchar); err_open: if (close_sock) { close_connection(sock, CONNECTION_CLOSE_PROPERLY); } err: return retval; }
int handshake_test(char *name, int sock, char close_sock, int testflags) { int retval = -1; int serverflags = 0; u64 tmp64; uint32_t tmp32 = 0; /* This should work */ if ((sock = setup_connection_common(sock, name, CONNECTION_TYPE_FULL, &serverflags, testflags)) < 0) { g_warning("Could not open socket: %s", errstr); goto err; } /* Intentionally throw an unknown option at the server */ tmp64 = htonll(opts_magic); WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not write magic: %s", strerror(errno)); tmp32 = htonl(0x7654321); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option: %s", strerror(errno)); tmp32 = htonl((uint32_t) sizeof(tmp32)); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option length: %s", strerror(errno)); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option payload: %s", strerror(errno)); /* Expect proper error from server */ READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not read magic: %s", strerror(errno)); tmp64 = ntohll(tmp64); if (tmp64 != 0x3e889045565a9LL) { strncpy(errstr, "magic does not match", errstr_len); goto err; } READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not read option: %s", strerror(errno)); tmp32 = ntohl(tmp32); if (tmp32 != 0x7654321) { strncpy(errstr, "option does not match", errstr_len); goto err; } READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not read status: %s", strerror(errno)); tmp32 = ntohl(tmp32); if (tmp32 != NBD_REP_ERR_UNSUP) { strncpy(errstr, "status does not match", errstr_len); goto err; } READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not read length: %s", strerror(errno)); tmp32 = ntohl(tmp32); while (tmp32) { char buf[1024]; size_t len = tmp32 < sizeof(buf) ? tmp32 : sizeof(buf); READ_ALL_ERRCHK(sock, buf, len, err, "Could not read payload: %s", strerror(errno)); tmp32 -= len; } /* Send NBD_OPT_ABORT to close the connection */ tmp64 = htonll(opts_magic); WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not write magic: %s", strerror(errno)); tmp32 = htonl(NBD_OPT_ABORT); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option: %s", strerror(errno)); tmp32 = htonl((uint32_t) 0); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option length: %s", strerror(errno)); retval = 0; g_message("Handshake test completed. No errors encountered."); err: return retval; }
int oversize_test(char *name, int sock, char close_sock, int testflags) { int retval = 0; struct nbd_request req; struct nbd_reply rep; int i = 0; int serverflags = 0; pid_t G_GNUC_UNUSED mypid = getpid(); char buf[((1024 * 1024) + sizeof(struct nbd_request) / 2) << 1]; bool got_err; /* This should work */ if ((sock = setup_connection_common(sock, name, CONNECTION_TYPE_FULL, &serverflags, testflags)) < 0) { g_warning("Could not open socket: %s", errstr); retval = -1; goto err; } req.magic = htonl(NBD_REQUEST_MAGIC); req.type = htonl(NBD_CMD_READ); req.len = htonl(1024 * 1024); memcpy(&(req.handle), &i, sizeof(i)); req.from = htonll(i); WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1, "Could not write request: %s", strerror(errno)); printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len)); READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1, "Could not read reply header: %s", strerror(errno)); READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1, "Could not read data: %s", strerror(errno)); if (rep.error) { snprintf(errstr, errstr_len, "Received unexpected error: %d", rep.error); retval = -1; goto err; } else { printf("OK\n"); } /* This probably should not work */ i++; req.from = htonll(i); req.len = htonl(ntohl(req.len) + sizeof(struct nbd_request) / 2); WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1, "Could not write request: %s", strerror(errno)); printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len)); READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1, "Could not read reply header: %s", strerror(errno)); READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1, "Could not read data: %s", strerror(errno)); if (rep.error) { printf("Received expected error\n"); got_err = true; } else { printf("OK\n"); got_err = false; } /* ... unless this works, too */ i++; req.from = htonll(i); req.len = htonl(ntohl(req.len) << 1); WRITE_ALL_ERR_RT(sock, &req, sizeof(req), err, -1, "Could not write request: %s", strerror(errno)); printf("%d: testing oversized request: %d: ", getpid(), ntohl(req.len)); READ_ALL_ERR_RT(sock, &rep, sizeof(struct nbd_reply), err, -1, "Could not read reply header: %s", strerror(errno)); READ_ALL_ERR_RT(sock, &buf, ntohl(req.len), err, -1, "Could not read data: %s", strerror(errno)); if (rep.error) { printf("error\n"); } else { printf("OK\n"); } if ((rep.error && !got_err) || (!rep.error && got_err)) { printf("Received unexpected error\n"); retval = -1; } err: return retval; }