3 * Interaction thread between director and the GUI
5 * Nicolas Boichat, April 2004
10 Copyright (C) 2004-2005 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 #include "console_thread.h" // class's header file
28 #include <wx/wxprec.h>
30 #include <wx/thread.h>
35 #include "console_conf.h"
41 char OK_msg[] = "2000 OK\n";
42 char TERM_msg[] = "2999 Terminate\n";
45 /* Imported functions */
46 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
48 bool console_thread::inited = false;
49 bool console_thread::configloaded = false;
50 wxString console_thread::working_dir = wxT(".");
55 * Call-back for reading a passphrase for an encrypted PEM file
56 * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
58 static int tls_pem_callback(char *buf, int size, const void *userdata)
61 const char *prompt = (const char *) userdata;
64 passwd = getpass(prompt);
65 bstrncpy(buf, passwd, size);
75 * Make a quick check to see that we have all the
78 static int check_resources()
86 foreach_res(director, R_DIRECTOR) {
88 /* tls_require implies tls_enable */
89 if (director->tls_require) {
91 director->tls_enable = true;
93 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
99 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
100 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
101 " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in config file.\n"
102 " At least one CA certificate store is required.\n"),
109 Jmsg(NULL, M_FATAL, 0, _("No Director resource defined in config file.\n"
110 "Without that I don't how to speak to the Director :-(\n"));
115 /* Loop over Consoles */
116 foreach_res(cons, R_CONSOLE) {
117 /* tls_require implies tls_enable */
118 if (cons->tls_require) {
120 cons->tls_enable = true;
122 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
128 if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
129 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
130 " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in config file.\n"),
140 void console_thread::SetWorkingDirectory(wxString w_dir) {
141 if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
142 console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
145 console_thread::working_dir = w_dir;
149 void console_thread::InitLib() {
150 if (WSA_Init() != 0) {
151 csprint("Error while initializing windows sockets...\n");
157 my_name_is(0, NULL, "wx-console");
158 //textdomain("bacula-console");
159 working_directory = (const char*) console_thread::working_dir.GetData();
164 void console_thread::FreeLib() {
166 if (WSACleanup() != 0) {
167 csprint("Error while cleaning up windows sockets...\n");
175 * Format a scanner error message
177 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
181 char more[MAXSTRING];
184 va_start(arg_ptr, msg);
185 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
188 if (lc->line_no > lc->begin_line_no) {
189 bsnprintf(more, sizeof(more),
190 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
195 err.Format(wxT("Config error: %s\n : line %d, col %d of file %s\n%s\n%s"),
196 buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
201 wxString console_thread::LoadConfig(wxString configfile) {
205 return wxT("Error while initializing library.");
208 free_config_resources();
210 MSGS* msgs = (MSGS *)malloc(sizeof(MSGS));
211 memset(msgs, 0, sizeof(MSGS));
212 for (int i=1; i<=M_MAX; i++) {
214 add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
216 // add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
217 add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
220 init_msg(NULL, msgs);
221 init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
224 if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
225 configloaded = false;
230 if (init_tls() != 0) {
231 Jmsg(NULL, M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
234 if (!check_resources()) {
235 Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file.\n"));
239 wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
240 init_msg(NULL, NULL);
248 console_thread::console_thread() {
250 choosingdirector = false;
254 console_thread::~console_thread() {
256 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
265 void* console_thread::Entry() {
268 csprint("Error : Library not initialized\n");
269 csprint(NULL, CS_END);
270 csprint(NULL, CS_DISCONNECTED);
271 csprint(NULL, CS_TERMINATED);
279 csprint("Error : No configuration file loaded\n");
280 csprint(NULL, CS_END);
281 csprint(NULL, CS_DISCONNECTED);
282 csprint(NULL, CS_TERMINATED);
289 csprint("Connecting...\n");
292 DIRRES* res[16]; /* Maximum 16 directors */
295 foreach_res(dir, R_DIRECTOR) {
305 csprint("Error : No director defined in config file.\n");
306 csprint(NULL, CS_END);
307 csprint(NULL, CS_DISCONNECTED);
308 csprint(NULL, CS_TERMINATED);
313 } else if (count == 1) {
317 csprint("Multiple directors found in your config file.\n");
318 for (int i = 0; i < count; i++) {
320 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
323 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
326 csprint(wxString(wxT("Please choose a director (1-")) << count << wxT(") : "),CS_DATA);
327 csprint(NULL, CS_PROMPT);
328 choosingdirector = true;
329 directorchoosen = -1;
330 while(directorchoosen == -1) {
331 bmicrosleep(0, 2000);
334 choosingdirector = false;
335 if (directorchoosen != 0) {
340 dir = res[directorchoosen-1];
342 memset(&jcr, 0, sizeof(jcr));
344 jcr.dequeuing = 1; /* TODO: catch messages */
347 /* If cons==NULL, default console will be used */
348 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
352 /* Initialize Console TLS context */
353 if (cons && (cons->tls_enable || cons->tls_require)) {
354 /* Generate passphrase prompt */
355 bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ", cons->hdr.name);
357 /* Initialize TLS context:
358 * Args: CA certfile, CA certdir, Certfile, Keyfile,
359 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
360 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
361 cons->tls_ca_certdir, cons->tls_certfile,
362 cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
364 if (!cons->tls_ctx) {
365 bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Console \"%s\".\n"),
373 /* Initialize Director TLS context */
374 if (dir->tls_enable || dir->tls_require) {
375 /* Generate passphrase prompt */
376 bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", dir->hdr.name);
378 /* Initialize TLS context:
379 * Args: CA certfile, CA certdir, Certfile, Keyfile,
380 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
381 dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
382 dir->tls_ca_certdir, dir->tls_certfile,
383 dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
386 bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Director \"%s\".\n"),
394 UA_sock = bnet_connect(&jcr, 3, 3, "Director daemon",
395 dir->address, NULL, dir->DIRport, 0);
397 if (UA_sock == NULL) {
398 csprint("Failed to connect to the director\n");
399 csprint(NULL, CS_END);
400 csprint(NULL, CS_DISCONNECTED);
401 csprint(NULL, CS_TERMINATED);
408 csprint("Connected\n");
410 jcr.dir_bsock = UA_sock;
411 if (!authenticate_director(&jcr, dir, cons)) {
413 csprint(UA_sock->msg);
414 csprint(NULL, CS_END);
415 csprint(NULL, CS_DISCONNECTED);
416 csprint(NULL, CS_TERMINATED);
423 csprint(NULL, CS_CONNECTED);
425 Write(".messages\n");
430 while(!TestDestroy()) { /* Tests if thread has been ended */
431 if ((stat = bnet_recv(UA_sock)) >= 0) {
432 csprint(UA_sock->msg);
434 else if (stat == BNET_SIGNAL) {
435 if (UA_sock->msglen == BNET_PROMPT) {
436 csprint(NULL, CS_PROMPT);
438 else if (UA_sock->msglen == BNET_EOD) {
439 csprint(NULL, CS_END);
441 else if (UA_sock->msglen == BNET_HEARTBEAT) {
442 bnet_sig(UA_sock, BNET_HB_RESPONSE);
443 csprint("<< Heartbeat signal received, answered. >>\n", CS_DEBUG);
446 csprint("<< Unexpected signal received : ", CS_DEBUG);
447 csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
448 csprint(">>\n", CS_DEBUG);
451 else { /* BNET_HARDEOF || BNET_ERROR */
452 csprint(NULL, CS_END);
456 if (is_bnet_stop(UA_sock)) {
457 csprint(NULL, CS_END);
458 break; /* error or term */
462 csprint(NULL, CS_DISCONNECTED);
464 csprint("Connection terminated\n");
468 csprint(NULL, CS_TERMINATED);
477 void console_thread::Write(const char* str) {
479 UA_sock->msglen = strlen(str);
480 pm_strcpy(&UA_sock->msg, str);
483 else if (choosingdirector) {
485 // wxString number = str;
486 // number.RemoveLast(); /* Removes \n */
489 // if (number.ToLong(&val)) {
490 if (val = atol(str)) {
491 directorchoosen = (int)val;
499 void console_thread::Delete() {
502 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
505 /*csprint(NULL, CS_END);
506 csprint(NULL, CS_DISCONNECTED);
507 csprint(NULL, CS_TERMINATED);*/