int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize) { char buf[8 + 8 + 8 + 128]; uint64_t magic; TRACE("Receiving negotation."); if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { LOG("read failed"); errno = EINVAL; return -1; } magic = be64_to_cpup((uint64_t*)(buf + 8)); *size = be64_to_cpup((uint64_t*)(buf + 16)); *blocksize = 1024; TRACE("Magic is %c%c%c%c%c%c%c%c", qemu_isprint(buf[0]) ? buf[0] : '.', qemu_isprint(buf[1]) ? buf[1] : '.', qemu_isprint(buf[2]) ? buf[2] : '.', qemu_isprint(buf[3]) ? buf[3] : '.', qemu_isprint(buf[4]) ? buf[4] : '.', qemu_isprint(buf[5]) ? buf[5] : '.', qemu_isprint(buf[6]) ? buf[6] : '.', qemu_isprint(buf[7]) ? buf[7] : '.'); TRACE("Magic is 0x%" PRIx64, magic); TRACE("Size is %" PRIu64, *size); if (memcmp(buf, "NBDMAGIC", 8) != 0) { LOG("Invalid magic received"); errno = EINVAL; return -1; } TRACE("Checking magic"); if (magic != 0x00420281861253LL) { LOG("Bad magic received"); errno = EINVAL; return -1; } return 0; }
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, off_t *size, size_t *blocksize) { char buf[256]; uint64_t magic, s; uint16_t tmp; TRACE("Receiving negotation."); if (read_sync(csock, buf, 8) != 8) { LOG("read failed"); errno = EINVAL; return -1; } buf[8] = '\0'; if (strlen(buf) == 0) { LOG("server connection closed"); errno = EINVAL; return -1; } TRACE("Magic is %c%c%c%c%c%c%c%c", qemu_isprint(buf[0]) ? buf[0] : '.', qemu_isprint(buf[1]) ? buf[1] : '.', qemu_isprint(buf[2]) ? buf[2] : '.', qemu_isprint(buf[3]) ? buf[3] : '.', qemu_isprint(buf[4]) ? buf[4] : '.', qemu_isprint(buf[5]) ? buf[5] : '.', qemu_isprint(buf[6]) ? buf[6] : '.', qemu_isprint(buf[7]) ? buf[7] : '.'); if (memcmp(buf, "NBDMAGIC", 8) != 0) { LOG("Invalid magic received"); errno = EINVAL; return -1; } if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { LOG("read failed"); errno = EINVAL; return -1; } magic = be64_to_cpu(magic); TRACE("Magic is 0x%" PRIx64, magic); if (name) { uint32_t reserved = 0; uint32_t opt; uint32_t namesize; TRACE("Checking magic (opts_magic)"); if (magic != 0x49484156454F5054LL) { LOG("Bad magic received"); errno = EINVAL; return -1; } if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { LOG("flags read failed"); errno = EINVAL; return -1; } *flags = be16_to_cpu(tmp) << 16; /* reserved for future use */ if (write_sync(csock, &reserved, sizeof(reserved)) != sizeof(reserved)) { LOG("write failed (reserved)"); errno = EINVAL; return -1; } /* write the export name */ magic = cpu_to_be64(magic); if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { LOG("write failed (magic)"); errno = EINVAL; return -1; } opt = cpu_to_be32(NBD_OPT_EXPORT_NAME); if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) { LOG("write failed (opt)"); errno = EINVAL; return -1; } namesize = cpu_to_be32(strlen(name)); if (write_sync(csock, &namesize, sizeof(namesize)) != sizeof(namesize)) { LOG("write failed (namesize)"); errno = EINVAL; return -1; } if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) { LOG("write failed (name)"); errno = EINVAL; return -1; } } else { TRACE("Checking magic (cli_magic)"); if (magic != 0x00420281861253LL) { LOG("Bad magic received"); errno = EINVAL; return -1; } } if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) { LOG("read failed"); errno = EINVAL; return -1; } *size = be64_to_cpu(s); *blocksize = 1024; TRACE("Size is %" PRIu64, *size); if (!name) { if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) { LOG("read failed (flags)"); errno = EINVAL; return -1; } *flags = be32_to_cpup(flags); } else { if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { LOG("read failed (tmp)"); errno = EINVAL; return -1; } *flags |= be32_to_cpu(tmp); } if (read_sync(csock, &buf, 124) != 124) { LOG("read failed (buf)"); errno = EINVAL; return -1; } return 0; }
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, off_t *size, Error **errp) { char buf[256]; uint64_t magic, s; uint16_t tmp; int rc; TRACE("Receiving negotiation."); rc = -EINVAL; if (read_sync(csock, buf, 8) != 8) { error_setg(errp, "Failed to read data"); goto fail; } buf[8] = '\0'; if (strlen(buf) == 0) { error_setg(errp, "Server connection closed unexpectedly"); goto fail; } TRACE("Magic is %c%c%c%c%c%c%c%c", qemu_isprint(buf[0]) ? buf[0] : '.', qemu_isprint(buf[1]) ? buf[1] : '.', qemu_isprint(buf[2]) ? buf[2] : '.', qemu_isprint(buf[3]) ? buf[3] : '.', qemu_isprint(buf[4]) ? buf[4] : '.', qemu_isprint(buf[5]) ? buf[5] : '.', qemu_isprint(buf[6]) ? buf[6] : '.', qemu_isprint(buf[7]) ? buf[7] : '.'); if (memcmp(buf, "NBDMAGIC", 8) != 0) { error_setg(errp, "Invalid magic received"); goto fail; } if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { error_setg(errp, "Failed to read magic"); goto fail; } magic = be64_to_cpu(magic); TRACE("Magic is 0x%" PRIx64, magic); if (name) { uint32_t reserved = 0; uint32_t opt; uint32_t namesize; TRACE("Checking magic (opts_magic)"); if (magic != NBD_OPTS_MAGIC) { if (magic == NBD_CLIENT_MAGIC) { error_setg(errp, "Server does not support export names"); } else { error_setg(errp, "Bad magic received"); } goto fail; } if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { error_setg(errp, "Failed to read server flags"); goto fail; } *flags = be16_to_cpu(tmp) << 16; /* reserved for future use */ if (write_sync(csock, &reserved, sizeof(reserved)) != sizeof(reserved)) { error_setg(errp, "Failed to read reserved field"); goto fail; } /* write the export name */ magic = cpu_to_be64(magic); if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { error_setg(errp, "Failed to send export name magic"); goto fail; } opt = cpu_to_be32(NBD_OPT_EXPORT_NAME); if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) { error_setg(errp, "Failed to send export name option number"); goto fail; } namesize = cpu_to_be32(strlen(name)); if (write_sync(csock, &namesize, sizeof(namesize)) != sizeof(namesize)) { error_setg(errp, "Failed to send export name length"); goto fail; } if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) { error_setg(errp, "Failed to send export name"); goto fail; } } else { TRACE("Checking magic (cli_magic)"); if (magic != NBD_CLIENT_MAGIC) { if (magic == NBD_OPTS_MAGIC) { error_setg(errp, "Server requires an export name"); } else { error_setg(errp, "Bad magic received"); } goto fail; } } if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) { error_setg(errp, "Failed to read export length"); goto fail; } *size = be64_to_cpu(s); TRACE("Size is %" PRIu64, *size); if (!name) { if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) { error_setg(errp, "Failed to read export flags"); goto fail; } *flags = be32_to_cpup(flags); } else { if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { error_setg(errp, "Failed to read export flags"); goto fail; } *flags |= be16_to_cpu(tmp); } if (read_sync(csock, &buf, 124) != 124) { error_setg(errp, "Failed to read reserved block"); goto fail; } rc = 0; fail: return rc; }