/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
-
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version three of the GNU Affero General Public
- License as published by the Free Software Foundation and included
- in the file LICENSE.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2015 Kern Sibbald
+ Copyright (C) 2007-2014 Free Software Foundation Europe e.V.
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
* Network Utility Routines
*
- * by Kern Sibbald
+ * Written by Kern Sibbald
*
*/
#include <netdb.h>
#include <netinet/tcp.h>
-#ifndef ENODATA /* not defined on BSD systems */
-#define ENODATA EPIPE
-#endif
-
-#ifdef HAVE_WIN32
-#define socketRead(fd, buf, len) ::recv(fd, buf, len, 0)
-#define socketWrite(fd, buf, len) ::send(fd, buf, len, 0)
-#define socketClose(fd) ::closesocket(fd)
-#else
+#if !defined(ENODATA) /* not defined on BSD systems */
+#define ENODATA EPIPE
+#endif
+
+#if !defined(SOL_TCP) /* Not defined on some systems */
+#define SOL_TCP IPPROTO_TCP
+#endif
+
#define socketRead(fd, buf, len) ::read(fd, buf, len)
#define socketWrite(fd, buf, len) ::write(fd, buf, len)
#define socketClose(fd) ::close(fd)
-#endif
/*
- * This is a non-class BSOCK "constructor" because we want to
+ * This is a non-class BSOCK "constructor" because we want to
* call the Bacula smartalloc routines instead of new.
*/
BSOCK *new_bsock()
void BSOCK::init()
{
memset(this, 0, sizeof(BSOCK));
+ set_closed();
+ set_terminated();
m_blocking = 1;
+ pout_msg_no = &out_msg_no;
msg = get_pool_memory(PM_BSOCK);
errmsg = get_pool_memory(PM_MESSAGE);
- /*
- * ****FIXME**** reduce this to a few hours once
- * heartbeats are implemented
- */
- timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
-}
-
-/*
- * This is our "class destructor" that ensures that we use
- * smartalloc rather than the system free().
- */
-void BSOCK::free_bsock()
-{
- destroy();
+ timeout = BSOCK_TIMEOUT;
}
void BSOCK::free_tls()
{
free_tls_connection(this->tls);
this->tls = NULL;
-}
+}
/*
* Try to connect to host for max_retry_time at retry_time intervals.
if (max_retry_time) {
tid = start_thread_timer(jcr, pthread_self(), (uint32_t)max_retry_time);
}
-
+
for (i = 0; !open(jcr, name, host, service, port, heart_beat, &fatal);
i -= retry_interval) {
berrno be;
if (fatal || (jcr && job_canceled(jcr))) {
goto bail_out;
}
- Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
+ Dmsg4(50, "Unable to connect to %s on %s:%d. ERR=%s\n",
name, host, port, be.bstrerror());
if (i < 0) {
i = 60 * 5; /* complain again in 5 minutes */
return ok;
}
-/*
- * Finish initialization of the pocket structure.
+/*
+ * Finish initialization of the packet structure.
*/
void BSOCK::fin_init(JCR * jcr, int sockfd, const char *who, const char *host, int port,
- struct sockaddr *lclient_addr)
+ struct sockaddr *lclient_addr)
{
Dmsg3(100, "who=%s host=%s port=%d\n", who, host, port);
m_fd = sockfd;
+ if (m_who) {
+ free(m_who);
+ }
+ if (m_host) {
+ free(m_host);
+ }
set_who(bstrdup(who));
set_host(bstrdup(host));
set_port(port);
* Returns BSOCK * pointer on success
*/
bool BSOCK::open(JCR *jcr, const char *name, char *host, char *service,
- int port, utime_t heart_beat, int *fatal)
+ int port, utime_t heart_beat, int *fatal)
{
int sockfd = -1;
dlist *addr_list;
*/
if ((addr_list = bnet_host2ipaddrs(host, 0, &errstr)) == NULL) {
/* Note errstr is not malloc'ed */
- Qmsg2(jcr, M_ERROR, 0, _("bnet_host2ipaddrs() for host \"%s\" failed: ERR=%s\n"),
+ Qmsg2(jcr, M_ERROR, 0, _("gethostbyname() for host \"%s\" failed: ERR=%s\n"),
host, errstr);
Dmsg2(100, "bnet_host2ipaddrs() for host %s failed: ERR=%s\n",
host, errstr);
return false;
}
+ remove_duplicate_addresses(addr_list);
foreach_dlist(ipaddr, addr_list) {
ipaddr->set_port_net(htons(port));
char allbuf[256 * 10];
#endif
default:
*fatal = 1;
- Pmsg3(000, _("Socket open error. proto=%d port=%d. ERR=%s\n"),
+ Qmsg3(jcr, M_ERROR, 0, _("Socket open error. proto=%d port=%d. ERR=%s\n"),
+ ipaddr->get_family(), ipaddr->get_port_host_order(), be.bstrerror());
+ Pmsg3(300, _("Socket open error. proto=%d port=%d. ERR=%s\n"),
ipaddr->get_family(), ipaddr->get_port_host_order(), be.bstrerror());
break;
}
berrno be;
save_errno = errno;
*fatal = 1;
+ Qmsg2(jcr, M_ERROR, 0, _("Source address bind error. proto=%d. ERR=%s\n"),
+ src_addr->get_family(), be.bstrerror() );
Pmsg2(000, _("Source address bind error. proto=%d. ERR=%s\n"),
src_addr->get_family(), be.bstrerror() );
+ if (sockfd >= 0) socketClose(sockfd);
continue;
}
}
/* connect to server */
if (::connect(sockfd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) < 0) {
save_errno = errno;
- socketClose(sockfd);
+ if (sockfd >= 0) socketClose(sockfd);
continue;
}
*fatal = 0;
}
if (!connected) {
+ berrno be;
free_addresses(addr_list);
errno = save_errno | b_errno_win32;
+ Dmsg4(50, "Could not connect to server %s %s:%d. ERR=%s\n",
+ name, host, port, be.bstrerror());
return false;
}
/*
}
fin_init(jcr, sockfd, name, host, port, ipaddr->get_sockaddr());
free_addresses(addr_list);
+
+ /* Clean the packet a bit */
+ m_closed = false;
+ m_duped = false;
+ m_spool = false;
+ m_use_locking = false;
+ m_timed_out = false;
+ m_terminated = false;
+ m_suppress_error_msgs = false;
+ errors = 0;
+ m_blocking = 0;
+
+ Dmsg3(50, "OK connected to server %s %s:%d.\n",
+ name, host, port);
+
return true;
}
if (m_use_locking) {
return true; /* already set */
}
- if ((stat = pthread_mutex_init(&m_mutex, NULL)) != 0) {
+ pm_rmutex = &m_rmutex;
+ pm_wmutex = &m_wmutex;
+ if ((stat = pthread_mutex_init(pm_rmutex, NULL)) != 0) {
berrno be;
- Qmsg(m_jcr, M_FATAL, 0, _("Could not init bsock mutex. ERR=%s\n"),
+ Qmsg(m_jcr, M_FATAL, 0, _("Could not init bsock read mutex. ERR=%s\n"),
+ be.bstrerror(stat));
+ return false;
+ }
+ if ((stat = pthread_mutex_init(pm_wmutex, NULL)) != 0) {
+ berrno be;
+ Qmsg(m_jcr, M_FATAL, 0, _("Could not init bsock write mutex. ERR=%s\n"),
be.bstrerror(stat));
return false;
}
void BSOCK::clear_locking()
{
- if (!m_use_locking) {
+ if (!m_use_locking || m_duped) {
return;
}
m_use_locking = false;
- pthread_mutex_destroy(&m_mutex);
+ pthread_mutex_destroy(pm_rmutex);
+ pthread_mutex_destroy(pm_wmutex);
+ pm_rmutex = NULL;
+ pm_wmutex = NULL;
return;
}
/*
- * Send a message over the network. The send consists of
- * two network packets. The first is sends a 32 bit integer containing
- * the length of the data packet which follows.
*
* Returns: false on failure
* true on success
*/
-bool BSOCK::send()
+bool BSOCK::send(int aflags)
{
int32_t rc;
int32_t pktsiz;
- int32_t *hdr;
+ int32_t *hdrptr;
+ int hdrsiz;
bool ok = true;
+ int32_t save_msglen;
+ POOLMEM *save_msg;
+ bool locked = false;
+ if (is_closed()) {
+ if (!m_suppress_error_msgs) {
+ Qmsg0(m_jcr, M_ERROR, 0, _("Socket is closed\n"));
+ }
+ return false;
+ }
if (errors) {
if (!m_suppress_error_msgs) {
Qmsg4(m_jcr, M_ERROR, 0, _("Socket has errors=%d on call to %s:%s:%d\n"),
}
return false;
}
+
if (msglen > 4000000) {
if (!m_suppress_error_msgs) {
Qmsg4(m_jcr, M_ERROR, 0,
return false;
}
- if (m_use_locking) P(m_mutex);
+ if (m_use_locking) {
+ pP(pm_wmutex);
+ locked = true;
+ }
+ save_msglen = msglen;
+ save_msg = msg;
+ m_flags = aflags;
+
/* Compute total packet length */
if (msglen <= 0) {
- pktsiz = sizeof(pktsiz); /* signal, no data */
+ hdrsiz = sizeof(pktsiz);
+ pktsiz = hdrsiz; /* signal, no data */
+ } else if (m_flags) {
+ hdrsiz = 2 * sizeof(pktsiz); /* have 64 bit header */
+ pktsiz = msglen + hdrsiz;
} else {
- pktsiz = msglen + sizeof(pktsiz); /* data */
+ hdrsiz = sizeof(pktsiz); /* have 32 bit header */
+ pktsiz = msglen + hdrsiz;
}
- /* Store packet length at head of message -- note, we
+
+ /*
+ * Store packet length at head of message -- note, we
* have reserved an int32_t just before msg, so we can
- * store there
+ * store there
*/
- hdr = (int32_t *)(msg - (int)sizeof(pktsiz));
- *hdr = htonl(msglen); /* store signal/length */
+ hdrptr = (int32_t *)(msg - hdrsiz);
+ *hdrptr = htonl(msglen); /* store signal/length */
+ if (m_flags) {
+ *(hdrptr+1) = htonl(m_flags); /* store flags */
+ }
- out_msg_no++; /* increment message number */
+ (*pout_msg_no)++; /* increment message number */
/* send data packet */
timer_start = watchdog_time; /* start timer */
clear_timed_out();
/* Full I/O done in one write */
- rc = write_nbytes(this, (char *)hdr, pktsiz);
+ rc = write_nbytes(this, (char *)hdrptr, pktsiz);
+// if (chk_dbglvl(DT_NETWORK|1900)) dump_bsock_msg(m_fd, *pout_msg_no, "SEND", rc, msglen, m_flags, save_msg, save_msglen);
timer_start = 0; /* clear timer */
if (rc != pktsiz) {
errors++;
if (rc < 0) {
if (!m_suppress_error_msgs) {
Qmsg5(m_jcr, M_ERROR, 0,
- _("Write error sending %d bytes to %s:%s:%d: ERR=%s\n"),
- msglen, m_who,
+ _("Write error sending %d bytes to %s:%s:%d: ERR=%s\n"),
+ pktsiz, m_who,
m_host, m_port, this->bstrerror());
}
} else {
Qmsg5(m_jcr, M_ERROR, 0,
_("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
- msglen, m_who, m_host, m_port, rc);
+ pktsiz, m_who, m_host, m_port, rc);
}
ok = false;
}
- if (m_use_locking) V(m_mutex);
+ msglen = save_msglen;
+ msg = save_msg;
+ if (locked) pV(pm_wmutex);
return ok;
}
va_list arg_ptr;
int maxlen;
- if (errors || is_terminated()) {
+ if (errors || is_terminated() || is_closed()) {
return false;
}
/* This probably won't work, but we vsnprintf, then if we
* Returns -1 on signal (BNET_SIGNAL)
* Returns -2 on hard end of file (BNET_HARDEOF)
* Returns -3 on error (BNET_ERROR)
- *
+ * Returns -4 on COMMAND (BNET_COMMAND)
* Unfortunately, it is a bit complicated because we have these
* four return types:
* 1. Normal data
* 2. Signal including end of data stream
* 3. Hard end of file
* 4. Error
- * Using is_bnet_stop() and is_bnet_error() you can figure this all out.
+ * Using bsock->is_stop() and bsock->is_error() you can figure this all out.
*/
int32_t BSOCK::recv()
{
int32_t nbytes;
int32_t pktsiz;
+ bool locked = false;
msg[0] = 0;
msglen = 0;
- if (errors || is_terminated()) {
+ m_flags = 0;
+ if (errors || is_terminated() || is_closed()) {
return BNET_HARDEOF;
}
+ if (m_use_locking) {
+ pP(pm_rmutex);
+ locked = true;
+ }
- if (m_use_locking) P(m_mutex);
read_seqno++; /* bump sequence number */
timer_start = watchdog_time; /* set start wait time */
clear_timed_out();
/* If signal or packet size too big */
if (pktsiz < 0 || pktsiz > 1000000) {
if (pktsiz > 0) { /* if packet too big */
- Qmsg3(m_jcr, M_FATAL, 0,
- _("Packet size too big from \"%s:%s:%d. Terminating connection.\n"),
- m_who, m_host, m_port);
+ Qmsg4(m_jcr, M_FATAL, 0,
+ _("Packet size=%d too big from \"%s:%s:%d. Terminating connection.\n"),
+ pktsiz, m_who, m_host, m_port);
pktsiz = BNET_TERMINATE; /* hang up */
}
if (pktsiz == BNET_TERMINATE) {
nbytes = BNET_ERROR;
goto get_out;
}
+
/* always add a zero by to properly terminate any
* string that was send to us. Note, we ensured above that the
* buffer is at least one byte longer than the message length.
*/
msg[nbytes] = 0; /* terminate in case it is a string */
/*
- * The following uses *lots* of resources so turn it on only for
+ * The following uses *lots* of resources so turn it on only for
* serious debugging.
*/
Dsm_check(300);
get_out:
- if (m_use_locking) V(m_mutex);
+// if ((chk_dbglvl(DT_NETWORK|1900))) dump_bsock_msg(m_fd, read_seqno, "RECV", nbytes, o_pktsiz, m_flags, msg, msglen);
+
+ if (locked) pV(pm_rmutex);
return nbytes; /* return actual length of message */
}
return send();
}
-/*
+/*
* Despool spooled attributes
*/
bool BSOCK::despool(void update_attr_spool_size(ssize_t size), ssize_t tsize)
if (nbytes != (size_t)msglen) {
berrno be;
Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, msglen);
- Qmsg1(get_jcr(), M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
- be.bstrerror());
+ Qmsg2(get_jcr(), M_FATAL, 0, _("fread attr spool error. Wanted=%d got=%d bytes.\n"),
+ msglen, nbytes);
update_attr_spool_size(tsize - last);
return false;
}
if (errmsg == NULL) {
errmsg = get_pool_memory(PM_MESSAGE);
}
- pm_strcpy(errmsg, be.bstrerror(b_errno));
+ if (b_errno == 0) {
+ pm_strcpy(errmsg, "I/O Error");
+ } else {
+ pm_strcpy(errmsg, be.bstrerror(b_errno));
+ }
return errmsg;
}
-int BSOCK::get_peer(char *buf, socklen_t buflen)
+int BSOCK::get_peer(char *buf, socklen_t buflen)
{
-#if !defined(HAVE_WIN32)
if (peer_addr.sin_family == 0) {
socklen_t salen = sizeof(peer_addr);
int rval = (getpeername)(m_fd, (struct sockaddr *)&peer_addr, &salen);
return -1;
return 0;
-#else
- return -1;
-#endif
}
/*
#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
int opt;
opt = IPTOS_THROUGHPUT;
- setsockopt(fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
+ setsockopt(m_fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
#endif
if (size != 0) {
Qmsg1(get_jcr(), M_WARNING, 0,
_("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
}
- if (dbuf_size % TAPE_BSIZE != 0) {
- Qmsg1(get_jcr(), M_ABORT, 0,
- _("Network buffer size %d not multiple of tape block size.\n"),
- dbuf_size);
- }
}
if (size != 0) {
dbuf_size = size;
Qmsg1(get_jcr(), M_WARNING, 0,
_("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
}
- if (dbuf_size % TAPE_BSIZE != 0) {
- Qmsg1(get_jcr(), M_ABORT, 0,
- _("Network buffer size %d not multiple of tape block size.\n"),
- dbuf_size);
- }
}
msglen = dbuf_size;
*/
int BSOCK::set_nonblocking()
{
-#ifndef HAVE_WIN32
int oflags;
/* Get current flags */
m_blocking = 0;
return oflags;
-#else
- int flags;
- u_long ioctlArg = 1;
-
- flags = m_blocking;
- ioctlsocket(m_fd, FIONBIO, &ioctlArg);
- m_blocking = 0;
-
- return flags;
-#endif
}
/*
*/
int BSOCK::set_blocking()
{
-#ifndef HAVE_WIN32
int oflags;
/* Get current flags */
if ((oflags = fcntl(m_fd, F_GETFL, 0)) < 0) {
m_blocking = 1;
return oflags;
-#else
- int flags;
- u_long ioctlArg = 0;
-
- flags = m_blocking;
- ioctlsocket(m_fd, FIONBIO, &ioctlArg);
- m_blocking = 1;
-
- return flags;
-#endif
}
void BSOCK::set_killable(bool killable)
/*
* Restores socket flags
*/
-void BSOCK::restore_blocking (int flags)
+void BSOCK::restore_blocking (int flags)
{
-#ifndef HAVE_WIN32
if ((fcntl(m_fd, F_SETFL, flags)) < 0) {
berrno be;
Qmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
}
m_blocking = (flags & O_NONBLOCK) ? true : false;
-#else
- u_long ioctlArg = flags;
-
- ioctlsocket(m_fd, FIONBIO, &ioctlArg);
- m_blocking = 1;
-#endif
}
/*
return -1; /* error return */
default:
b_errno = 0;
+#ifdef HAVE_TLS
+ if (this->tls && !tls_bsock_probe(this)) {
+ continue; /* false alarm, maybe a session key negotiation in progress on the socket */
+ }
+#endif
return 1;
}
}
return -1; /* error return */
default:
b_errno = 0;
+#ifdef HAVE_TLS
+ if (this->tls && !tls_bsock_probe(this)) {
+ /* maybe a session key negotiation waked up the socket */
+ return 0;
+ }
+#endif
break;
}
return 1;
}
/*
- * Note, this routine closes and destroys all the sockets
- * that are open including the duped ones.
+ * This routine closes the current BSOCK.
+ * It does not delete the socket packet
+ * resources, which are released int
+ * bsock->destroy().
*/
#ifndef SHUT_RDWR
#define SHUT_RDWR 2
#endif
+/*
+ * Note, this routine closes the socket, but leaves the
+ * bsock memory in place.
+ */
void BSOCK::close()
{
BSOCK *bsock = this;
BSOCK *next;
+ if (bsock->is_closed()) {
+ return;
+ }
if (!m_duped) {
clear_locking();
}
for (; bsock; bsock = next) {
next = bsock->m_next; /* get possible pointer to next before destoryed */
+ bsock->set_closed();
+ bsock->set_terminated();
if (!bsock->m_duped) {
/* Shutdown tls cleanly. */
if (bsock->tls) {
free_tls_connection(bsock->tls);
bsock->tls = NULL;
}
+
if (bsock->is_timed_out()) {
shutdown(bsock->m_fd, SHUT_RDWR); /* discard any pending I/O */
}
+ /* On Windows this discards data if we did not do a close_wait() */
socketClose(bsock->m_fd); /* normal close */
}
- bsock->destroy();
}
return;
}
+/*
+ * Destroy the socket (i.e. release all resources)
+ * including and duped sockets.
+ */
void BSOCK::destroy()
{
+ this->close(); /* Ensure that socket is closed */
+
if (msg) {
free_pool_memory(msg);
msg = NULL;
} else {
- ASSERT(1 == 0); /* double close */
+ ASSERT2(1 == 0, "Two calls to destroy socket"); /* double destroy */
}
if (errmsg) {
free_pool_memory(errmsg);
if (src_addr) {
free(src_addr);
src_addr = NULL;
- }
+ }
+ if (m_next) {
+ m_next->destroy();
+ }
free(this);
}
* Authenticate Director
*/
bool BSOCK::authenticate_director(const char *name, const char *password,
- TLS_CONTEXT *tls_ctx, char *response, int response_len)
+ TLS_CONTEXT *tls_ctx, char *errmsg, int errmsg_len)
{
int tls_local_need = BNET_TLS_NONE;
int tls_remote_need = BNET_TLS_NONE;
char bashed_name[MAX_NAME_LENGTH];
BSOCK *dir = this; /* for readability */
- response[0] = 0;
+ *errmsg = 0;
/*
* Send my name to the Director then do authentication
*/
if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) ||
/* Now challenge dir */
!cram_md5_challenge(dir, password, tls_local_need, compatible)) {
- bsnprintf(response, response_len, _("Director authorization problem at \"%s:%d\"\n"),
+ bsnprintf(errmsg, errmsg_len, _("Director authorization error at \"%s:%d\"\n"),
dir->host(), dir->port());
goto bail_out;
}
/* Verify that the remote host is willing to meet our TLS requirements */
if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
- bsnprintf(response, response_len, _("Authorization problem:"
+ bsnprintf(errmsg, errmsg_len, _("Authorization error:"
" Remote server at \"%s:%d\" did not advertise required TLS support.\n"),
dir->host(), dir->port());
goto bail_out;
/* Verify that we are willing to meet the remote host's requirements */
if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
- bsnprintf(response, response_len, _("Authorization problem with Director at \"%s:%d\":"
+ bsnprintf(errmsg, errmsg_len, _("Authorization error with Director at \"%s:%d\":"
" Remote server requires TLS.\n"),
dir->host(), dir->port());
if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
/* Engage TLS! Full Speed Ahead! */
if (!bnet_tls_client(tls_ctx, dir, NULL)) {
- bsnprintf(response, response_len, _("TLS negotiation failed with Director at \"%s:%d\"\n"),
+ bsnprintf(errmsg, errmsg_len, _("TLS negotiation failed with Director at \"%s:%d\"\n"),
dir->host(), dir->port());
goto bail_out;
}
Dmsg1(6, ">dird: %s", dir->msg);
if (dir->recv() <= 0) {
dir->stop_timer();
- bsnprintf(response, response_len, _("Bad response to Hello command: ERR=%s\n"
- "The Director at \"%s:%d\" is probably not running.\n"),
+ bsnprintf(errmsg, errmsg_len, _("Bad errmsg to Hello command: ERR=%s\n"
+ "The Director at \"%s:%d\" may not be running.\n"),
dir->bstrerror(), dir->host(), dir->port());
return false;
}
dir->stop_timer();
Dmsg1(10, "<dird: %s", dir->msg);
if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) {
- bsnprintf(response, response_len, _("Director at \"%s:%d\" rejected Hello command\n"),
+ bsnprintf(errmsg, errmsg_len, _("Director at \"%s:%d\" rejected Hello command\n"),
dir->host(), dir->port());
return false;
} else {
- bsnprintf(response, response_len, "%s", dir->msg);
+ bsnprintf(errmsg, errmsg_len, "%s", dir->msg);
}
return true;
bail_out:
dir->stop_timer();
- bsnprintf(response, response_len, _("Authorization problem with Director at \"%s:%d\"\n"
+ bsnprintf(errmsg, errmsg_len, _("Authorization error with Director at \"%s:%d\"\n"
"Most likely the passwords do not agree.\n"
"If you are using TLS, there may have been a certificate validation error during the TLS handshake.\n"
- "Please see " MANUAL_AUTH_URL " for help.\n"),
+ "For help, please see: " MANUAL_AUTH_URL "\n"),
dir->host(), dir->port());
return false;
}
+
+/* Try to limit the bandwidth of a network connection
+ */
+void BSOCK::control_bwlimit(int bytes)
+{
+ btime_t now, temp;
+ if (bytes == 0) {
+ return;
+ }
+
+ now = get_current_btime(); /* microseconds */
+ temp = now - m_last_tick; /* microseconds */
+
+ m_nb_bytes += bytes;
+
+ if (temp < 0 || temp > 10000000) { /* Take care of clock problems (>10s) or back in time */
+ m_nb_bytes = bytes;
+ m_last_tick = now;
+ return;
+ }
+
+ /* Less than 0.1ms since the last call, see the next time */
+ if (temp < 100) {
+ return;
+ }
+
+ /* Remove what was authorised to be written in temp us */
+ m_nb_bytes -= (int64_t)(temp * ((double)m_bwlimit / 1000000.0));
+
+ if (m_nb_bytes < 0) {
+ m_nb_bytes = 0;
+ }
+
+ /* What exceed should be converted in sleep time */
+ int64_t usec_sleep = (int64_t)(m_nb_bytes /((double)m_bwlimit / 1000000.0));
+ if (usec_sleep > 100) {
+ bmicrosleep(0, usec_sleep); /* TODO: Check that bmicrosleep slept enough or sleep again */
+ m_last_tick = get_current_btime();
+ m_nb_bytes = 0;
+ } else {
+ m_last_tick = now;
+ }
+}