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++) {
219 add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
220 // add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
221 add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
224 init_msg(NULL, msgs);
225 //init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
228 if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
229 configloaded = false;
234 if (init_crypto() != 0) {
235 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Cryptographic library initialization failed.\n")).mb_str(*wxConvCurrent));
238 if (!check_resources()) {
239 Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Please correct configuration file.\n")).mb_str(*wxConvCurrent));
243 wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
244 init_msg(NULL, NULL);
252 console_thread::console_thread() {
254 choosingdirector = false;
258 console_thread::~console_thread() {
260 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
269 void* console_thread::Entry() {
271 /* It seems we must redefine the locale on each thread on wxGTK.
272 * On Win32 it makes wx-console crash. */
275 m_locale.AddCatalog(wxT("bacula"));
276 wxLocale::AddCatalogLookupPathPrefix(wxT(LOCALEDIR));
281 csprint(_("Error : Library not initialized\n"));
282 csprint(NULL, CS_END);
283 csprint(NULL, CS_DISCONNECTED);
284 csprint(NULL, CS_TERMINATED);
292 csprint(_("Error : No configuration file loaded\n"));
293 csprint(NULL, CS_END);
294 csprint(NULL, CS_DISCONNECTED);
295 csprint(NULL, CS_TERMINATED);
302 csprint(_("Connecting...\n"));
305 DIRRES* res[16]; /* Maximum 16 directors */
308 foreach_res(dir, R_DIRECTOR) {
318 csprint(_("Error : No director defined in config file.\n"));
319 csprint(NULL, CS_END);
320 csprint(NULL, CS_DISCONNECTED);
321 csprint(NULL, CS_TERMINATED);
326 } else if (count == 1) {
330 csprint(_("Multiple directors found in your config file.\n"));
331 for (int i = 0; i < count; i++) {
333 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
336 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
339 csprint(wxString::Format(_("Please choose a director (1-%d): "), count), CS_DATA);
340 csprint(NULL, CS_PROMPT);
341 choosingdirector = true;
342 directorchoosen = -1;
343 while(directorchoosen == -1) {
344 bmicrosleep(0, 2000);
347 choosingdirector = false;
348 if (directorchoosen != 0) {
353 dir = res[directorchoosen-1];
355 memset(&jcr, 0, sizeof(jcr));
357 jcr.dequeuing = 1; /* TODO: catch messages */
360 /* If cons==NULL, default console will be used */
361 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
365 /* Initialize Console TLS context */
366 if (cons && (cons->tls_enable || cons->tls_require)) {
367 /* Generate passphrase prompt */
368 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Console \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), cons->hdr.name);
370 /* Initialize TLS context:
371 * Args: CA certfile, CA certdir, Certfile, Keyfile,
372 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
373 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
374 cons->tls_ca_certdir, cons->tls_certfile,
375 cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
377 if (!cons->tls_ctx) {
378 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Console \"%s\".\n")).mb_str(*wxConvCurrent),
386 /* Initialize Director TLS context */
387 if (dir->tls_enable || dir->tls_require) {
388 /* Generate passphrase prompt */
389 bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Director \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), dir->hdr.name);
391 /* Initialize TLS context:
392 * Args: CA certfile, CA certdir, Certfile, Keyfile,
393 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
394 dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
395 dir->tls_ca_certdir, dir->tls_certfile,
396 dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
399 bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Director \"%s\".\n")).mb_str(*wxConvCurrent),
407 UA_sock = bnet_connect(&jcr, 3, 3, wxString(_("Director daemon")).mb_str(*wxConvCurrent),
408 dir->address, NULL, dir->DIRport, 0);
410 if (UA_sock == NULL) {
411 csprint(_("Failed to connect to the director\n"));
412 csprint(NULL, CS_END);
413 csprint(NULL, CS_DISCONNECTED);
414 csprint(NULL, CS_TERMINATED);
421 csprint(_("Connected\n"));
423 jcr.dir_bsock = UA_sock;
424 if (!authenticate_director(&jcr, dir, cons)) {
426 csprint(UA_sock->msg);
427 csprint(NULL, CS_END);
428 csprint(NULL, CS_DISCONNECTED);
429 csprint(NULL, CS_TERMINATED);
436 csprint(NULL, CS_CONNECTED);
438 Write("autodisplay on\n");
439 Write(".messages\n");
443 int last_is_eod = 0; /* Last packet received is BNET_EOD */
444 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) */
447 while(!TestDestroy()) { /* Tests if thread has been ended */
448 stat = bnet_wait_data(UA_sock, 10);
451 Write(".messages\n");
452 do_not_forward_eod = 1;
458 if ((stat = bnet_recv(UA_sock)) >= 0) {
459 if (do_not_forward_eod) { /* .messages got data: remove the prompt */
460 csprint(NULL, CS_REMOVEPROMPT);
462 csprint(UA_sock->msg);
464 else if (stat == BNET_SIGNAL) {
465 if (UA_sock->msglen == BNET_PROMPT) {
466 csprint(NULL, CS_PROMPT);
467 } else if (UA_sock->msglen == BNET_EOD) {
469 if (!do_not_forward_eod)
470 csprint(NULL, CS_END);
471 } else if (UA_sock->msglen == BNET_HEARTBEAT) {
472 bnet_sig(UA_sock, BNET_HB_RESPONSE);
473 csprint(_("<< Heartbeat signal received, answered. >>\n"), CS_DEBUG);
474 } else if (UA_sock->msglen == BNET_START_SELECT ||
475 UA_sock->msglen == BNET_END_SELECT) {
476 /* Ignore start/end selections for now */
478 csprint(_("<< Unexpected signal received : "), CS_DEBUG);
479 csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
480 csprint(">>\n", CS_DEBUG);
483 else { /* BNET_HARDEOF || BNET_ERROR */
484 csprint(NULL, CS_END);
488 if (is_bnet_stop(UA_sock)) {
489 csprint(NULL, CS_END);
490 break; /* error or term */
493 do_not_forward_eod = 0;
496 csprint(NULL, CS_DISCONNECTED);
498 csprint(_("Connection terminated\n"));
502 csprint(NULL, CS_TERMINATED);
511 void console_thread::Write(const char* str)
514 UA_sock->msglen = (int32_t)strlen(str);
515 pm_strcpy(&UA_sock->msg, str);
517 } else if (choosingdirector) {
518 // wxString number = str;
519 // number.RemoveLast(); /* Removes \n */
522 // if (number.ToLong(&val)) {
525 directorchoosen = (int)val;
532 void console_thread::Delete() {
535 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
538 /*csprint(NULL, CS_END);
539 csprint(NULL, CS_DISCONNECTED);
540 csprint(NULL, CS_TERMINATED);*/