1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Network Utility Routines
25 *
26 * by Kern Sibbald
27 *
28 * Adapted and enhanced for BAREOS, originally written
29 * for inclusion in the Apcupsd package
30 */
31 /**
32 * @file
33 * Network Utility Routines
34 */
35
36 #include "include/bareos.h"
37 #include "jcr.h"
38 #include "lib/berrno.h"
39 #include "lib/bnet.h"
40 #include "lib/bsock.h"
41 #include "lib/bsys.h"
42 #include "lib/ascii_control_characters.h"
43 #include "lib/bstringlist.h"
44
45 #include <netdb.h>
46 #include "lib/tls.h"
47
48 #ifndef INADDR_NONE
49 # define INADDR_NONE -1
50 #endif
51
52 #ifndef HAVE_GETADDRINFO
53 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
54 #endif
55
56 /**
57 * Receive a message from the other end. Each message consists of
58 * two packets. The first is a header that contains the size
59 * of the data that follows in the second packet.
60 * Returns number of bytes read (may return zero)
61 * Returns -1 on signal (BNET_SIGNAL)
62 * Returns -2 on hard end of file (BNET_HARDEOF)
63 * Returns -3 on error (BNET_ERROR)
64 *
65 * Unfortunately, it is a bit complicated because we have these
66 * four return types:
67 * 1. Normal data
68 * 2. Signal including end of data stream
69 * 3. Hard end of file
70 * 4. Error
71 * Using IsBnetStop() and IsBnetError() you can figure this all out.
72 */
BnetRecv(BareosSocket * bsock)73 int32_t BnetRecv(BareosSocket* bsock) { return bsock->recv(); }
74
75
76 /**
77 * Return 1 if there are errors on this bsock or it is closed,
78 * i.e. stop communicating on this line.
79 */
IsBnetStop(BareosSocket * bsock)80 bool IsBnetStop(BareosSocket* bsock) { return bsock->IsStop(); }
81
82 /**
83 * Return number of errors on socket
84 */
IsBnetError(BareosSocket * bsock)85 int IsBnetError(BareosSocket* bsock) { return bsock->IsError(); }
86
87 /**
88 * Call here after error during closing to suppress error
89 * messages which are due to the other end shutting down too.
90 */
BnetSuppressErrorMessages(BareosSocket * bsock,bool flag)91 void BnetSuppressErrorMessages(BareosSocket* bsock, bool flag)
92 {
93 bsock->suppress_error_msgs_ = flag;
94 }
95
96 /**
97 * Send a message over the network. The send consists of
98 * two network packets. The first is sends a 32 bit integer containing
99 * the length of the data packet which follows.
100 *
101 * Returns: false on failure
102 * true on success
103 */
BnetSend(BareosSocket * bsock)104 bool BnetSend(BareosSocket* bsock) { return bsock->send(); }
105
106
107 /**
108 * Establish a TLS connection -- server side
109 * Returns: true on success
110 * false on failure
111 */
112 #ifdef HAVE_TLS
BnetTlsServer(BareosSocket * bsock,const std::vector<std::string> & verify_list)113 bool BnetTlsServer(BareosSocket* bsock,
114 const std::vector<std::string>& verify_list)
115 {
116 JobControlRecord* jcr = bsock->jcr();
117
118 if (!bsock->tls_conn_init) {
119 Dmsg0(100, "No TLS Connection: Cannot call TlsBsockAccept\n");
120 goto err;
121 }
122
123 if (!bsock->tls_conn_init->TlsBsockAccept(bsock)) {
124 Qmsg0(bsock->jcr(), M_FATAL, 0, _("TLS Negotiation failed.\n"));
125 goto err;
126 }
127
128 if (!verify_list.empty()) {
129 if (!bsock->tls_conn_init->TlsPostconnectVerifyCn(jcr, verify_list)) {
130 Qmsg1(bsock->jcr(), M_FATAL, 0,
131 _("TLS certificate verification failed."
132 " Peer certificate did not match a required commonName\n"),
133 bsock->host());
134 goto err;
135 }
136 }
137
138 bsock->LockMutex();
139 bsock->tls_conn = std::move(bsock->tls_conn_init);
140 bsock->UnlockMutex();
141
142 Dmsg0(50, "TLS server negotiation established.\n");
143 return true;
144
145 err:
146 bsock->CloseTlsConnectionAndFreeMemory();
147 return false;
148 }
149
150 /**
151 * Establish a TLS connection -- client side
152 * Returns: true on success
153 * false on failure
154 */
BnetTlsClient(BareosSocket * bsock,bool VerifyPeer,const std::vector<std::string> & verify_list)155 bool BnetTlsClient(BareosSocket* bsock,
156 bool VerifyPeer,
157 const std::vector<std::string>& verify_list)
158 {
159 JobControlRecord* jcr = bsock->jcr();
160
161 if (!bsock->tls_conn_init) {
162 Dmsg0(100, "No TLS Connection: Cannot call TlsBsockConnect\n");
163 goto err;
164 }
165
166 if (!bsock->tls_conn_init->TlsBsockConnect(bsock)) { goto err; }
167
168 if (VerifyPeer) {
169 /*
170 * If there's an Allowed CN verify list, use that to validate the remote
171 * certificate's CN. Otherwise, we use standard host/CN matching.
172 */
173 if (!verify_list.empty()) {
174 if (!bsock->tls_conn_init->TlsPostconnectVerifyCn(jcr, verify_list)) {
175 Qmsg1(bsock->jcr(), M_FATAL, 0,
176 _("TLS certificate verification failed."
177 " Peer certificate did not match a required commonName\n"),
178 bsock->host());
179 goto err;
180 }
181 } else {
182 if (!bsock->tls_conn_init->TlsPostconnectVerifyHost(jcr, bsock->host())) {
183 Qmsg1(bsock->jcr(), M_FATAL, 0,
184 _("TLS host certificate verification failed. Host name \"%s\" "
185 "did not match presented certificate\n"),
186 bsock->host());
187 goto err;
188 }
189 }
190 }
191
192 bsock->LockMutex();
193 bsock->tls_conn = std::move(bsock->tls_conn_init);
194 bsock->UnlockMutex();
195
196 Dmsg0(50, "TLS client negotiation established.\n");
197 return true;
198
199 err:
200 bsock->CloseTlsConnectionAndFreeMemory();
201 return false;
202 }
203 #else
BnetTlsServer(BareosSocket * bsock,const std::vector<std::string> & verify_list)204 bool BnetTlsServer(/* std::shared_ptr<TlsImplementation> tls_implementation, */
205 BareosSocket* bsock,
206 const std::vector<std::string>& verify_list)
207 {
208 Jmsg(bsock->jcr(), M_ABORT, 0, _("TLS enabled but not configured.\n"));
209 return false;
210 }
211
BnetTlsClient(BareosSocket * bsock,bool VerifyPeer,const std::vector<std::string> & verify_list)212 bool BnetTlsClient(/* std::shared_ptr<TLS_IMPLEMENTATION> tls_implementation, */
213 BareosSocket* bsock,
214 bool VerifyPeer,
215 const std::vector<std::string>& verify_list)
216 {
217 Jmsg(bsock->jcr(), M_ABORT, 0, _("TLS enabled but not configured.\n"));
218 return false;
219 }
220 #endif /* HAVE_TLS */
221
222 /**
223 * Wait for a specified time for data to appear on
224 * the BareosSocket connection.
225 *
226 * Returns: 1 if data available
227 * 0 if timeout
228 * -1 if error
229 */
BnetWaitData(BareosSocket * bsock,int sec)230 int BnetWaitData(BareosSocket* bsock, int sec) { return bsock->WaitData(sec); }
231
232 /**
233 * As above, but returns on interrupt
234 */
BnetWaitDataIntr(BareosSocket * bsock,int sec)235 int BnetWaitDataIntr(BareosSocket* bsock, int sec)
236 {
237 return bsock->WaitDataIntr(sec);
238 }
239
240 #ifndef NETDB_INTERNAL
241 # define NETDB_INTERNAL -1 /* See errno. */
242 #endif
243 #ifndef NETDB_SUCCESS
244 # define NETDB_SUCCESS 0 /* No problem. */
245 #endif
246 #ifndef HOST_NOT_FOUND
247 # define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found. */
248 #endif
249 #ifndef TRY_AGAIN
250 # define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL. */
251 #endif
252 #ifndef NO_RECOVERY
253 # define NO_RECOVERY 3 /* unrecoverable errors, FORMERR, REFUSED, NOTIMP. */
254 #endif
255 #ifndef NO_DATA
256 # define NO_DATA 4 /* Valid name, no data record of requested type. */
257 #endif
258
259 #if HAVE_GETADDRINFO
resolv_host(int family,const char * host,dlist * addr_list)260 const char* resolv_host(int family, const char* host, dlist* addr_list)
261 {
262 int res;
263 struct addrinfo hints;
264 struct addrinfo *ai, *rp;
265 IPADDR* addr;
266
267 memset(&hints, 0, sizeof(struct addrinfo));
268 hints.ai_family = family;
269 hints.ai_socktype = SOCK_STREAM;
270 hints.ai_protocol = IPPROTO_TCP;
271 hints.ai_flags = 0;
272
273 res = getaddrinfo(host, NULL, &hints, &ai);
274 if (res != 0) { return gai_strerror(res); }
275
276 for (rp = ai; rp != NULL; rp = rp->ai_next) {
277 switch (rp->ai_addr->sa_family) {
278 case AF_INET:
279 addr = new IPADDR(rp->ai_addr->sa_family);
280 addr->SetType(IPADDR::R_MULTIPLE);
281 /*
282 * Some serious casting to get the struct in_addr *
283 * rp->ai_addr == struct sockaddr
284 * as this is AF_INET family we can cast that
285 * to struct_sockaddr_in. Of that we need the
286 * address of the sin_addr member which contains a
287 * struct in_addr
288 */
289 addr->SetAddr4(&(((struct sockaddr_in*)rp->ai_addr)->sin_addr));
290 break;
291 # ifdef HAVE_IPV6
292 case AF_INET6:
293 addr = new IPADDR(rp->ai_addr->sa_family);
294 addr->SetType(IPADDR::R_MULTIPLE);
295 /*
296 * Some serious casting to get the struct in6_addr *
297 * rp->ai_addr == struct sockaddr
298 * as this is AF_INET6 family we can cast that
299 * to struct_sockaddr_in6. Of that we need the
300 * address of the sin6_addr member which contains a
301 * struct in6_addr
302 */
303 addr->SetAddr6(&(((struct sockaddr_in6*)rp->ai_addr)->sin6_addr));
304 break;
305 # endif
306 default:
307 continue;
308 }
309 addr_list->append(addr);
310 }
311 freeaddrinfo(ai);
312 return NULL;
313 }
314 #else
315 /**
316 * Get human readable error for gethostbyname()
317 */
gethost_strerror()318 static const char* gethost_strerror()
319 {
320 const char* msg;
321 BErrNo be;
322 switch (h_errno) {
323 case NETDB_INTERNAL:
324 msg = be.bstrerror();
325 break;
326 case NETDB_SUCCESS:
327 msg = _("No problem.");
328 break;
329 case HOST_NOT_FOUND:
330 msg = _("Authoritative answer for host not found.");
331 break;
332 case TRY_AGAIN:
333 msg = _("Non-authoritative for host not found, or ServerFail.");
334 break;
335 case NO_RECOVERY:
336 msg = _("Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.");
337 break;
338 case NO_DATA:
339 msg = _("Valid name, no data record of resquested type.");
340 break;
341 default:
342 msg = _("Unknown error.");
343 }
344 return msg;
345 }
346
resolv_host(int family,const char * host,dlist * addr_list)347 static const char* resolv_host(int family, const char* host, dlist* addr_list)
348 {
349 struct hostent* hp;
350 const char* errmsg;
351 char** p;
352 IPADDR* addr;
353
354 P(ip_mutex); /* gethostbyname() is not thread safe */
355 # ifdef HAVE_GETHOSTBYNAME2
356 if ((hp = gethostbyname2(host, family)) == NULL) {
357 # else
358 if ((hp = gethostbyname(host)) == NULL) {
359 # endif
360 /* may be the strerror give not the right result -:( */
361 errmsg = gethost_strerror();
362 V(ip_mutex);
363 return errmsg;
364 } else {
365 for (p = hp->h_addr_list; *p != 0; p++) {
366 switch (hp->h_addrtype) {
367 case AF_INET:
368 addr = new IPADDR(hp->h_addrtype);
369 addr->SetType(IPADDR::R_MULTIPLE);
370 addr->SetAddr4((struct in_addr*)*p);
371 break;
372 # ifdef HAVE_IPV6
373 case AF_INET6:
374 addr = new IPADDR(hp->h_addrtype);
375 addr->SetType(IPADDR::R_MULTIPLE);
376 addr->SetAddr6((struct in6_addr*)*p);
377 break;
378 # endif
379 default:
380 continue;
381 }
382 addr_list->append(addr);
383 }
384 V(ip_mutex);
385 }
386 return NULL;
387 }
388 #endif
389
390 static IPADDR* add_any(int family)
391 {
392 IPADDR* addr = new IPADDR(family);
393 addr->SetType(IPADDR::R_MULTIPLE);
394 addr->SetAddrAny();
395 return addr;
396 }
397
398 /**
399 * i host = 0 mean INADDR_ANY only ipv4
400 */
401 dlist* BnetHost2IpAddrs(const char* host, int family, const char** errstr)
402 {
403 struct in_addr inaddr;
404 IPADDR* addr = 0;
405 const char* errmsg;
406 #ifdef HAVE_IPV6
407 struct in6_addr inaddr6;
408 #endif
409
410 dlist* addr_list = new dlist(addr, &addr->link);
411 if (!host || host[0] == '\0') {
412 if (family != 0) {
413 addr_list->append(add_any(family));
414 } else {
415 addr_list->append(add_any(AF_INET));
416 #ifdef HAVE_IPV6
417 addr_list->append(add_any(AF_INET6));
418 #endif
419 }
420 } else if (inet_aton(host, &inaddr)) { /* MA Bug 4 */
421 addr = new IPADDR(AF_INET);
422 addr->SetType(IPADDR::R_MULTIPLE);
423 addr->SetAddr4(&inaddr);
424 addr_list->append(addr);
425 #ifdef HAVE_IPV6
426 # ifndef HAVE_WIN32
427 } else if (inet_pton(AF_INET6, host, &inaddr6) == 1) {
428 # else
429 } else if (p_InetPton && p_InetPton(AF_INET6, host, &inaddr6) == 1) {
430 # endif
431 addr = new IPADDR(AF_INET6);
432 addr->SetType(IPADDR::R_MULTIPLE);
433 addr->SetAddr6(&inaddr6);
434 addr_list->append(addr);
435 #endif
436 } else {
437 if (family != 0) {
438 errmsg = resolv_host(family, host, addr_list);
439 if (errmsg) {
440 *errstr = errmsg;
441 FreeAddresses(addr_list);
442 return 0;
443 }
444 } else {
445 #ifdef HAVE_IPV6
446 /* We try to resolv host for ipv6 and ipv4, the connection procedure
447 * will try to reach the host for each protocols. We report only "Host
448 * not found" ipv4 message (no need to have ipv6 and ipv4 messages).
449 */
450 resolv_host(AF_INET6, host, addr_list);
451 #endif
452 errmsg = resolv_host(AF_INET, host, addr_list);
453
454 if (addr_list->size() == 0) {
455 *errstr = errmsg;
456 FreeAddresses(addr_list);
457 return 0;
458 }
459 }
460 }
461 return addr_list;
462 }
463
464 /**
465 * Return the string for the error that occurred
466 * on the socket. Only the first error is retained.
467 */
468 const char* BnetStrerror(BareosSocket* bsock) { return bsock->bstrerror(); }
469
470 /**
471 * Format and send a message
472 * Returns: false on error
473 * true on success
474 */
475 bool BnetFsend(BareosSocket* bs, const char* fmt, ...)
476 {
477 va_list arg_ptr;
478 int maxlen;
479
480 if (bs->errors || bs->IsTerminated()) { return false; }
481 /* This probably won't work, but we vsnprintf, then if we
482 * get a negative length or a length greater than our buffer
483 * (depending on which library is used), the printf was truncated, so
484 * get a bigger buffer and try again.
485 */
486 for (;;) {
487 maxlen = SizeofPoolMemory(bs->msg) - 1;
488 va_start(arg_ptr, fmt);
489 bs->message_length = Bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
490 va_end(arg_ptr);
491 if (bs->message_length > 0 && bs->message_length < (maxlen - 5)) { break; }
492 bs->msg = ReallocPoolMemory(bs->msg, maxlen + maxlen / 2);
493 }
494 return bs->send();
495 }
496
497 int BnetGetPeer(BareosSocket* bs, char* buf, socklen_t buflen)
498 {
499 return bs->GetPeer(buf, buflen);
500 }
501
502 /**
503 * Set the network buffer size, suggested size is in size.
504 * Actual size obtained is returned in bs->message_length
505 *
506 * Returns: 0 on failure
507 * 1 on success
508 */
509 bool BnetSetBufferSize(BareosSocket* bs, uint32_t size, int rw)
510 {
511 return bs->SetBufferSize(size, rw);
512 }
513
514 /**
515 * Set socket non-blocking
516 * Returns previous socket flag
517 */
518 int BnetSetNonblocking(BareosSocket* bsock) { return bsock->SetNonblocking(); }
519
520 /**
521 * Set socket blocking
522 * Returns previous socket flags
523 */
524 int BnetSetBlocking(BareosSocket* bsock) { return bsock->SetBlocking(); }
525
526 /**
527 * Restores socket flags
528 */
529 void BnetRestoreBlocking(BareosSocket* bsock, int flags)
530 {
531 bsock->RestoreBlocking(flags);
532 }
533
534 bool BnetSig(BareosSocket* bs, int signal) { return bs->signal(signal); }
535
536 /**
537 * Convert a network "signal" code into
538 * human readable ASCII.
539 */
540
541 /* clang-format off */
542 std::map<int, std::pair<std::string, std::string>> bnet_signal_to_text {
543 {BNET_EOD, {"BNET_EOD", "End of data stream, new data may follow"}},
544 {BNET_EOD_POLL, {"BNET_EOD_POLL", "End of data and poll all in one "}},
545 {BNET_STATUS, {"BNET_STATUS", "Send full status"}},
546 {BNET_TERMINATE, {"BNET_TERMINATE", "Conversation terminated, doing close() "}},
547 {BNET_POLL, {"BNET_POLL", "Poll request, I'm hanging on a read "}},
548 {BNET_HEARTBEAT, {"BNET_HEARTBEAT", "Heartbeat Response requested "}},
549 {BNET_HB_RESPONSE, {"BNET_HB_RESPONSE", "Only response permited to HB "}},
550 {BNET_xxxxxxPROMPT, {"BNET_xxxxxxPROMPT", "No longer used -- Prompt for subcommand "}},
551 {BNET_BTIME, {"BNET_BTIME", "Send UTC btime "}},
552 {BNET_BREAK, {"BNET_BREAK", "Stop current command -- ctl-c "}},
553 {BNET_START_SELECT, {"BNET_START_SELECT", "Start of a selection list "}},
554 {BNET_END_SELECT, {"BNET_END_SELECT", "End of a select list "}},
555 {BNET_INVALID_CMD, {"BNET_INVALID_CMD", "Invalid command sent "}},
556 {BNET_CMD_FAILED, {"BNET_CMD_FAILED", "Command failed "}},
557 {BNET_CMD_OK, {"BNET_CMD_OK", "Command succeeded "}},
558 {BNET_CMD_BEGIN, {"BNET_CMD_BEGIN", "Start command execution "}},
559 {BNET_MSGS_PENDING, {"BNET_MSGS_PENDING", "Messages pending "}},
560 {BNET_MAIN_PROMPT, {"BNET_MAIN_PROMPT", "Server ready and waiting "}},
561 {BNET_SELECT_INPUT, {"BNET_SELECT_INPUT", "Return selection input "}},
562 {BNET_WARNING_MSG, {"BNET_WARNING_MSG", "Warning message "}},
563 {BNET_ERROR_MSG, {"BNET_ERROR_MSG", "Error message -- command failed "}},
564 {BNET_INFO_MSG, {"BNET_INFO_MSG", "Info message -- status line "}},
565 {BNET_RUN_CMD, {"BNET_RUN_CMD", "Run command follows "}},
566 {BNET_YESNO, {"BNET_YESNO", "Request yes no response "}},
567 {BNET_START_RTREE, {"BNET_START_RTREE", "Start restore tree mode "}},
568 {BNET_END_RTREE, {"BNET_END_RTREE", "End restore tree mode "}},
569 {BNET_SUB_PROMPT, {"BNET_SUB_PROMPT", "Indicate we are at a subprompt "}},
570 {BNET_TEXT_INPUT, {"BNET_TEXT_INPUT", "Get text input from user "}},
571 };
572 /* clang-format on */
573
574 std::string BnetSignalToString(int signal)
575 {
576 if (bnet_signal_to_text.find(signal) != bnet_signal_to_text.end()) {
577 return bnet_signal_to_text[signal].first;
578 }
579 return "Unknown sig " + std::to_string(signal);
580 }
581
582 std::string BnetSignalToString(const BareosSocket* bs)
583 {
584 return BnetSignalToString(bs->message_length);
585 }
586
587 std::string BnetSignalToDescription(int signal)
588 {
589 if (bnet_signal_to_text.find(signal) != bnet_signal_to_text.end()) {
590 return bnet_signal_to_text[signal].second;
591 }
592 return "Unknown sig " + std::to_string(signal);
593 }
594
595 bool ReadoutCommandIdFromMessage(const BStringList& list_of_arguments,
596 uint32_t& id_out)
597 {
598 if (list_of_arguments.size() < 1) { return false; }
599
600 uint32_t id = kMessageIdUnknown;
601
602 try { /* "1000 OK: <director name> ..." */
603 const std::string& first_argument = list_of_arguments.front();
604 id = std::stoul(first_argument);
605 } catch (const std::exception& e) {
606 id_out = kMessageIdProtokollError;
607 return false;
608 }
609
610 id_out = id;
611 return true;
612 }
613
614 bool EvaluateResponseMessageId(const std::string& message,
615 uint32_t& id_out,
616 BStringList& args_out)
617 {
618 BStringList list_of_arguments(message,
619 AsciiControlCharacters::RecordSeparator());
620 uint32_t id = kMessageIdUnknown;
621
622 bool ok = ReadoutCommandIdFromMessage(list_of_arguments, id);
623
624 if (ok) { id_out = id; }
625 args_out = list_of_arguments;
626
627 return ok;
628 }
629
630 bool BareosSocket::ReceiveAndEvaluateResponseMessage(uint32_t& id_out,
631 BStringList& args_out)
632 {
633 StartTimer(30); // 30 seconds
634 int ret = recv();
635 StopTimer();
636
637 if (ret <= 0) {
638 Dmsg1(100, "Error while receiving response message: %s", msg);
639 return false;
640 }
641
642 std::string message(msg);
643
644 if (message.empty()) {
645 Dmsg0(100, "Received message is empty\n");
646 return false;
647 }
648
649 return EvaluateResponseMessageId(message, id_out, args_out);
650 }
651
652 bool BareosSocket::FormatAndSendResponseMessage(
653 uint32_t id,
654 const BStringList& list_of_arguments)
655 {
656 std::string m = std::to_string(id);
657 m += AsciiControlCharacters::RecordSeparator();
658 m += list_of_arguments.Join(AsciiControlCharacters::RecordSeparator());
659
660 StartTimer(30); // 30 seconds
661 if (send(m.c_str(), m.size()) <= 0) {
662 Dmsg1(100, "Could not send response message: %d\n", m.c_str());
663 StopTimer();
664 return false;
665 }
666 StopTimer();
667 return true;
668 }
669
670 bool BareosSocket::FormatAndSendResponseMessage(uint32_t id,
671 const std::string& str)
672 {
673 BStringList message;
674 message << str;
675
676 return FormatAndSendResponseMessage(id, message);
677 }
678