Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


a6efa9f06effc145ef9b4d9a4eac7eafda08f1d2
[palacios.git] / misc / network_servers / v3_nbd / v3_nbd.cc
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
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.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <iostream>
22 #include <fstream>
23 #include <stdio.h>
24 #include <sstream>
25
26 #ifdef linux 
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #elif defined(WIN32) && !defined(__CYGWIN__)
31
32 #endif
33
34
35 #include "v3_nbd.h"
36
37 #define NBD_KEY "V3_NBD_1"
38
39
40 #define DEFAULT_LOG_FILE "./status.log"
41 #define DEFAULT_CONF_FILE "v3_nbd.ini"
42
43
44 #define DEFAULT_PORT 9500
45 #define MAX_STRING_SIZE 1024
46 #define MAX_DISKS 32
47
48 #define LOGFILE_TAG "logfile"
49 #define PORT_TAG  "port"
50 #define DISKS_TAG "disks"
51
52 // Turn on 64 bit file offset support (see 'man fseeko')
53 #define _FILE_OFFSET_BITS 64
54
55
56 using namespace std;
57 //using namespace __gnu_cxx;
58
59
60 struct eqsock {
61     bool operator()(const SOCK sock1, const SOCK sock2) const {
62         return sock1 == sock2;
63     }
64 };
65
66
67 // Server Port that we'll listen on
68 int server_port;
69
70 // List of disks being served 
71 // eqstr from vtl (config.h)
72 map<const string, struct disk_info *, eqstr> disks;
73
74 // List of open connections
75 map<SOCK, struct disk_info *, eqsock> conns;
76
77
78 // Enable Debugging
79 static const int enable_debug = 1;
80
81
82 void usage();
83 int config_nbd(string conf_file_name);
84 int serv_loop(int serv_sock);
85 void setup_disk(string disk_tag, config_t &config_map);
86
87 int handle_new_connection(SOCK new_conn);
88
89
90 int __main (int argc, char ** argv);
91
92
93
94 #ifdef linux
95
96 int main(int argc, char ** argv) {
97   return __main(argc, argv);
98 }
99
100 #elif WIN32
101
102 void main() {
103   __main(0, NULL);
104 }
105
106 #endif 
107
108 int __main (int argc, char ** argv) {
109   string config_file;
110   SOCK serv_sock;
111   if (argc > 2) {
112     usage();
113     exit(0);
114   }
115
116   if (argc == 2) {
117     config_file = string(argv[1]);
118   } else {
119     config_file = DEFAULT_CONF_FILE;
120   }
121
122  
123   if (config_nbd(config_file) == -1) {
124     cerr << "Configuration Error" << endl;
125     exit(-1);
126   }
127
128   // setup network sockets
129   serv_sock = CreateAndSetupTcpSocket();
130   
131   if (serv_sock == -1) {
132       cerr << "Could not create server socket, exiting..." << endl;
133       exit(-1);
134   }
135
136   if (BindSocket(serv_sock, server_port) == -1) {
137       cerr << "Could not bind socket to port: " << server_port << endl;
138       exit(-1);
139   }
140
141   if (ListenSocket(serv_sock) == -1) {
142       cerr << "Could not listen on server socket (port=" << server_port << ")" << endl;
143       exit(-1);
144   }
145
146
147   vtl_debug("Starting Server Loop\n");
148   serv_loop(serv_sock);
149
150   return 0;
151 }
152
153
154 #ifdef linux
155 int serv_loop(int serv_sock) {
156     fd_set all_set, read_set;
157     int max_fd = -1;
158     RawEthernetPacket pkt;
159
160
161     list<SOCK> pending_cons;
162
163     FD_ZERO(&all_set);
164     FD_SET(serv_sock, &all_set);
165     max_fd = serv_sock;
166
167
168     while (1) {
169         int nready = 0;
170         read_set = all_set;
171         write_set = all_set;
172         nready = select(max_fd + 1, &read_set, &write_set, NULL, NULL);
173     
174         if (nready == -1) {
175             if (errno == EINTR) {
176                 continue;
177             } else {
178                 vtl_debug("Select returned error\n");
179                 exit(-1);
180             }
181         }
182     
183
184         if (FD_ISSET(serv_sock, &read_set)) {
185             SOCK conn_socket;
186             struct sockaddr_in rem_addr;
187             socklen_t addr_len = sizeof(struct sockaddr_in);
188             // new connection
189             conn_socket = accept(serv_sock, (struct sockaddr *)&rem_addr, &addr_len);
190
191             if (conn_socket < 0) {
192                 if (errno == EINTR) {
193                     continue;
194                 } else {
195                     vtl_debug("Accept returned error\n");
196                     exit(-1);
197                 }
198             }
199
200             pending_cons.push_front(conn_socket);
201
202             FD_SET(conn_socket, &all_set);
203
204             if (conn_socket > max_fd) {
205                 max_fd = conn_socket;
206             }
207
208             if (--nready <= 0) continue;
209         }
210
211         // handle open connections
212
213
214         // check pending connections
215
216         for (list<SOCK>::iterator pending_iter = pending_cons.begin();
217              pending_iter != pending_cons.end();
218              pending_iter++) {
219             
220             if (handle_new_connection(pending_iter.value()) == -1) {
221                 // error
222             }
223             
224             pending_cons.remove(pending_iter);
225             
226             if (--nready <= 0) break;
227         }
228         
229         if (nready <= 0) continue;
230         
231
232
233     }
234
235     return 0;
236 }
237
238 #elif WIN32
239 int serv_loop(iface_t * iface, SOCK vnet_sock, struct vnet_config * vnet_info) {
240   int ret;
241   RawEthernetPacket pkt;
242   WSANETWORKEVENTS net_events;
243   WSAEVENT events[2];
244   DWORD event_i;
245   
246   events[VNET_EVENT] = WSACreateEvent();
247   
248   WSAEventSelect(vnet_sock, events[VNET_EVENT], FD_READ | FD_CLOSE);
249   events[IF_EVENT] = if_get_event(iface);
250   
251   while (1) {
252     event_i = WSAWaitForMultipleEvents(2, events, false, WSA_INFINITE, false);
253     cout << "Wait returned" << endl;
254     
255     if (event_i == WAIT_FAILED) {
256       cout << "ERROR: " <<   GetLastError() << endl;
257       exit(-1);
258     }
259     event_i -= WAIT_OBJECT_0;
260     
261     if (event_i == VNET_EVENT) {
262       
263       if (WSAEnumNetworkEvents(vnet_sock, events[event_i], &net_events) == SOCKET_ERROR) {
264         cout << "EnumEventsError: " << WSAGetLastError() << endl;
265         exit(-1);
266       }
267       if (net_events.lNetworkEvents & FD_READ) {
268         
269         // we received data
270         
271         if (vnet_info->link_type == TCP_LINK) {
272           pkt.Unserialize(vnet_sock);
273         } else if (vnet_info->link_type == UDP_LINK) {
274           pkt.UdpUnserialize(vnet_sock);
275         }
276         
277         process_outbound_pkt(&pkt);
278         
279         if_write_pkt(iface, &pkt);
280         
281       } else if (net_events.lNetworkEvents & FD_CLOSE) {
282         CLOSE(vnet_sock);
283         return 0;
284       }
285       
286     }
287   }
288   
289   return 0;
290 }
291 #endif
292
293
294
295
296 /* Negotiation:
297  * <NBD_KEY> <Disk Tag>\n
298  */
299
300 int handle_new_connection(SOCK new_conn) {
301     string input;
302     string key_str;
303     string tag_str;
304     struct disk_info * disk = NULL;
305
306     GetLine(new_conn, input);
307
308     {
309         istringstream is(input, istringstream::in);
310         is >> key_str >> tag_str;
311     }
312
313     if (key_str != NBD_KEY) {
314         vtl_debug("Error: Invalid NBD key string (%s)\n", key_str.c_str());
315         return -1;
316     }
317
318     if (disks[tag_str].count() == 0) {
319         vtl_debug("Error: Requesting disk that does not exist (%s)\n", tag_str.c_str());
320         return -1;
321     }
322
323     // Check if already assigned...
324     disk = disks[tag_str];
325
326     if (!disk) {
327         return -1;
328     }
329
330     conns[new_conn] = disk;
331
332     return 0;
333 }
334
335
336 int config_nbd(string conf_file_name) {
337     config_t config_map;
338     
339     if (read_config(conf_file_name, &config_map) != 0) {
340         cerr << "Could not read config file..." << endl;
341         return -1;
342     }
343
344     if (config_map.count(PORT_TAG) > 0) {
345         server_port = atoi(config_map[PORT_TAG].c_str());
346     } else {
347         server_port = DEFAULT_PORT;
348     }
349         
350     if (config_map.count(DISKS_TAG) > 0) {
351         istringstream disk_stream(config_map[DISKS_TAG], istringstream::in);
352         string disk_tag;
353         int i = 0;
354         
355         while (disk_stream >> disk_tag) {
356
357             if (i >= MAX_DISKS) {
358                 cerr << "You specified too many disks, truncating..." << endl;
359                 break;
360             }
361             
362             setup_disk(disk_tag, config_map);
363             i++;
364         }       
365     } else {
366         cerr << "Must specify a set of disks" << endl;
367         return -1;
368     }
369     
370     if (config_map.count(LOGFILE_TAG) == 0) {
371         config_map[LOGFILE_TAG] = DEFAULT_LOG_FILE;
372     }
373     
374     vtl_debug_init(config_map[LOGFILE_TAG], enable_debug);
375
376     return 0;
377 }
378
379 void setup_disk(string disk_tag, config_t &config_map) {
380     string file_tag = disk_tag +  ".file";
381     string type_tag = disk_tag + ".type";
382
383     string type;
384
385
386     cout << "Setting up " << disk_tag.c_str() << endl;
387
388     if ((config_map.count(file_tag) == 0) && 
389         (config_map.count(type_tag) == 0)) {
390         cerr << "Missing Disk configuration directive for " << disk_tag << endl;
391     }
392
393     type = config_map[type_tag];  
394
395     if (type == "RAW") {
396         disks[disk->tag] = new raw_disk(config_map[file_tag]);;
397     } else if (type == "ISO") {
398         
399     }
400
401
402
403
404     return;
405 }
406
407
408
409
410
411
412 void usage() {
413   cout << "Usage: v3_nbd [config_file]" << endl;
414   return;
415 }