child-delete: Reply as usual when concurrently rekeying the IKE_SA
[strongswan.git] / src / dumm / main.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "dumm.h"
17
18 #include <collections/linked_list.h>
19
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include <sched.h>
23
24 #include <glib.h>
25 #include <gtk/gtk.h>
26 #include <vte/vte.h>
27 #include <vte/reaper.h>
28
29 /**
30 * notebook page with vte and guest
31 */
32 typedef struct {
33 gint num;
34 GtkWidget *vte;
35 guest_t *guest;
36 } page_t;
37
38 /**
39 * Main window
40 */
41 GtkWidget *window;
42
43 /**
44 * notebook with guests, vtes
45 */
46 GtkWidget *notebook;
47
48 /**
49 * dumm context
50 */
51 dumm_t *dumm;
52
53 /**
54 * pages in notebook, page_t
55 */
56 linked_list_t *pages;
57
58 /**
59 * handle guest termination, SIGCHILD
60 */
61 static void child_exited(VteReaper *vtereaper, gint pid, gint status)
62 {
63 enumerator_t *enumerator;
64 page_t *page;
65
66 enumerator = pages->create_enumerator(pages);
67 while (enumerator->enumerate(enumerator, (void**)&page))
68 {
69 if (page->guest->get_pid(page->guest) == pid)
70 {
71 page->guest->sigchild(page->guest);
72 vte_terminal_feed(VTE_TERMINAL(page->vte),
73 "\n\r--- guest terminated ---\n\r", -1);
74 break;
75 }
76 }
77 enumerator->destroy(enumerator);
78 }
79
80 static page_t* get_page(int num)
81 {
82 enumerator_t *enumerator;
83 page_t *page, *found = NULL;
84
85 enumerator = pages->create_enumerator(pages);
86 while (enumerator->enumerate(enumerator, (void**)&page))
87 {
88 if (page->num == num)
89 {
90 found = page;
91 break;
92 }
93 }
94 enumerator->destroy(enumerator);
95 return found;
96 }
97
98 /**
99 * Guest invocation callback
100 */
101 static pid_t invoke(void *vte, guest_t *guest,
102 char *args[], int argc)
103 {
104 GPid pid;
105
106 if (vte_terminal_fork_command_full(VTE_TERMINAL(vte),
107 VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP,
108 NULL, args, NULL,
109 G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_SEARCH_PATH,
110 NULL, NULL, &pid, NULL))
111 {
112 return pid;
113 }
114 return 0;
115 }
116
117 void idle(void)
118 {
119 gtk_main_iteration_do(FALSE);
120 sched_yield();
121 }
122
123 static void start_guest()
124 {
125 page_t *page;
126
127 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
128 if (page && page->guest->get_state(page->guest) == GUEST_STOPPED)
129 {
130 vte_terminal_feed(VTE_TERMINAL(page->vte),
131 "--- starting guest ---\n\r", -1);
132 page->guest->start(page->guest, invoke, VTE_TERMINAL(page->vte), idle);
133 }
134 }
135
136 static void start_all_guests()
137 {
138 enumerator_t *enumerator;
139 page_t *page;
140
141 enumerator = pages->create_enumerator(pages);
142 while (enumerator->enumerate(enumerator, (void**)&page))
143 {
144 if (page->guest->get_state(page->guest) == GUEST_STOPPED)
145 {
146 vte_terminal_feed(VTE_TERMINAL(page->vte),
147 "--- starting all guests ---\n\r", -1);
148 page->guest->start(page->guest, invoke,
149 VTE_TERMINAL(page->vte), idle);
150 }
151 }
152 enumerator->destroy(enumerator);
153 }
154
155 static void stop_guest()
156 {
157 page_t *page;
158
159 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
160 if (page && page->guest->get_state(page->guest) == GUEST_RUNNING)
161 {
162 page->guest->stop(page->guest, idle);
163 }
164 }
165
166 /**
167 * quit signal handler
168 */
169 static void quit()
170 {
171 enumerator_t *enumerator;
172 page_t *page;
173
174 dumm->load_template(dumm, NULL);
175
176 enumerator = pages->create_enumerator(pages);
177 while (enumerator->enumerate(enumerator, &page))
178 {
179 if (page->guest->get_state(page->guest) != GUEST_STOPPED)
180 {
181 page->guest->stop(page->guest, idle);
182 }
183 }
184 enumerator->destroy(enumerator);
185 gtk_main_quit();
186 }
187
188 static void error_dialog(char *msg)
189 {
190 GtkWidget *error;
191
192 error = gtk_message_dialog_new(GTK_WINDOW(window),
193 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
194 GTK_BUTTONS_CLOSE, msg);
195 gtk_dialog_run(GTK_DIALOG(error));
196 gtk_widget_destroy(error);
197 }
198
199 static void create_switch()
200 {
201 GtkWidget *dialog, *table, *label, *name;
202 bridge_t *bridge;
203
204 dialog = gtk_dialog_new_with_buttons("Create new switch", GTK_WINDOW(window),
205 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
206 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
207 GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
208
209 table = gtk_table_new(1, 2, TRUE);
210 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
211
212 label = gtk_label_new("Switch name");
213 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
214 gtk_widget_show(label);
215
216 name = gtk_entry_new();
217 gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
218 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
219 gtk_widget_show(name);
220
221 gtk_widget_show(table);
222
223 while (TRUE)
224 {
225 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
226 {
227 case GTK_RESPONSE_ACCEPT:
228 {
229 if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
230 {
231 continue;
232 }
233 bridge = dumm->create_bridge(dumm,
234 (char*)gtk_entry_get_text(GTK_ENTRY(name)));
235 if (!bridge)
236 {
237 error_dialog("creating bridge failed!");
238 continue;
239 }
240 break;
241 }
242 default:
243 break;
244 }
245 break;
246 }
247 gtk_widget_destroy(dialog);
248 }
249
250 static void delete_switch()
251 {
252
253 }
254
255 static void connect_guest()
256 {
257 page_t *page;
258 GtkWidget *dialog, *table, *label, *name, *box;
259 bridge_t *bridge;
260 iface_t *iface;
261 enumerator_t *enumerator;
262
263 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
264 if (!page || page->guest->get_state(page->guest) != GUEST_RUNNING)
265 {
266 return;
267 }
268
269 dialog = gtk_dialog_new_with_buttons("Connect guest", GTK_WINDOW(window),
270 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
271 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
272 GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
273
274 table = gtk_table_new(2, 2, TRUE);
275 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
276
277 label = gtk_label_new("Interface name");
278 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
279 gtk_widget_show(label);
280
281 name = gtk_entry_new();
282 gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
283 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
284 gtk_widget_show(name);
285
286 label = gtk_label_new("Connected switch");
287 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
288 gtk_widget_show(label);
289
290 box = gtk_combo_box_new_text();
291 gtk_table_attach(GTK_TABLE(table), box, 1, 2, 1, 2,
292 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
293 enumerator = dumm->create_bridge_enumerator(dumm);
294 while (enumerator->enumerate(enumerator, &bridge))
295 {
296 gtk_combo_box_append_text(GTK_COMBO_BOX(box), bridge->get_name(bridge));
297 }
298 enumerator->destroy(enumerator);
299 gtk_widget_show(box);
300
301 gtk_widget_show(table);
302
303 while (TRUE)
304 {
305 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
306 {
307 case GTK_RESPONSE_ACCEPT:
308 {
309 if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
310 {
311 continue;
312 }
313
314 iface = page->guest->create_iface(page->guest,
315 (char*)gtk_entry_get_text(GTK_ENTRY(name)));
316 if (!iface)
317 {
318 error_dialog("creating interface failed!");
319 continue;
320 }
321 enumerator = dumm->create_bridge_enumerator(dumm);
322 while (enumerator->enumerate(enumerator, &bridge))
323 {
324 if (!bridge->connect_iface(bridge, iface))
325 {
326 error_dialog("connecting interface failed!");
327 }
328 break;
329 }
330 enumerator->destroy(enumerator);
331 break;
332 }
333 default:
334 break;
335 }
336 break;
337 }
338 gtk_widget_destroy(dialog);
339 }
340
341 static void disconnect_guest()
342 {
343
344 }
345
346 static void delete_guest()
347 {
348 page_t *page;
349
350 page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
351 if (page)
352 {
353 page->guest->stop(page->guest, idle);
354 dumm->delete_guest(dumm, page->guest);
355 gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page->num);
356 pages->remove(pages, page, NULL);
357 g_free(page);
358 }
359 }
360
361 /**
362 * create a new page for a guest
363 */
364 static page_t* create_page(guest_t *guest)
365 {
366 GtkWidget *label;
367 page_t *page;
368
369 page = g_new(page_t, 1);
370 page->guest = guest;
371 page->vte = vte_terminal_new();
372 label = gtk_label_new(guest->get_name(guest));
373 page->num = gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
374 page->vte, label);
375 gtk_widget_show(page->vte);
376 pages->insert_last(pages, page);
377 return page;
378 }
379
380 /**
381 * create a new guest
382 */
383 static void create_guest()
384 {
385 guest_t *guest;
386 GtkWidget *dialog, *table, *label, *name, *kernel, *master, *args;
387
388 dialog = gtk_dialog_new_with_buttons("Create new guest", GTK_WINDOW(window),
389 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
390 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
391 GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
392
393 table = gtk_table_new(4, 2, TRUE);
394 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
395
396 label = gtk_label_new("Guest name");
397 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
398 gtk_widget_show(label);
399
400 label = gtk_label_new("UML kernel");
401 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
402 gtk_widget_show(label);
403
404 label = gtk_label_new("Master filesystem");
405 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 0, 0, 0, 0);
406 gtk_widget_show(label);
407
408 label = gtk_label_new("Kernel arguments");
409 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 0, 0);
410 gtk_widget_show(label);
411
412 name = gtk_entry_new();
413 gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
414 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
415 gtk_widget_show(name);
416
417 kernel = gtk_file_chooser_button_new("Select UML kernel image",
418 GTK_FILE_CHOOSER_ACTION_OPEN);
419 gtk_table_attach(GTK_TABLE(table), kernel, 1, 2, 1, 2,
420 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
421 gtk_widget_show(kernel);
422
423 master = gtk_file_chooser_button_new("Select master filesystem",
424 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
425 gtk_table_attach(GTK_TABLE(table), master, 1, 2, 2, 3,
426 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
427 gtk_widget_show(master);
428
429 args = gtk_entry_new();
430 gtk_table_attach(GTK_TABLE(table), args, 1, 2, 3, 4,
431 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
432 gtk_widget_show(args);
433
434 gtk_widget_show(table);
435
436 while (TRUE)
437 {
438 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
439 {
440 case GTK_RESPONSE_ACCEPT:
441 {
442 char *sname, *skernel, *smaster, *sargs;
443 page_t *page;
444
445 sname = (char*)gtk_entry_get_text(GTK_ENTRY(name));
446 skernel = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(kernel));
447 smaster = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(master));
448 sargs = (char*)gtk_entry_get_text(GTK_ENTRY(args));
449
450 if (!sname[0] || !skernel || !smaster)
451 {
452 continue;
453 }
454 guest = dumm->create_guest(dumm, sname, skernel, smaster, sargs);
455 if (!guest)
456 {
457 error_dialog("creating guest failed!");
458 continue;
459 }
460 page = create_page(guest);
461 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page->num);
462 break;
463 }
464 default:
465 break;
466 }
467 break;
468 }
469 gtk_widget_destroy(dialog);
470 }
471
472 /**
473 * main routine, parses args and reads from console
474 */
475 int main(int argc, char *argv[])
476 {
477 GtkWidget *menubar, *menu, *menuitem, *vbox;
478 GtkWidget *dummMenu, *guestMenu, *switchMenu;
479 enumerator_t *enumerator;
480 guest_t *guest;
481
482 library_init(NULL, "dumm");
483 gtk_init(&argc, &argv);
484
485 pages = linked_list_create();
486 dumm = dumm_create(NULL);
487
488 /* setup window */
489 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
490 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(quit), NULL);
491 gtk_window_set_title(GTK_WINDOW (window), "Dumm");
492 gtk_window_set_default_size(GTK_WINDOW (window), 1000, 500);
493 g_signal_connect(G_OBJECT(vte_reaper_get()), "child-exited",
494 G_CALLBACK(child_exited), NULL);
495
496 /* add vbox with menubar, notebook */
497 vbox = gtk_vbox_new(FALSE, 0);
498 gtk_container_add(GTK_CONTAINER(window), vbox);
499 menubar = gtk_menu_bar_new();
500 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
501 notebook = gtk_notebook_new();
502 g_object_set(G_OBJECT(notebook), "homogeneous", TRUE, NULL);
503 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
504 gtk_container_add(GTK_CONTAINER(vbox), notebook);
505
506 /* Dumm menu */
507 menu = gtk_menu_new();
508 dummMenu = gtk_menu_item_new_with_mnemonic("_Dumm");
509 gtk_menu_bar_append(GTK_MENU_BAR(menubar), dummMenu);
510 gtk_widget_show(dummMenu);
511 gtk_menu_item_set_submenu(GTK_MENU_ITEM(dummMenu), menu);
512
513 /* Dumm -> exit */
514 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
515 g_signal_connect(G_OBJECT(menuitem), "activate",
516 G_CALLBACK(quit), NULL);
517 gtk_menu_append(GTK_MENU(menu), menuitem);
518 gtk_widget_show(menuitem);
519
520 /* Guest menu */
521 menu = gtk_menu_new();
522 guestMenu = gtk_menu_item_new_with_mnemonic("_Guest");
523 gtk_menu_bar_append(GTK_MENU_BAR(menubar), guestMenu);
524 gtk_widget_show(guestMenu);
525 gtk_menu_item_set_submenu(GTK_MENU_ITEM(guestMenu), menu);
526
527 /* Guest -> new */
528 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
529 g_signal_connect(G_OBJECT(menuitem), "activate",
530 G_CALLBACK(create_guest), NULL);
531 gtk_menu_append(GTK_MENU(menu), menuitem);
532 gtk_widget_show(menuitem);
533
534 /* Guest -> delete */
535 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
536 g_signal_connect(G_OBJECT(menuitem), "activate",
537 G_CALLBACK(delete_guest), NULL);
538 gtk_menu_append(GTK_MENU(menu), menuitem);
539 gtk_widget_show(menuitem);
540
541 menuitem = gtk_separator_menu_item_new();
542 gtk_menu_append(GTK_MENU(menu), menuitem);
543 gtk_widget_show(menuitem);
544
545 /* Guest -> start */
546 menuitem = gtk_menu_item_new_with_mnemonic("_Start");
547 g_signal_connect(G_OBJECT(menuitem), "activate",
548 G_CALLBACK(start_guest), NULL);
549 gtk_menu_append(GTK_MENU(menu), menuitem);
550 gtk_widget_show(menuitem);
551
552 /* Guest -> startall */
553 menuitem = gtk_menu_item_new_with_mnemonic("Start _all");
554 g_signal_connect(G_OBJECT(menuitem), "activate",
555 G_CALLBACK(start_all_guests), NULL);
556 gtk_menu_append(GTK_MENU(menu), menuitem);
557 gtk_widget_show(menuitem);
558
559 /* Guest -> stop */
560 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_STOP, NULL);
561 g_signal_connect(G_OBJECT(menuitem), "activate",
562 G_CALLBACK(stop_guest), NULL);
563 gtk_menu_append(GTK_MENU(menu), menuitem);
564 gtk_widget_show(menuitem);
565
566 menuitem = gtk_separator_menu_item_new();
567 gtk_menu_append(GTK_MENU(menu), menuitem);
568 gtk_widget_show(menuitem);
569
570 /* Guest -> connect */
571 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL);
572 g_signal_connect(G_OBJECT(menuitem), "activate",
573 G_CALLBACK(connect_guest), NULL);
574 gtk_menu_append(GTK_MENU(menu), menuitem);
575 gtk_widget_show(menuitem);
576
577 /* Guest -> disconnect */
578 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DISCONNECT, NULL);
579 g_signal_connect(G_OBJECT(menuitem), "activate",
580 G_CALLBACK(disconnect_guest), NULL);
581 gtk_menu_append(GTK_MENU(menu), menuitem);
582 gtk_widget_set_sensitive(menuitem, FALSE);
583 gtk_widget_show(menuitem);
584
585 /* Switch menu */
586 menu = gtk_menu_new();
587 switchMenu = gtk_menu_item_new_with_mnemonic("_Switch");
588 gtk_menu_bar_append(GTK_MENU_BAR(menubar), switchMenu);
589 gtk_widget_show(switchMenu);
590 gtk_menu_item_set_submenu(GTK_MENU_ITEM(switchMenu), menu);
591
592 /* Switch -> new */
593 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
594 g_signal_connect(G_OBJECT(menuitem), "activate",
595 G_CALLBACK(create_switch), NULL);
596 gtk_menu_append(GTK_MENU(menu), menuitem);
597 gtk_widget_show(menuitem);
598
599 /* Switch -> delete */
600 menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
601 g_signal_connect(G_OBJECT(menuitem), "activate",
602 G_CALLBACK(delete_switch), NULL);
603 gtk_menu_append(GTK_MENU(menu), menuitem);
604 gtk_widget_set_sensitive(menuitem, FALSE);
605 gtk_widget_show(menuitem);
606
607 /* show widgets */
608 gtk_widget_show(menubar);
609 gtk_widget_show(notebook);
610 gtk_widget_show(vbox);
611 gtk_widget_show(window);
612
613 /* fill notebook with guests */
614 enumerator = dumm->create_guest_enumerator(dumm);
615 while (enumerator->enumerate(enumerator, (void**)&guest))
616 {
617 create_page(guest);
618 }
619 enumerator->destroy(enumerator);
620
621 gtk_main();
622
623 dumm->destroy(dumm);
624 pages->destroy_function(pages, g_free);
625
626 library_deinit();
627 return 0;
628 }
629