3 * Interaction thread between director and the GUI
5 * Nicolas Boichat, April 2004
10 Copyright (C) 2004-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
24 // http://66.102.9.104/search?q=cache:Djc1mPF3hRoJ:cvs.sourceforge.net/viewcvs.py/audacity/audacity-src/src/AudioIO.cpp%3Frev%3D1.102+macos+x+wxthread&hl=fr
26 /* _("...") macro returns a wxChar*, so if we need a char*, we need to convert it with:
27 * wxString(_("...")).mb_str(*wxConvCurrent) */
29 /* Windows debug builds set _DEBUG which is used by wxWidgets to select their
30 * debug memory allocator. Unfortunately it conflicts with Bacula's SmartAlloc.
31 * So we turn _DEBUG off since we aren't interested in things it enables.
37 #include "console_conf.h"
39 #include "console_thread.h" // class's header file
41 #include <wx/wxprec.h>
43 #include <wx/thread.h>
49 char OK_msg[] = "2000 OK\n";
50 char TERM_msg[] = "2999 Terminate\n";
53 /* Imported functions */
54 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
56 bool console_thread::inited = false;
57 bool console_thread::configloaded = false;
58 wxString console_thread::working_dir = wxT(".");
63 * Call-back for reading a passphrase for an encrypted PEM file
64 * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
66 static int tls_pem_callback(char *buf, int size, const void *userdata)
68 #if defined(HAVE_TLS) && !defined(HAVE_WIN32)
69 const char *prompt = (const char *) userdata;
72 passwd = getpass(prompt);
73 bstrncpy(buf, passwd, size);
83 * Make a quick check to see that we have all the
86 static int check_resources()
94 foreach_res(director, R_DIRECTOR) {
96 /* tls_require implies tls_enable */
97 if (director->tls_require) {
99 director->tls_enable = true;
101 Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
107 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
108 Jmsg(NULL, M_FATAL, 0, wxString(_("Neither \"TLS CA Certificate\" or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in config file.\nAt least one CA certificate store is required.\n")).mb_str(*wxConvCurrent),
115 Jmsg(NULL, M_FATAL, 0, wxString(_("No Director resource defined in config file.\nWithout that I don't how to speak to the Director :-(\n")).mb_str(*wxConvCurrent));
120 /* Loop over Consoles */
121 foreach_res(cons, R_CONSOLE) {
122 /* tls_require implies tls_enable */
123 if (cons->tls_require) {
125 cons->tls_enable = true;
127 Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
133 if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
134 Jmsg(NULL, M_FATAL, 0, wxString(_("Neither \"TLS CA Certificate\" or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in config file.\n")).mb_str(*wxConvCurrent),
144 void console_thread::SetWorkingDirectory(wxString w_dir) {
145 if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
146 console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
149 console_thread::working_dir = w_dir;
153 void console_thread::InitLib()
155 if (WSA_Init() != 0) {
156 csprint(_("Error while initializing windows sockets...\n"));
162 my_name_is(0, NULL, "wx-console");
163 working_directory = (const char*) console_thread::working_dir.GetData();
168 void console_thread::FreeLib()
171 if (WSACleanup() != 0) {
172 csprint(_("Error while cleaning up windows sockets...\n"));
180 * Format a scanner error message
182 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
186 char more[MAXSTRING];
189 va_start(arg_ptr, msg);
190 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
193 if (lc->line_no > lc->begin_line_no) {
194 bsnprintf(more, sizeof(more),
195 wxString(_("Problem probably begins at line %d.\n")).mb_str(*wxConvCurrent), lc->begin_line_no);
200 err.Format(_("Config error: %s\n : line %d, col %d of file %s\n%s\n%s"),
201 buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
206 wxString console_thread::LoadConfig(wxString configfile)
211 return _("Error while initializing library.");
214 free_config_resources();
216 MSGS* msgs = (MSGS *)bmalloc(sizeof(MSGS));
217 memset(msgs, 0, sizeof(MSGS));
218 for (int i=1; i<=M_MAX; i++) {
220 add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
222 // add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
223 add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
226 init_msg(NULL, msgs);
227 //init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
230 if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
231 configloaded = false;
236 if (init_crypto() != 0) {
237 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Cryptographic library initialization failed.\n")).mb_str(*wxConvCurrent));
240 if (!check_resources()) {
241 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Please correct configuration file.\n")).mb_str(*wxConvCurrent));
245 wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
246 init_msg(NULL, NULL);
254 console_thread::console_thread() {
256 choosingdirector = false;
260 console_thread::~console_thread() {
262 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
271 void* console_thread::Entry() {
273 /* It seems we must redefine the locale on each thread on wxGTK.
274 * On Win32 it makes wx-console crash. */
277 m_locale.AddCatalog(wxT("bacula"));
278 wxLocale::AddCatalogLookupPathPrefix(wxT(LOCALEDIR));
283 csprint(_("Error : Library not initialized\n"));
284 csprint(NULL, CS_END);
285 csprint(NULL, CS_DISCONNECTED);
286 csprint(NULL, CS_TERMINATED);
294 csprint(_("Error : No configuration file loaded\n"));
295 csprint(NULL, CS_END);
296 csprint(NULL, CS_DISCONNECTED);
297 csprint(NULL, CS_TERMINATED);
304 csprint(_("Connecting...\n"));
307 DIRRES* res[16]; /* Maximum 16 directors */
310 foreach_res(dir, R_DIRECTOR) {
320 csprint(_("Error : No director defined in config file.\n"));
321 csprint(NULL, CS_END);
322 csprint(NULL, CS_DISCONNECTED);
323 csprint(NULL, CS_TERMINATED);
328 } else if (count == 1) {
332 csprint(_("Multiple directors found in your config file.\n"));
333 for (int i = 0; i < count; i++) {
335 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
338 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
341 csprint(wxString::Format(_("Please choose a director (1-%d): "), count), CS_DATA);
342 csprint(NULL, CS_PROMPT);
343 choosingdirector = true;
344 directorchoosen = -1;
345 while(directorchoosen == -1) {
346 bmicrosleep(0, 2000);
349 choosingdirector = false;
350 if (directorchoosen != 0) {
355 dir = res[directorchoosen-1];
357 memset(&jcr, 0, sizeof(jcr));
359 jcr.dequeuing = 1; /* TODO: catch messages */
362 /* If cons==NULL, default console will be used */
363 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
367 /* Initialize Console TLS context */
368 if (cons && (cons->tls_enable || cons->tls_require)) {
369 /* Generate passphrase prompt */
370 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Console \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), cons->hdr.name);
372 /* Initialize TLS context:
373 * Args: CA certfile, CA certdir, Certfile, Keyfile,
374 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
375 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
376 cons->tls_ca_certdir, cons->tls_certfile,
377 cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
379 if (!cons->tls_ctx) {
380 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Console \"%s\".\n")).mb_str(*wxConvCurrent),
388 /* Initialize Director TLS context */
389 if (dir->tls_enable || dir->tls_require) {
390 /* Generate passphrase prompt */
391 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Director \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), dir->hdr.name);
393 /* Initialize TLS context:
394 * Args: CA certfile, CA certdir, Certfile, Keyfile,
395 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
396 dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
397 dir->tls_ca_certdir, dir->tls_certfile,
398 dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
401 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Director \"%s\".\n")).mb_str(*wxConvCurrent),
409 UA_sock = bnet_connect(&jcr, 3, 3, wxString(_("Director daemon")).mb_str(*wxConvCurrent),
410 dir->address, NULL, dir->DIRport, 0);
412 if (UA_sock == NULL) {
413 csprint(_("Failed to connect to the director\n"));
414 csprint(NULL, CS_END);
415 csprint(NULL, CS_DISCONNECTED);
416 csprint(NULL, CS_TERMINATED);
423 csprint(_("Connected\n"));
425 jcr.dir_bsock = UA_sock;
426 if (!authenticate_director(&jcr, dir, cons)) {
428 csprint(UA_sock->msg);
429 csprint(NULL, CS_END);
430 csprint(NULL, CS_DISCONNECTED);
431 csprint(NULL, CS_TERMINATED);
438 csprint(NULL, CS_CONNECTED);
440 Write("autodisplay on\n");
441 Write(".messages\n");
445 int last_is_eod = 0; /* Last packet received is BNET_EOD */
446 int do_not_forward_eod = 0; /* Last packet received/sent is .messages, so don't forward EOD. (so wx-console don't show the prompt again) */
449 while(!TestDestroy()) { /* Tests if thread has been ended */
450 stat = bnet_wait_data(UA_sock, 10);
453 Write(".messages\n");
454 do_not_forward_eod = 1;
460 if ((stat = bnet_recv(UA_sock)) >= 0) {
461 if (do_not_forward_eod) { /* .messages got data: remove the prompt */
462 csprint(NULL, CS_REMOVEPROMPT);
464 csprint(UA_sock->msg);
466 else if (stat == BNET_SIGNAL) {
467 if (UA_sock->msglen == BNET_PROMPT) {
468 csprint(NULL, CS_PROMPT);
469 } else if (UA_sock->msglen == BNET_EOD) {
471 if (!do_not_forward_eod)
472 csprint(NULL, CS_END);
473 } else if (UA_sock->msglen == BNET_HEARTBEAT) {
474 bnet_sig(UA_sock, BNET_HB_RESPONSE);
475 csprint(_("<< Heartbeat signal received, answered. >>\n"), CS_DEBUG);
476 } else if (UA_sock->msglen == BNET_START_SELECT ||
477 UA_sock->msglen == BNET_END_SELECT) {
478 /* Ignore start/end selections for now */
480 csprint(_("<< Unexpected signal received : "), CS_DEBUG);
481 csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
482 csprint(">>\n", CS_DEBUG);
485 else { /* BNET_HARDEOF || BNET_ERROR */
486 csprint(NULL, CS_END);
490 if (is_bnet_stop(UA_sock)) {
491 csprint(NULL, CS_END);
492 break; /* error or term */
495 do_not_forward_eod = 0;
498 csprint(NULL, CS_DISCONNECTED);
500 csprint(_("Connection terminated\n"));
504 csprint(NULL, CS_TERMINATED);
513 void console_thread::Write(const char* str)
516 UA_sock->msglen = (int32_t)strlen(str);
517 pm_strcpy(&UA_sock->msg, str);
519 } else if (choosingdirector) {
520 // wxString number = str;
521 // number.RemoveLast(); /* Removes \n */
524 // if (number.ToLong(&val)) {
527 directorchoosen = (int)val;
534 void console_thread::Delete() {
537 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
540 /*csprint(NULL, CS_END);
541 csprint(NULL, CS_DISCONNECTED);
542 csprint(NULL, CS_TERMINATED);*/