]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/bsock.c
kes Begin implementing new comm signals for API.
[bacula/bacula] / bacula / src / lib / bsock.c
index b290240662dd6e2bd89d88da12ab905dc62b3292..8567f37fdda59f5865f11fcaa175f1f7e856468b 100644 (file)
 #include "jcr.h"
 #include <netdb.h>
 
+#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
+#define socketRead(fd, buf, len)  ::read(fd, buf, len)
+#define socketWrite(fd, buf, len) ::write(fd, buf, len)
+#define socketClose(fd)           ::close(fd)
+#endif
+
 /*
  * Send a message over the network. The send consists of
  * two network packets. The first is sends a 32 bit integer containing
@@ -85,15 +95,15 @@ bool BSOCK::send()
       }
       if (rc < 0) {
          if (!suppress_error_msgs) {
-            Qmsg5(jcr, M_ERROR, 0,
+            Qmsg5(m_jcr, M_ERROR, 0,
                   _("Write error sending %d bytes to %s:%s:%d: ERR=%s\n"), 
-                  msglen, who,
-                  host, port, bnet_strerror(this));
+                  msglen, m_who,
+                  m_host, m_port, bnet_strerror(this));
          }
       } else {
-         Qmsg5(jcr, M_ERROR, 0,
+         Qmsg5(m_jcr, M_ERROR, 0,
                _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
-               msglen, who, host, port, rc);
+               msglen, m_who, m_host, m_port, rc);
       }
       return false;
    }
@@ -131,6 +141,124 @@ bool BSOCK::fsend(const char *fmt, ...)
    return send();
 }
 
+/*
+ * 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 BSOCK::recv()
+{
+   int32_t nbytes;
+   int32_t pktsiz;
+
+   msg[0] = 0;
+   msglen = 0;
+   if (errors || terminated) {
+      return BNET_HARDEOF;
+   }
+
+   read_seqno++;            /* bump sequence number */
+   timer_start = watchdog_time;  /* set start wait time */
+   timed_out = 0;
+   /* get data size -- in int32_t */
+   if ((nbytes = read_nbytes(this, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
+      timer_start = 0;      /* clear timer */
+      /* probably pipe broken because client died */
+      if (errno == 0) {
+         b_errno = ENODATA;
+      } else {
+         b_errno = errno;
+      }
+      errors++;
+      return BNET_HARDEOF;         /* assume hard EOF received */
+   }
+   timer_start = 0;         /* clear timer */
+   if (nbytes != sizeof(int32_t)) {
+      errors++;
+      b_errno = EIO;
+      Qmsg5(m_jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"),
+            sizeof(int32_t), nbytes, m_who, m_host, m_port);
+      return BNET_ERROR;
+   }
+
+   pktsiz = ntohl(pktsiz);         /* decode no. of bytes that follow */
+
+   if (pktsiz == 0) {              /* No data transferred */
+      timer_start = 0;      /* clear timer */
+      in_msg_no++;
+      msglen = 0;
+      return 0;                    /* zero bytes read */
+   }
+
+   /* 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);
+         pktsiz = BNET_TERMINATE;  /* hang up */
+      }
+      if (pktsiz == BNET_TERMINATE) {
+         terminated = 1;
+      }
+      timer_start = 0;      /* clear timer */
+      b_errno = ENODATA;
+      msglen = pktsiz;      /* signal code */
+      return BNET_SIGNAL;          /* signal */
+   }
+
+   /* Make sure the buffer is big enough + one byte for EOS */
+   if (pktsiz >= (int32_t) sizeof_pool_memory(msg)) {
+      msg = realloc_pool_memory(msg, pktsiz + 100);
+   }
+
+   timer_start = watchdog_time;  /* set start wait time */
+   timed_out = 0;
+   /* now read the actual data */
+   if ((nbytes = read_nbytes(this, msg, pktsiz)) <= 0) {
+      timer_start = 0;      /* clear timer */
+      if (errno == 0) {
+         b_errno = ENODATA;
+      } else {
+         b_errno = errno;
+      }
+      errors++;
+      Qmsg4(m_jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
+            m_who, m_host, m_port, bnet_strerror(this));
+      return BNET_ERROR;
+   }
+   timer_start = 0;         /* clear timer */
+   in_msg_no++;
+   msglen = nbytes;
+   if (nbytes != pktsiz) {
+      b_errno = EIO;
+      errors++;
+      Qmsg5(m_jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"),
+            pktsiz, nbytes, m_who, m_host, m_port);
+      return BNET_ERROR;
+   }
+   /* 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 */
+   sm_check(__FILE__, __LINE__, false);
+   return nbytes;                  /* return actual length of message */
+}
+
+
 /*
  * Send a signal
  */
@@ -142,3 +270,52 @@ bool BSOCK::signal(int signal)
    }
    return send();
 }
+
+void BSOCK::close()
+{
+   BSOCK *bsock = this;
+   BSOCK *next;
+
+   for (; bsock; bsock = next) {
+      next = bsock->m_next;           /* get possible pointer to next before destoryed */
+      if (!bsock->duped) {
+#ifdef HAVE_TLS
+         /* Shutdown tls cleanly. */
+         if (bsock->tls) {
+            tls_bsock_shutdown(bsock);
+            free_tls_connection(bsock->tls);
+            bsock->tls = NULL;
+         }
+#endif /* HAVE_TLS */
+         if (bsock->timed_out) {
+            shutdown(bsock->fd, 2);   /* discard any pending I/O */
+         }
+         socketClose(bsock->fd);      /* normal close */
+      }
+      destroy();                      /* free the packet */
+   }
+   return;
+}
+
+void BSOCK::destroy()
+{
+   if (msg) {
+      free_pool_memory(msg);
+      msg = NULL;
+   } else {
+      ASSERT(1 == 0);              /* double close */
+   }
+   if (errmsg) {
+      free_pool_memory(errmsg);
+      errmsg = NULL;
+   }
+   if (m_who) {
+      free(m_who);
+      m_who = NULL;
+   }
+   if (m_host) {
+      free(m_host);
+      m_host = NULL;
+   }
+   free(this);
+}