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 working_directory = (const char*) console_thread::working_dir.GetData();
163 void console_thread::FreeLib() {
165 if (WSACleanup() != 0) {
166 csprint(_("Error while cleaning up windows sockets...\n"));
174 * Format a scanner error message
176 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
180 char more[MAXSTRING];
183 va_start(arg_ptr, msg);
184 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
187 if (lc->line_no > lc->begin_line_no) {
188 bsnprintf(more, sizeof(more),
189 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
194 err.Format(wxT(_("Config error: %s\n : line %d, col %d of file %s\n%s\n%s")),
195 buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
200 wxString console_thread::LoadConfig(wxString configfile) {
204 return wxT(_("Error while initializing library."));
207 free_config_resources();
209 MSGS* msgs = (MSGS *)malloc(sizeof(MSGS));
210 memset(msgs, 0, sizeof(MSGS));
211 for (int i=1; i<=M_MAX; i++) {
213 add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
215 // add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
216 add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
219 init_msg(NULL, msgs);
220 init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
223 if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
224 configloaded = false;
229 if (init_tls() != 0) {
230 Jmsg(NULL, M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
233 if (!check_resources()) {
234 Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file.\n"));
238 wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
239 init_msg(NULL, NULL);
247 console_thread::console_thread() {
249 choosingdirector = false;
253 console_thread::~console_thread() {
255 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
264 void* console_thread::Entry() {
267 csprint(_("Error : Library not initialized\n"));
268 csprint(NULL, CS_END);
269 csprint(NULL, CS_DISCONNECTED);
270 csprint(NULL, CS_TERMINATED);
278 csprint(_("Error : No configuration file loaded\n"));
279 csprint(NULL, CS_END);
280 csprint(NULL, CS_DISCONNECTED);
281 csprint(NULL, CS_TERMINATED);
288 csprint(_("Connecting...\n"));
291 DIRRES* res[16]; /* Maximum 16 directors */
294 foreach_res(dir, R_DIRECTOR) {
304 csprint(_("Error : No director defined in config file.\n"));
305 csprint(NULL, CS_END);
306 csprint(NULL, CS_DISCONNECTED);
307 csprint(NULL, CS_TERMINATED);
312 } else if (count == 1) {
316 csprint(_("Multiple directors found in your config file.\n"));
317 for (int i = 0; i < count; i++) {
319 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
322 csprint(wxString(wxT(" ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
325 csprint(wxString::Format(wxT(_("Please choose a director (1-%d): ")), count), CS_DATA);
326 csprint(NULL, CS_PROMPT);
327 choosingdirector = true;
328 directorchoosen = -1;
329 while(directorchoosen == -1) {
330 bmicrosleep(0, 2000);
333 choosingdirector = false;
334 if (directorchoosen != 0) {
339 dir = res[directorchoosen-1];
341 memset(&jcr, 0, sizeof(jcr));
343 jcr.dequeuing = 1; /* TODO: catch messages */
346 /* If cons==NULL, default console will be used */
347 CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
351 /* Initialize Console TLS context */
352 if (cons && (cons->tls_enable || cons->tls_require)) {
353 /* Generate passphrase prompt */
354 bsnprintf(buf, sizeof(buf), _("Passphrase for Console \"%s\" TLS private key: "), cons->hdr.name);
356 /* Initialize TLS context:
357 * Args: CA certfile, CA certdir, Certfile, Keyfile,
358 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
359 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
360 cons->tls_ca_certdir, cons->tls_certfile,
361 cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
363 if (!cons->tls_ctx) {
364 bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Console \"%s\".\n"),
372 /* Initialize Director TLS context */
373 if (dir->tls_enable || dir->tls_require) {
374 /* Generate passphrase prompt */
375 bsnprintf(buf, sizeof(buf), _("Passphrase for Director \"%s\" TLS private key: "), dir->hdr.name);
377 /* Initialize TLS context:
378 * Args: CA certfile, CA certdir, Certfile, Keyfile,
379 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
380 dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
381 dir->tls_ca_certdir, dir->tls_certfile,
382 dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
385 bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Director \"%s\".\n"),
393 UA_sock = bnet_connect(&jcr, 3, 3, _("Director daemon"),
394 dir->address, NULL, dir->DIRport, 0);
396 if (UA_sock == NULL) {
397 csprint(_("Failed to connect to the director\n"));
398 csprint(NULL, CS_END);
399 csprint(NULL, CS_DISCONNECTED);
400 csprint(NULL, CS_TERMINATED);
407 csprint(_("Connected\n"));
409 jcr.dir_bsock = UA_sock;
410 if (!authenticate_director(&jcr, dir, cons)) {
412 csprint(UA_sock->msg);
413 csprint(NULL, CS_END);
414 csprint(NULL, CS_DISCONNECTED);
415 csprint(NULL, CS_TERMINATED);
422 csprint(NULL, CS_CONNECTED);
424 Write(".messages\n");
429 while(!TestDestroy()) { /* Tests if thread has been ended */
430 if ((stat = bnet_recv(UA_sock)) >= 0) {
431 csprint(UA_sock->msg);
433 else if (stat == BNET_SIGNAL) {
434 if (UA_sock->msglen == BNET_PROMPT) {
435 csprint(NULL, CS_PROMPT);
437 else if (UA_sock->msglen == BNET_EOD) {
438 csprint(NULL, CS_END);
440 else if (UA_sock->msglen == BNET_HEARTBEAT) {
441 bnet_sig(UA_sock, BNET_HB_RESPONSE);
442 csprint(_("<< Heartbeat signal received, answered. >>\n"), CS_DEBUG);
445 csprint(_("<< Unexpected signal received : "), CS_DEBUG);
446 csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
447 csprint(">>\n", CS_DEBUG);
450 else { /* BNET_HARDEOF || BNET_ERROR */
451 csprint(NULL, CS_END);
455 if (is_bnet_stop(UA_sock)) {
456 csprint(NULL, CS_END);
457 break; /* error or term */
461 csprint(NULL, CS_DISCONNECTED);
463 csprint(_("Connection terminated\n"));
467 csprint(NULL, CS_TERMINATED);
476 void console_thread::Write(const char* str)
479 UA_sock->msglen = strlen(str);
480 pm_strcpy(&UA_sock->msg, str);
482 } else if (choosingdirector) {
483 // wxString number = str;
484 // number.RemoveLast(); /* Removes \n */
487 // if (number.ToLong(&val)) {
490 directorchoosen = (int)val;
497 void console_thread::Delete() {
500 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
503 /*csprint(NULL, CS_END);
504 csprint(NULL, CS_DISCONNECTED);
505 csprint(NULL, CS_TERMINATED);*/