]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/bsock.c
update version
[bacula/bacula] / bacula / src / lib / bsock.c
index 18b3019a01a6309a572b6ef16261bd6c1d015a84..cc3231b2c0ae02541c932ab1e0a5ab807b488984 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
+   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 two of the GNU General Public
+   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.
 
@@ -15,7 +15,7 @@
    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 General Public License
+   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.
  *
  *  by Kern Sibbald
  *
- *   Version $Id: $
  */
 
-
 #include "bacula.h"
 #include "jcr.h"
 #include <netdb.h>
@@ -67,7 +65,7 @@ void BSOCK::init()
 {
    memset(this, 0, sizeof(BSOCK));
    m_blocking = 1;
-   msg = get_pool_memory(PM_MESSAGE);
+   msg = get_pool_memory(PM_BSOCK);
    errmsg = get_pool_memory(PM_MESSAGE);
    /*
     * ****FIXME**** reduce this to a few hours once
@@ -145,12 +143,11 @@ bail_out:
    return ok;
 }
 
-
 /*       
  * Finish initialization of the pocket 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;
@@ -161,14 +158,32 @@ void BSOCK::fin_init(JCR * jcr, int sockfd, const char *who, const char *host, i
    set_jcr(jcr);
 }
 
+/*
+ * Copy the address from the configuration dlist that gets passed in
+ */
+void BSOCK::set_source_address(dlist *src_addr_list)
+{
+   IPADDR *addr = NULL;
+
+   // delete the object we already have, if it's allocated
+   if (src_addr) {
+     free( src_addr);
+     src_addr = NULL;
+   }
+
+   if (src_addr_list) {
+     addr = (IPADDR*) src_addr_list->first();
+     src_addr = New( IPADDR(*addr));
+   }
+}
+
 /*
  * Open a TCP connection to the server
  * Returns NULL
  * 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;
@@ -208,6 +223,19 @@ bool BSOCK::open(JCR *jcr, const char *name, char *host, char *service,
             ipaddr->get_family(), ipaddr->get_port_host_order(), be.bstrerror());
          continue;
       }
+
+      /* Bind to the source address if it is set */
+      if (src_addr) {
+         if (bind(sockfd, src_addr->get_sockaddr(), src_addr->get_sockaddr_len()) < 0) {
+            berrno be;
+            save_errno = errno;
+            *fatal = 1;
+            Pmsg2(000, _("Source address bind error. proto=%d. ERR=%s\n"),
+                  src_addr->get_family(), be.bstrerror() );
+            continue;
+         }
+      }
+
       /*
        * Keep socket from timing out from inactivity
        */
@@ -268,7 +296,7 @@ bool BSOCK::set_locking()
    }
    if ((stat = pthread_mutex_init(&m_mutex, NULL)) != 0) {
       berrno be;
-      Jmsg(m_jcr, M_FATAL, 0, _("Could not init bsock mutex. ERR=%s\n"),
+      Qmsg(m_jcr, M_FATAL, 0, _("Could not init bsock mutex. ERR=%s\n"),
          be.bstrerror(stat));
       return false;
    }
@@ -301,9 +329,29 @@ bool BSOCK::send()
    int32_t *hdr;
    bool ok = true;
 
-   if (errors || is_terminated() || msglen > 1000000) {
+   if (errors) {
+      if (!m_suppress_error_msgs) {
+         Qmsg4(m_jcr, M_ERROR, 0,  _("Socket has errors=%d on call to %s:%s:%d\n"),
+             errors, m_who, m_host, m_port);
+      }
+      return false;
+   }
+   if (is_terminated()) {
+      if (!m_suppress_error_msgs) {
+         Qmsg4(m_jcr, M_ERROR, 0,  _("Socket is terminated=%d on call to %s:%s:%d\n"),
+             is_terminated(), m_who, m_host, m_port);
+      }
+      return false;
+   }
+   if (msglen > 4000000) {
+      if (!m_suppress_error_msgs) {
+         Qmsg4(m_jcr, M_ERROR, 0,
+            _("Socket has insane msglen=%d on call to %s:%s:%d\n"),
+             msglen, m_who, m_host, m_port);
+      }
       return false;
    }
+
    if (m_use_locking) P(m_mutex);
    /* Compute total packet length */
    if (msglen <= 0) {
@@ -502,14 +550,17 @@ int32_t BSOCK::recv()
     * buffer is at least one byte longer than the message length.
     */
    msg[nbytes] = 0; /* terminate in case it is a string */
-   sm_check(__FILE__, __LINE__, false);
+   /*
+    * 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);
    return nbytes;                  /* return actual length of message */
 }
 
-
 /*
  * Send a signal
  */
@@ -531,6 +582,7 @@ bool BSOCK::despool(void update_attr_spool_size(ssize_t size), ssize_t tsize)
    size_t nbytes;
    ssize_t last = 0, size = 0;
    int count = 0;
+   JCR *jcr = get_jcr();
 
    rewind(m_spool_fd);
 
@@ -543,11 +595,11 @@ bool BSOCK::despool(void update_attr_spool_size(ssize_t size), ssize_t tsize)
       size += sizeof(int32_t);
       msglen = ntohl(pktsiz);
       if (msglen > 0) {
-         if (msglen > (int32_t) sizeof_pool_memory(msg)) {
+         if (msglen > (int32_t)sizeof_pool_memory(msg)) {
             msg = realloc_pool_memory(msg, msglen + 1);
          }
          nbytes = fread(msg, 1, msglen, m_spool_fd);
-         if (nbytes != (size_t) msglen) {
+         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"),
@@ -562,12 +614,13 @@ bool BSOCK::despool(void update_attr_spool_size(ssize_t size), ssize_t tsize)
          }
       }
       send();
+      if (jcr && job_canceled(jcr)) {
+         return false;
+      }
    }
    update_attr_spool_size(tsize - last);
    if (ferror(m_spool_fd)) {
-      berrno be;
-      Qmsg1(get_jcr(), M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
-            be.bstrerror());
+      Qmsg(jcr, M_FATAL, 0, _("fread attr spool I/O error.\n"));
       return false;
    }
    return true;
@@ -614,6 +667,7 @@ int BSOCK::get_peer(char *buf, socklen_t buflen)
 bool BSOCK::set_buffer_size(uint32_t size, int rw)
 {
    uint32_t dbuf_size, start_size;
+
 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
    int opt;
    opt = IPTOS_THROUGHPUT;
@@ -630,6 +684,17 @@ bool BSOCK::set_buffer_size(uint32_t size, int rw)
       Qmsg0(get_jcr(), M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
       return false;
    }
+
+   /*
+    * If user has not set the size, use the OS default -- i.e. do not
+    *   try to set it.  This allows sys admins to set the size they
+    *   want in the OS, and Bacula will comply. See bug #1493
+    */
+   if (size == 0) {
+      msglen = dbuf_size;
+      return true;
+   }
+
    if (rw & BNET_SETBUF_READ) {
       while ((dbuf_size > TAPE_BSIZE) && (setsockopt(m_fd, SOL_SOCKET,
               SO_RCVBUF, (sockopt_val_t) & dbuf_size, sizeof(dbuf_size)) < 0)) {
@@ -689,13 +754,13 @@ int BSOCK::set_nonblocking()
    /* Get current flags */
    if ((oflags = fcntl(m_fd, F_GETFL, 0)) < 0) {
       berrno be;
-      Jmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_GETFL error. ERR=%s\n"), be.bstrerror());
+      Qmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_GETFL error. ERR=%s\n"), be.bstrerror());
    }
 
    /* Set O_NONBLOCK flag */
    if ((fcntl(m_fd, F_SETFL, oflags|O_NONBLOCK)) < 0) {
       berrno be;
-      Jmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
+      Qmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
    }
 
    m_blocking = 0;
@@ -723,13 +788,13 @@ int BSOCK::set_blocking()
    /* Get current flags */
    if ((oflags = fcntl(m_fd, F_GETFL, 0)) < 0) {
       berrno be;
-      Jmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_GETFL error. ERR=%s\n"), be.bstrerror());
+      Qmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_GETFL error. ERR=%s\n"), be.bstrerror());
    }
 
    /* Set O_NONBLOCK flag */
    if ((fcntl(m_fd, F_SETFL, oflags & ~O_NONBLOCK)) < 0) {
       berrno be;
-      Jmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
+      Qmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
    }
 
    m_blocking = 1;
@@ -754,7 +819,7 @@ void BSOCK::restore_blocking (int flags)
 #ifndef HAVE_WIN32
    if ((fcntl(m_fd, F_SETFL, flags)) < 0) {
       berrno be;
-      Jmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
+      Qmsg1(get_jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
    }
 
    m_blocking = (flags & O_NONBLOCK) ? true : false;
@@ -774,7 +839,7 @@ void BSOCK::restore_blocking (int flags)
  *            0 if timeout
  *           -1 if error
  */
-int BSOCK::wait_data(int sec)
+int BSOCK::wait_data(int sec, int usec)
 {
    fd_set fdset;
    struct timeval tv;
@@ -783,7 +848,7 @@ int BSOCK::wait_data(int sec)
    FD_SET((unsigned)m_fd, &fdset);
    for (;;) {
       tv.tv_sec = sec;
-      tv.tv_usec = 0;
+      tv.tv_usec = usec;
       switch (select(m_fd + 1, &fdset, NULL, NULL, &tv)) {
       case 0:                      /* timeout */
          b_errno = 0;
@@ -804,15 +869,18 @@ int BSOCK::wait_data(int sec)
 /*
  * As above, but returns on interrupt
  */
-int BSOCK::wait_data_intr(int sec)
+int BSOCK::wait_data_intr(int sec, int usec)
 {
    fd_set fdset;
    struct timeval tv;
 
+   if (this == NULL) {
+      return -1;
+   }
    FD_ZERO(&fdset);
    FD_SET((unsigned)m_fd, &fdset);
    tv.tv_sec = sec;
-   tv.tv_usec = 0;
+   tv.tv_usec = usec;
    switch (select(m_fd + 1, &fdset, NULL, NULL, &tv)) {
    case 0:                      /* timeout */
       b_errno = 0;
@@ -882,6 +950,10 @@ void BSOCK::destroy()
       free(m_host);
       m_host = NULL;
    }
+   if (src_addr) {
+      free(src_addr);
+      src_addr = NULL;
+   } 
    free(this);
 }
 
@@ -895,7 +967,7 @@ static char OKhello[]   = "1000 OK:";
  * Authenticate Director
  */
 bool BSOCK::authenticate_director(const char *name, const char *password,
-               TLS_CONTEXT *tls_ctx, char *msg, int msglen)
+                                  TLS_CONTEXT *tls_ctx, char *response, int response_len)
 {
    int tls_local_need = BNET_TLS_NONE;
    int tls_remote_need = BNET_TLS_NONE;
@@ -903,7 +975,7 @@ bool BSOCK::authenticate_director(const char *name, const char *password,
    char bashed_name[MAX_NAME_LENGTH];
    BSOCK *dir = this;        /* for readability */
 
-   msg[0] = 0;
+   response[0] = 0;
    /*
     * Send my name to the Director then do authentication
     */
@@ -920,14 +992,14 @@ bool BSOCK::authenticate_director(const char *name, const char *password,
    if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) ||
        /* Now challenge dir */
        !cram_md5_challenge(dir, password, tls_local_need, compatible)) {
-      bsnprintf(msg, msglen, _("Director authorization problem at \"%s:%d\"\n"),
+      bsnprintf(response, response_len, _("Director authorization problem 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(msg, msglen, _("Authorization problem:"
+      bsnprintf(response, response_len, _("Authorization problem:"
              " Remote server at \"%s:%d\" did not advertise required TLS support.\n"),
              dir->host(), dir->port());
       goto bail_out;
@@ -935,7 +1007,7 @@ bool BSOCK::authenticate_director(const char *name, const char *password,
 
    /* 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(msg, msglen, _("Authorization problem with Director at \"%s:%d\":"
+      bsnprintf(response, response_len, _("Authorization problem with Director at \"%s:%d\":"
                      " Remote server requires TLS.\n"),
                      dir->host(), dir->port());
 
@@ -947,7 +1019,7 @@ bool BSOCK::authenticate_director(const char *name, const char *password,
       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(msg, msglen, _("TLS negotiation failed with Director at \"%s:%d\"\n"),
+            bsnprintf(response, response_len, _("TLS negotiation failed with Director at \"%s:%d\"\n"),
                dir->host(), dir->port());
             goto bail_out;
          }
@@ -957,7 +1029,7 @@ bool BSOCK::authenticate_director(const char *name, const char *password,
    Dmsg1(6, ">dird: %s", dir->msg);
    if (dir->recv() <= 0) {
       dir->stop_timer();
-      bsnprintf(msg, msglen, _("Bad response to Hello command: ERR=%s\n"
+      bsnprintf(response, response_len, _("Bad response to Hello command: ERR=%s\n"
                       "The Director at \"%s:%d\" is probably not running.\n"),
                     dir->bstrerror(), dir->host(), dir->port());
       return false;
@@ -966,20 +1038,20 @@ bool BSOCK::authenticate_director(const char *name, const char *password,
   dir->stop_timer();
    Dmsg1(10, "<dird: %s", dir->msg);
    if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) {
-      bsnprintf(msg, msglen, _("Director at \"%s:%d\" rejected Hello command\n"),
+      bsnprintf(response, response_len, _("Director at \"%s:%d\" rejected Hello command\n"),
          dir->host(), dir->port());
       return false;
    } else {
-      bsnprintf(msg, msglen, "%s", dir->msg);
+      bsnprintf(response, response_len, "%s", dir->msg);
    }
    return true;
 
 bail_out:
    dir->stop_timer();
-   bsnprintf(msg, msglen, _("Authorization problem with Director at \"%s:%d\"\n"
+   bsnprintf(response, response_len, _("Authorization problem 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 http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n"), 
+             "Please see " MANUAL_AUTH_URL " for help.\n"),
              dir->host(), dir->port());
    return false;
 }