X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=misc%2Fnetwork_servers%2Fv3_nbd%2Fv3_nbd.cc;h=b3eb805e084b645b0f41cf3ec1eae808c3b3d9b4;hb=dc41a5e6b7601dcdf9eb2ac84dbf297cac037f5b;hp=a6efa9f06effc145ef9b4d9a4eac7eafda08f1d2;hpb=7e8a39a13c99e8a04885ca3b6fafdfafb6078288;p=palacios.git diff --git a/misc/network_servers/v3_nbd/v3_nbd.cc b/misc/network_servers/v3_nbd/v3_nbd.cc index a6efa9f..b3eb805 100644 --- a/misc/network_servers/v3_nbd/v3_nbd.cc +++ b/misc/network_servers/v3_nbd/v3_nbd.cc @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef linux #include @@ -32,11 +33,21 @@ #endif -#include "v3_nbd.h" +#include "v3_disk.h" +#include "raw.h" +#include "iso.h" #define NBD_KEY "V3_NBD_1" +#define NBD_READ_CMD 0x1 +#define NBD_WRITE_CMD 0x2 +#define NBD_CAPACITY_CMD 0x3 + +#define NBD_STATUS_OK 0x00 +#define NBD_STATUS_ERR 0xff + + #define DEFAULT_LOG_FILE "./status.log" #define DEFAULT_CONF_FILE "v3_nbd.ini" @@ -69,10 +80,10 @@ int server_port; // List of disks being served // eqstr from vtl (config.h) -map disks; +map disks; // List of open connections -map conns; +map conns; // Enable Debugging @@ -85,7 +96,11 @@ int serv_loop(int serv_sock); void setup_disk(string disk_tag, config_t &config_map); int handle_new_connection(SOCK new_conn); +int handle_disk_request(SOCK conn, v3_disk * disk); +int handle_capacity_request(SOCK conn, v3_disk * disk); +int handle_read_request(SOCK conn, v3_disk * disk); +int handle_write_request(SOCK conn, v3_disk * disk); int __main (int argc, char ** argv); @@ -108,11 +123,19 @@ void main() { int __main (int argc, char ** argv) { string config_file; SOCK serv_sock; + + + if (argc > 2) { usage(); exit(0); } + // init global maps + disks.clear(); + conns.clear(); + + if (argc == 2) { config_file = string(argv[1]); } else { @@ -168,14 +191,14 @@ int serv_loop(int serv_sock) { while (1) { int nready = 0; read_set = all_set; - write_set = all_set; - nready = select(max_fd + 1, &read_set, &write_set, NULL, NULL); + nready = select(max_fd + 1, &read_set, NULL, NULL, NULL); if (nready == -1) { if (errno == EINTR) { continue; } else { vtl_debug("Select returned error\n"); + perror("Select returned error: "); exit(-1); } } @@ -188,6 +211,8 @@ int serv_loop(int serv_sock) { // new connection conn_socket = accept(serv_sock, (struct sockaddr *)&rem_addr, &addr_len); + vtl_debug("New Connection...\n"); + if (conn_socket < 0) { if (errno == EINTR) { continue; @@ -208,22 +233,57 @@ int serv_loop(int serv_sock) { if (--nready <= 0) continue; } + // handle open connections + for (map::iterator con_iter = conns.begin(); + con_iter != conns.end(); ) { + SOCK tmp_sock = con_iter->first; + v3_disk * tmp_disk = con_iter->second; + if (FD_ISSET(con_iter->first, &read_set)) { - // check pending connections + if (handle_disk_request(tmp_sock, tmp_disk) == -1) { + vtl_debug("Error: Could not complete disk request\n"); + + map::iterator tmp_iter = con_iter; + con_iter++; + + tmp_disk->detach(); + + + FD_CLR(tmp_sock, &all_set); + close(tmp_sock); + + conns.erase(tmp_iter); + } else { + con_iter++; + } + if (--nready <= 0) break; + } + } + + if (nready <= 0) continue; + + // check pending connections for (list::iterator pending_iter = pending_cons.begin(); - pending_iter != pending_cons.end(); - pending_iter++) { - - if (handle_new_connection(pending_iter.value()) == -1) { - // error - } + pending_iter != pending_cons.end();) { - pending_cons.remove(pending_iter); - - if (--nready <= 0) break; + if (FD_ISSET(*pending_iter, &read_set)) { + if (handle_new_connection(*pending_iter) == -1) { + // error + vtl_debug("Error: Could not connect to disk\n"); + FD_CLR(*pending_iter, &all_set); + } + list::iterator tmp_iter = pending_iter; + pending_iter++; + + pending_cons.erase(tmp_iter); + + if (--nready <= 0) break; + } else { + pending_iter++; + } } if (nready <= 0) continue; @@ -291,6 +351,192 @@ int serv_loop(iface_t * iface, SOCK vnet_sock, struct vnet_config * vnet_info) { #endif +// byte 1: command (read = 1, write = 2, capacity = 3) +// byte 2 - 4: zero +int handle_disk_request(SOCK conn, v3_disk * disk) { + char buf[4]; + + int read_len = Receive(conn, buf, 4, true); + + if (read_len == 0) { + vtl_debug("Detaching from disk (conn=%d)\n", conn); + return -1; + } + + if (read_len == -1) { + vtl_debug("Could not read command\n"); + return -1; + } + + if ((buf[1] != 0) || (buf[2] != 0) || (buf[3] != 0)) { + // error + vtl_debug("Invalid command padding\n"); + return -1; + } + + switch (buf[0]) { + case NBD_CAPACITY_CMD: + return handle_capacity_request(conn, disk); + case NBD_READ_CMD: + return handle_read_request(conn, disk); + case NBD_WRITE_CMD: + return handle_write_request(conn, disk); + default: + vtl_debug("Invalid Disk Command %d\n", buf[0]); + return -1; + } + + return 0; +} + + +// send: +// 8 bytes : capacity +int handle_capacity_request(SOCK conn, v3_disk * disk) { + off_t capacity = disk->get_capacity(); + + vtl_debug("Returing capacity %d\n", capacity); + + return Send(conn, (char *)&capacity, 8, true); +} + +// receive: +// 8 bytes : offset +// 4 bytes : length +// send: +// 1 byte : status +// 4 bytes : return length +// x bytes : data +int handle_read_request(SOCK conn, v3_disk * disk) { + off_t offset = 0; + unsigned int length = 0; + unsigned char * buf = NULL; + unsigned int ret_len = 0; + unsigned char status = NBD_STATUS_OK; + + vtl_debug("Read Request\n"); + + + + if (Receive(conn, (char *)&offset, 8, true) <= 0) { + vtl_debug("Error receiving read offset\n"); + return -1; + } + + vtl_debug("Read Offset %d\n", offset); + + if (Receive(conn, (char *)&length, 4, true) <= 0) { + vtl_debug("Error receiving read length\n"); + return -1; + } + + vtl_debug("Read length: %d\n", length); + + buf = new unsigned char[length]; + + ret_len = disk->read(buf, offset, length); + + vtl_debug("Read %d bytes from source disk\n", ret_len); + + if (ret_len == 0) { + vtl_debug("Read Error\n"); + status = NBD_STATUS_ERR; + } + + vtl_debug("Sending Status byte (%d)\n", status); + + if (Send(conn, (char *)&status, 1, true) <= 0) { + vtl_debug("Error Sending Read Status\n"); + return -1; + } + + vtl_debug("Sending Ret Len: %d\n", ret_len); + + if (Send(conn, (char *)&ret_len, 4, true) <= 0) { + vtl_debug("Error Sending Read Length\n"); + return -1; + } + + + + if (ret_len > 0) { + vtl_debug("Sending Data\n"); + + SetNoDelaySocket(conn, false); + + if (Send(conn, (char *)buf, ret_len, true) <= 0) { + vtl_debug("Error sending Read Data\n"); + return -1; + } + + SetNoDelaySocket(conn, true); + } + + vtl_debug("Read Complete\n"); + + delete buf; + + return 0; +} + +// receive: +// 8 bytes : offset +// 4 bytes : length +// x bytes : data +// send : +// 1 bytes : status +int handle_write_request(SOCK conn, v3_disk * disk) { + off_t offset = 0; + unsigned int length = 0; + unsigned char * buf = NULL; + unsigned int ret_len = 0; + unsigned char status = NBD_STATUS_OK; + + vtl_debug("Write Request\n"); + + if (Receive(conn, (char *)&offset, 8, true) <= 0) { + vtl_debug("Error receiving write offset\n"); + return -1; + } + + vtl_debug("Write Offset %d\n", offset); + + if (Receive(conn, (char *)&length, 4, true) <= 0) { + vtl_debug("Error receiving write length\n"); + return -1; + } + + vtl_debug("Write length: %d\n", length); + + buf = new unsigned char[length]; + + vtl_debug("Receiving Data\n"); + + if (Receive(conn, (char *)buf, length, true) <= 0) { + vtl_debug("Error receiving Write Data\n"); + return -1; + } + + vtl_debug("Wrote %d bytes to source disk\n", ret_len); + + if (disk->write(buf, offset, length) != length) { + vtl_debug("Write Error\n"); + status = NBD_STATUS_ERR; + } + + vtl_debug("Sending Status byte (%d)\n", status); + + if (Send(conn, (char *)&status, 1, true) <= 0) { + vtl_debug("Error Sending Wrte Status\n"); + return -1; + } + + vtl_debug("Write Complete\n"); + + delete buf; + + return 0; +} /* Negotiation: @@ -301,10 +547,12 @@ int handle_new_connection(SOCK new_conn) { string input; string key_str; string tag_str; - struct disk_info * disk = NULL; + v3_disk * disk = NULL; GetLine(new_conn, input); + vtl_debug("New Connection: %s\n", input.c_str()); + { istringstream is(input, istringstream::in); is >> key_str >> tag_str; @@ -315,20 +563,30 @@ int handle_new_connection(SOCK new_conn) { return -1; } - if (disks[tag_str].count() == 0) { + if (disks.count(tag_str) == 0) { vtl_debug("Error: Requesting disk that does not exist (%s)\n", tag_str.c_str()); return -1; } - // Check if already assigned... disk = disks[tag_str]; if (!disk) { + vtl_debug("Disk (%s) Does not exist\n", tag_str.c_str()); + return -1; + } + + if (disk->locked == 1) { + vtl_debug("Attempting to attach to a device already in use\n"); return -1; } conns[new_conn] = disk; + disk->attach(); + + + vtl_debug("Connected to disk %s\n", tag_str.c_str()); + return 0; } @@ -341,6 +599,13 @@ int config_nbd(string conf_file_name) { return -1; } + if (config_map.count(LOGFILE_TAG) == 0) { + config_map[LOGFILE_TAG] = DEFAULT_LOG_FILE; + } + + vtl_debug_init(config_map[LOGFILE_TAG], enable_debug); + + if (config_map.count(PORT_TAG) > 0) { server_port = atoi(config_map[PORT_TAG].c_str()); } else { @@ -367,11 +632,6 @@ int config_nbd(string conf_file_name) { return -1; } - if (config_map.count(LOGFILE_TAG) == 0) { - config_map[LOGFILE_TAG] = DEFAULT_LOG_FILE; - } - - vtl_debug_init(config_map[LOGFILE_TAG], enable_debug); return 0; } @@ -379,7 +639,8 @@ int config_nbd(string conf_file_name) { void setup_disk(string disk_tag, config_t &config_map) { string file_tag = disk_tag + ".file"; string type_tag = disk_tag + ".type"; - + + v3_disk * disk; string type; @@ -393,13 +654,13 @@ void setup_disk(string disk_tag, config_t &config_map) { type = config_map[type_tag]; if (type == "RAW") { - disks[disk->tag] = new raw_disk(config_map[file_tag]);; + disk = new raw_disk(config_map[file_tag]); } else if (type == "ISO") { - + vtl_debug("Setting up ISO\n"); + disk = new iso_image(config_map[file_tag]); } - - + disks[disk_tag] = disk; return; }