/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2014 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.
+ 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 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.
+ 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.
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.
*/
/*
* Network Utility Routines
*
*/
+
#include "bacula.h"
#include "jcr.h"
#include <netdb.h>
* It is possible that the total bytes require in several
* read requests
*/
+
int32_t read_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
{
int32_t nleft, nread;
}
nleft -= nread;
ptr += nread;
+ if (bsock->use_bwlimit()) {
+ bsock->control_bwlimit(nread);
+ }
}
return nbytes - nleft; /* return >= 0 */
}
if (nwritten != nbytes) {
berrno be;
bsock->b_errno = errno;
- Qmsg1(bsock->jcr(), M_FATAL, 0, _("Attr spool write error. ERR=%s\n"),
- be.bstrerror());
+ Qmsg3(bsock->jcr(), M_FATAL, 0, _("Attr spool write error. wrote=%d wanted=%d bytes. ERR=%s\n"),
+ nbytes, nwritten, be.bstrerror());
Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
errno = bsock->b_errno;
return -1;
}
nleft -= nwritten;
ptr += nwritten;
+ if (bsock->use_bwlimit()) {
+ bsock->control_bwlimit(nwritten);
+ }
}
return nbytes - nleft;
}
-/*
- * Receive a message from the other end. Each message consists of
- * two packets. The first is a header that contains the size
- * of the data that follows in the second packet.
- * Returns number of bytes read (may return zero)
- * Returns -1 on signal (BNET_SIGNAL)
- * Returns -2 on hard end of file (BNET_HARDEOF)
- * Returns -3 on error (BNET_ERROR)
- *
- * 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.
- */
-int32_t bnet_recv(BSOCK * bsock)
-{
- return bsock->recv();
-}
-
-
-/*
- * Return 1 if there are errors on this bsock or it is closed,
- * i.e. stop communicating on this line.
- */
-bool is_bnet_stop(BSOCK * bsock)
-{
- return bsock->is_stop();
-}
-
-/*
- * Return number of errors on socket
- */
-int is_bnet_error(BSOCK * bsock)
-{
- return bsock->is_error();
-}
-
-/*
- * Call here after error during closing to suppress error
- * messages which are due to the other end shutting down too.
- */
-void bnet_suppress_error_messages(BSOCK * bsock, bool flag)
-{
- bsock->m_suppress_error_msgs = flag;
-}
-
-/*
- * 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 bnet_send(BSOCK *bsock)
-{
- return bsock->send();
-}
-
-
/*
* Establish a TLS connection -- server side
* Returns: true on success
{
TLS_CONNECTION *tls;
JCR *jcr = bsock->jcr();
-
+
tls = new_tls_connection(ctx, bsock->m_fd);
if (!tls) {
Qmsg0(bsock->jcr(), M_FATAL, 0, _("TLS connection initialization failed.\n"));
* Returns: true on success
* false on failure
*/
-bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
+bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK *bsock, alist *verify_list)
{
TLS_CONNECTION *tls;
JCR *jcr = bsock->jcr();
bsock->host());
goto err;
}
- } else {
- if (!tls_postconnect_verify_host(jcr, tls, bsock->host())) {
- Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS host certificate verification failed. Host name \"%s\" did not match presented certificate\n"),
+ } else if (!tls_postconnect_verify_host(jcr, tls, bsock->host())) {
+ /* If host is 127.0.0.1, try localhost */
+ if (strcmp(bsock->host(), "127.0.0.1") != 0 ||
+ !tls_postconnect_verify_host(jcr, tls, "localhost")) {
+ Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS host certificate verification failed. Host name \"%s\" did not match presented certificate\n"),
bsock->host());
goto err;
}
#endif /* HAVE_TLS */
-/*
- * Wait for a specified time for data to appear on
- * the BSOCK connection.
- *
- * Returns: 1 if data available
- * 0 if timeout
- * -1 if error
- */
-int bnet_wait_data(BSOCK * bsock, int sec)
-{
- return bsock->wait_data(sec);
-}
-
-/*
- * As above, but returns on interrupt
- */
-int bnet_wait_data_intr(BSOCK * bsock, int sec)
-{
- return bsock->wait_data_intr(sec);
-}
-
#ifndef NETDB_INTERNAL
#define NETDB_INTERNAL -1 /* See errno. */
#endif
freeaddrinfo(ai);
return NULL;
}
+
#else
+
/*
* Get human readable error for gethostbyname()
*/
return msg;
}
-static const char *resolv_host(int family, const char *host, dlist *addr_list)
+/*
+ * Note: this is the old way of resolving a host
+ * that does not use the new getaddrinfo() above.
+ */
+static const char *resolv_host(int family, const char *host, dlist * addr_list)
{
struct hostent *hp;
const char *errmsg;
- char **p;
- IPADDR *addr;
P(ip_mutex); /* gethostbyname() is not thread safe */
#ifdef HAVE_GETHOSTBYNAME2
V(ip_mutex);
return errmsg;
} else {
+ char **p;
for (p = hp->h_addr_list; *p != 0; p++) {
- switch (hp->h_addrtype) {
- case AF_INET:
- addr = New(IPADDR(hp->h_addrtype));
- addr->set_type(IPADDR::R_MULTIPLE);
- addr->set_addr4((struct in_addr *)*p);
- break;
+ IPADDR *addr = New(IPADDR(hp->h_addrtype));
+ addr->set_type(IPADDR::R_MULTIPLE);
+ if (addr->get_family() == AF_INET) {
+ addr->set_addr4((struct in_addr*)*p);
+ }
#ifdef HAVE_IPV6
- case AF_INET6:
- addr = New(IPADDR(hp->h_addrtype));
- addr->set_type(IPADDR::R_MULTIPLE);
- addr->set_addr6((struct in6_addr *)*p);
- break;
-#endif
- default:
- continue;
+ else {
+ addr->set_addr6((struct in6_addr*)*p);
}
+#endif
addr_list->append(addr);
}
V(ip_mutex);
return addr_list;
}
-/*
- * This is the "old" way of opening a connection. The preferred way is
- * now to do what this subroutine does, but inline. That allows the
- * connect() call to return error status, ...
- */
-BSOCK *bnet_connect(JCR * jcr, int retry_interval, utime_t max_retry_time,
- utime_t heart_beat,
- const char *name, char *host, char *service, int port,
- int verbose)
-{
- BSOCK *bsock = new_bsock();
- if (!bsock->connect(jcr, retry_interval, max_retry_time, heart_beat,
- name, host, service, port, verbose)) {
- bsock->destroy();
- bsock = NULL;
- }
- return bsock;
-}
-
-/*
- * Return the string for the error that occurred
- * on the socket. Only the first error is retained.
- */
-const char *bnet_strerror(BSOCK * bsock)
-{
- return bsock->bstrerror();
-}
-
-/*
- * Format and send a message
- * Returns: false on error
- * true on success
- */
-bool bnet_fsend(BSOCK * bs, const char *fmt, ...)
-{
- va_list arg_ptr;
- int maxlen;
-
- if (bs->errors || bs->is_terminated()) {
- return false;
- }
- /* This probably won't work, but we vsnprintf, then if we
- * get a negative length or a length greater than our buffer
- * (depending on which library is used), the printf was truncated, so
- * get a bigger buffer and try again.
- */
- for (;;) {
- maxlen = sizeof_pool_memory(bs->msg) - 1;
- va_start(arg_ptr, fmt);
- bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
- va_end(arg_ptr);
- if (bs->msglen > 0 && bs->msglen < (maxlen - 5)) {
- break;
- }
- bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
- }
- return bs->send();
-}
-
-int bnet_get_peer(BSOCK *bs, char *buf, socklen_t buflen)
-{
- return bs->get_peer(buf, buflen);
-}
-
-/*
- * Set the network buffer size, suggested size is in size.
- * Actual size obtained is returned in bs->msglen
- *
- * Returns: 0 on failure
- * 1 on success
- */
-bool bnet_set_buffer_size(BSOCK * bs, uint32_t size, int rw)
-{
- return bs->set_buffer_size(size, rw);
-}
-
-/*
- * Set socket non-blocking
- * Returns previous socket flag
- */
-int bnet_set_nonblocking(BSOCK *bsock)
-{
- return bsock->set_nonblocking();
-}
-
-/*
- * Set socket blocking
- * Returns previous socket flags
- */
-int bnet_set_blocking(BSOCK *bsock)
-{
- return bsock->set_blocking();
-}
-
-/*
- * Restores socket flags
- */
-void bnet_restore_blocking (BSOCK *bsock, int flags)
-{
- bsock->restore_blocking(flags);
-}
-
-/*
- * Send a network "signal" to the other end
- * This consists of sending a negative packet length
- *
- * Returns: false on failure
- * true on success
- */
-bool bnet_sig(BSOCK * bs, int signal)
-{
- return bs->signal(signal);
-}
-
/*
* Convert a network "signal" code into
* human readable ASCII.
bsock->set_port(port);
memset(&bsock->peer_addr, 0, sizeof(bsock->peer_addr));
memcpy(&bsock->client_addr, client_addr, sizeof(bsock->client_addr));
- /*
- * ****FIXME**** reduce this to a few hours once
- * heartbeats are implemented
- */
- bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
+ bsock->timeout = BSOCK_TIMEOUT;
bsock->set_jcr(jcr);
return bsock;
}
return bsock;
}
-/* Close the network connection */
-void bnet_close(BSOCK * bsock)
+int set_socket_errno(int sockstat)
{
- bsock->close();
-}
-
-void term_bsock(BSOCK * bsock)
-{
- bsock->destroy();
+#ifdef HAVE_WIN32
+ /*
+ * For Windows, we must simulate Unix errno on a socket
+ * error in order to handle errors correctly.
+ */
+ if (sockstat == SOCKET_ERROR) {
+ berrno be;
+ DWORD err = WSAGetLastError();
+ if (err == WSAEINTR) {
+ errno = EINTR;
+ return sockstat;
+ } else if (err == WSAEWOULDBLOCK) {
+ errno = EAGAIN;
+ return sockstat;
+ } else {
+ errno = b_errno_win32 | b_errno_WSA;
+ }
+ Dmsg2(20, "Socket error: err=%d %s\n", err, be.bstrerror(err));
+ }
+#else
+ if (sockstat == SOCKET_ERROR) {
+ /* Handle errrors from prior connections as EAGAIN */
+ switch (errno) {
+ case ENETDOWN:
+ case EPROTO:
+ case ENOPROTOOPT:
+ case EHOSTDOWN:
+#ifdef ENONET
+ case ENONET:
+#endif
+ case EHOSTUNREACH:
+ case EOPNOTSUPP:
+ case ENETUNREACH:
+ errno = EAGAIN;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ return sockstat;
}