2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
28 #include <sys/types.h>
30 #elif defined(WIN32) && !defined(__CYGWIN__)
37 #define DEFAULT_LOG_FILE "./status.log"
38 #define DEFAULT_CONF_FILE "v3_nbd.ini"
41 #define DEFAULT_PORT 9500
42 #define MAX_STRING_SIZE 1024
45 #define LOGFILE_TAG "logfile"
46 #define PORT_TAG "port"
47 #define DISKS_TAG "disks"
49 // Turn on 64 bit file offset support (see 'man fseeko')
50 #define _FILE_OFFSET_BITS 64
54 //using namespace __gnu_cxx;
57 typedef enum {INVALID, ISO, RAW} disk_type_t;
70 bool operator()(const SOCK sock1, const SOCK sock2) const {
71 return sock1 == sock2;
76 // Server Port that we'll listen on
79 // List of disks being served
80 // eqstr from vtl (config.h)
81 map<const string, struct disk_info *, eqstr> disks;
84 // List of open connections
85 map<SOCK, struct disk_info *, eqsock> conns;
88 static const int enable_debug = 1;
92 int config_nbd(string conf_file_name);
93 int serv_loop(int serv_sock);
94 void setup_disk(string disk_tag, config_t &config_map);
97 int __main (int argc, char ** argv);
99 disk_type_t get_disk_type(const string type_str) {
101 if (type_str == "ISO") {
103 } else if (type_str == "RAW") {
113 int main(int argc, char ** argv) {
114 return __main(argc, argv);
125 int __main (int argc, char ** argv) {
134 config_file = string(argv[1]);
136 config_file = DEFAULT_CONF_FILE;
140 if (config_nbd(config_file) == -1) {
141 cerr << "Configuration Error" << endl;
145 // setup network sockets
146 serv_sock = CreateAndSetupTcpSocket();
148 if (serv_sock == -1) {
149 cerr << "Could not create server socket, exiting..." << endl;
153 if (BindSocket(serv_sock, server_port) == -1) {
154 cerr << "Could not bind socket to port: " << server_port << endl;
158 if (ListenSocket(serv_sock) == -1) {
159 cerr << "Could not listen on server socket (port=" << server_port << ")" << endl;
164 vtl_debug("Starting Server Loop\n");
165 serv_loop(serv_sock);
172 int serv_loop(int serv_sock) {
173 fd_set all_set, read_set;
175 RawEthernetPacket pkt;
178 FD_SET(serv_sock, &all_set);
185 nready = select(max_fd + 1, &read_set, NULL, NULL, NULL);
188 if (errno == EINTR) {
191 vtl_debug("Select returned error\n");
197 if (FD_ISSET(serv_sock, &read_set)) {
199 struct sockaddr_in rem_addr;
200 socklen_t addr_len = sizeof(struct sockaddr_in);
202 conn_socket = accept(serv_sock, (struct sockaddr *)&rem_addr, &addr_len);
204 if (conn_socket < 0) {
205 if (errno == EINTR) {
208 vtl_debug("Accept returned error\n");
222 int serv_loop(iface_t * iface, SOCK vnet_sock, struct vnet_config * vnet_info) {
224 RawEthernetPacket pkt;
225 WSANETWORKEVENTS net_events;
229 events[VNET_EVENT] = WSACreateEvent();
231 WSAEventSelect(vnet_sock, events[VNET_EVENT], FD_READ | FD_CLOSE);
232 events[IF_EVENT] = if_get_event(iface);
235 event_i = WSAWaitForMultipleEvents(2, events, false, WSA_INFINITE, false);
236 cout << "Wait returned" << endl;
238 if (event_i == WAIT_FAILED) {
239 cout << "ERROR: " << GetLastError() << endl;
242 event_i -= WAIT_OBJECT_0;
244 if (event_i == VNET_EVENT) {
246 if (WSAEnumNetworkEvents(vnet_sock, events[event_i], &net_events) == SOCKET_ERROR) {
247 cout << "EnumEventsError: " << WSAGetLastError() << endl;
250 if (net_events.lNetworkEvents & FD_READ) {
254 if (vnet_info->link_type == TCP_LINK) {
255 pkt.Unserialize(vnet_sock);
256 } else if (vnet_info->link_type == UDP_LINK) {
257 pkt.UdpUnserialize(vnet_sock);
260 process_outbound_pkt(&pkt);
262 if_write_pkt(iface, &pkt);
264 } else if (net_events.lNetworkEvents & FD_CLOSE) {
278 int config_nbd(string conf_file_name) {
281 if (read_config(conf_file_name, &config_map) != 0) {
282 cerr << "Could not read config file..." << endl;
286 if (config_map.count(PORT_TAG) > 0) {
287 server_port = atoi(config_map[PORT_TAG].c_str());
289 server_port = DEFAULT_PORT;
292 if (config_map.count(DISKS_TAG) > 0) {
293 istringstream disk_stream(config_map[DISKS_TAG], istringstream::in);
297 while (disk_stream >> disk_tag) {
299 if (i >= MAX_DISKS) {
300 cerr << "You specified too many disks, truncating..." << endl;
304 setup_disk(disk_tag, config_map);
308 cerr << "Must specify a set of disks" << endl;
312 if (config_map.count(LOGFILE_TAG) == 0) {
313 config_map[LOGFILE_TAG] = DEFAULT_LOG_FILE;
316 vtl_debug_init(config_map[LOGFILE_TAG], enable_debug);
321 void setup_disk(string disk_tag, config_t &config_map) {
322 string file_tag = disk_tag + ".file";
323 string type_tag = disk_tag + ".type";
324 struct disk_info * disk = (struct disk_info *)malloc(sizeof(struct disk_info));
326 cout << "Setting up " << disk_tag.c_str() << endl;
328 if ((config_map.count(file_tag) == 0) &&
329 (config_map.count(type_tag) == 0)) {
330 cerr << "Missing Disk configuration directive for " << disk_tag << endl;
333 disk->tag = disk_tag;
334 disk->filename = config_map[file_tag];
335 disk->type = get_disk_type(config_map[type_tag]);
337 if (disk->type == RAW) {
338 disk->disk_file = fopen(disk->filename.c_str(), "w+");
339 } else if (disk->type == ISO) {
340 disk->disk_file = fopen(disk->filename.c_str(), "r");
343 disks[disk->tag] = disk;
354 cout << "Usage: v3_nbd [config_file]" << endl;