]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/bnet.c
Backport from BEE
[bacula/bacula] / bacula / src / lib / bnet.c
index b6775230e0254f06e08854b8a9a481f83bf18110..91fd3970962a3040c87e066be2d4f437dfc729db 100644 (file)
@@ -1,29 +1,17 @@
 /*
    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
@@ -35,6 +23,7 @@
  *
  */
 
+
 #include "bacula.h"
 #include "jcr.h"
 #include <netdb.h>
@@ -62,6 +51,7 @@ static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
  * 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;
@@ -113,6 +103,9 @@ int32_t read_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
       }
       nleft -= nread;
       ptr += nread;
+      if (bsock->use_bwlimit()) {
+         bsock->control_bwlimit(nread);
+      }
    }
    return nbytes - nleft;          /* return >= 0 */
 }
@@ -131,8 +124,8 @@ int32_t write_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
       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;
@@ -196,73 +189,13 @@ int32_t write_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
       }
       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
@@ -273,7 +206,7 @@ bool bnet_tls_server(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
 {
    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"));
@@ -310,7 +243,7 @@ err:
  * 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();
@@ -337,9 +270,11 @@ bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
                                          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;
       }
@@ -368,27 +303,6 @@ bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
 
 #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
@@ -465,7 +379,9 @@ const char *resolv_host(int family, const char *host, dlist *addr_list)
    freeaddrinfo(ai);
    return NULL;
 }
+
 #else
+
 /*
  * Get human readable error for gethostbyname()
  */
@@ -498,12 +414,14 @@ static const char *gethost_strerror()
    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
@@ -516,23 +434,18 @@ static const char *resolv_host(int family, const char *host, dlist *addr_list)
       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);
@@ -611,120 +524,6 @@ dlist *bnet_host2ipaddrs(const char *host, int family, const char **errstr)
    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.
@@ -777,11 +576,7 @@ BSOCK *init_bsock(JCR * jcr, int sockfd, const char *who, const char *host, int
    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;
 }
@@ -805,13 +600,47 @@ BSOCK *dup_bsock(BSOCK *osock)
    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;
 }