/*
Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
+ This library 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307, USA.
*/
#include "bacula.h"
+#include "jcr.h"
extern time_t watchdog_time;
#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)
+#else
+#define socketRead(fd, buf, len) read(fd, buf, len)
+#define socketWrite(fd, buf, len) write(fd, buf, len)
+#endif
+
/*
* Read a nbytes from the network.
while (nleft > 0) {
do {
errno = 0;
- nread = read(bsock->fd, ptr, nleft);
- } while (!bsock->timed_out && nread == -1 && (errno == EINTR || errno == EAGAIN));
+ nread = socketRead(bsock->fd, ptr, nleft);
+ if (bsock->timed_out || bsock->terminated) {
+ return nread;
+ }
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
if (nread <= 0) {
return nread; /* error, or EOF */
}
{
int32_t nleft, nwritten;
+ if (bsock->spool) {
+ nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
+ if (nwritten != nbytes) {
+ Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno));
+ Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
+ return -1;
+ }
+ return nbytes;
+ }
nleft = nbytes;
while (nleft > 0) {
do {
errno = 0;
- nwritten = write(bsock->fd, ptr, nleft);
- } while (!bsock->timed_out && nwritten == -1 && (errno == EINTR || errno == EAGAIN));
+ nwritten = socketWrite(bsock->fd, ptr, nleft);
+ if (bsock->timed_out || bsock->terminated) {
+ return nwritten;
+ }
+ } while (nwritten == -1 && errno == EINTR);
+ /*
+ * If connection is non-blocking, we will get EAGAIN, so
+ * use select() to keep from consuming all the CPU
+ * and try again.
+ */
+ if (nwritten == -1 && errno == EAGAIN) {
+ fd_set fdset;
+ struct timeval tv;
+
+ FD_ZERO(&fdset);
+ FD_SET(bsock->fd, &fdset);
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ select(bsock->fd + 1, NULL, &fdset, NULL, &tv);
+ continue;
+ }
if (nwritten <= 0) {
return nwritten; /* error */
}
* 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
- * Returns 0 on end of file
- * Returns -1 on hard end of file (i.e. network connection close)
- * Returns -2 on error
+ * 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.
*/
-/* EXTPROTO */
-int32_t
-bnet_recv(BSOCK *bsock)
+int32_t bnet_recv(BSOCK *bsock)
{
int32_t nbytes;
int32_t pktsiz;
- if (bsock->errors) {
- return -2;
+ ASSERT(bsock != NULL);
+ mp_chr(bsock->msg)[0] = 0;
+ if (bsock->errors || bsock->terminated) {
+ return BNET_HARDEOF;
}
bsock->read_seqno++; /* bump sequence number */
bsock->b_errno = errno;
}
bsock->errors++;
- return -1; /* assume hard EOF received */
+ return BNET_HARDEOF; /* assume hard EOF received */
}
bsock->timer_start = 0; /* clear timer */
if (nbytes != sizeof(int32_t)) {
bsock->errors++;
bsock->b_errno = EIO;
- Emsg3(M_ERROR, 0, "Read %d expected %d from %s\n", nbytes, sizeof(int32_t),
- bsock->who);
- return -2;
+ Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
+ bsock->who, bsock->host, bsock->port);
+ return BNET_ERROR;
}
pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
- if (pktsiz <= 0) {
- bsock->b_errno = ENODATA;
- bsock->msglen = pktsiz; /* return size */
- return 0; /* soft EOF */
+ if (pktsiz == 0) { /* No data transferred */
+ bsock->timer_start = 0; /* clear timer */
+ bsock->in_msg_no++;
+ bsock->msglen = 0;
+ return 0; /* zero bytes read */
}
- /* For big packet size, something went wrong */
- if (pktsiz > 10000000) {
+
+ /* If signal or packet size too big */
+ if (pktsiz < 0 || pktsiz > 1000000) {
+ if (pktsiz > 0) { /* if packet too big */
+ Jmsg3(bsock->jcr, M_FATAL, 0,
+ _("Packet size too big from \"%s:%s:%d. Terminating connection.\n"),
+ bsock->who, bsock->host, bsock->port);
+ pktsiz = BNET_TERMINATE; /* hang up */
+ }
+ if (pktsiz == BNET_TERMINATE) {
+ bsock->terminated = 1;
+ }
+ bsock->timer_start = 0; /* clear timer */
bsock->b_errno = ENODATA;
- bsock->msglen = pktsiz; /* return size */
- return 0; /* soft EOF */
+ bsock->msglen = pktsiz; /* signal code */
+ return BNET_SIGNAL; /* signal */
}
/* Make sure the buffer is big enough + one byte for EOS */
bsock->timer_start = watchdog_time; /* set start wait time */
bsock->timed_out = 0;
/* now read the actual data */
- if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <= 0) {
+ if ((nbytes = read_nbytes(bsock, mp_chr(bsock->msg), pktsiz)) <= 0) {
bsock->timer_start = 0; /* clear timer */
if (errno == 0) {
bsock->b_errno = ENODATA;
bsock->b_errno = errno;
}
bsock->errors++;
- Emsg4(M_ERROR, 0, "Read error from %s:%s:%d: ERR=%s\n",
+ Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
- return -2;
+ return BNET_ERROR;
}
bsock->timer_start = 0; /* clear timer */
bsock->in_msg_no++;
if (nbytes != pktsiz) {
bsock->b_errno = EIO;
bsock->errors++;
- Emsg5(M_ERROR, 0, "Read expected %d got %d from %s:%s:%d\n", pktsiz, nbytes,
+ Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
bsock->who, bsock->host, bsock->port);
- return -2;
+ 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 atleast one byte longer than the message length.
+ * buffer is at least one byte longer than the message length.
*/
- bsock->msg[nbytes] = 0; /* terminate in case it is a string */
+ mp_chr(bsock->msg)[nbytes] = 0; /* terminate in case it is a string */
sm_check(__FILE__, __LINE__, False);
return nbytes; /* return actual length of message */
}
+
+/*
+ * Return 1 if there are errors on this bsock or it is closed,
+ * i.e. stop communicating on this line.
+ */
+int is_bnet_stop(BSOCK *bsock)
+{
+ return bsock->errors || bsock->terminated;
+}
+
+/*
+ * Return number of errors on socket
+ */
+int is_bnet_error(BSOCK *bsock)
+{
+ return bsock->errors;
+}
+
+/*
+ * 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, int flag)
+{
+ bsock->suppress_error_msgs = flag;
+}
+
+
+/*
+ * Transmit spooled data now to a BSOCK
+ */
+int bnet_despool_to_bsock(BSOCK *bsock)
+{
+ int32_t pktsiz;
+ size_t nbytes;
+
+ rewind(bsock->spool_fd);
+ while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
+ bsock->msglen = ntohl(pktsiz);
+ if (bsock->msglen > 0) {
+ if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
+ bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen + 1);
+ }
+ nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
+ if (nbytes != (size_t)bsock->msglen) {
+ Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
+ Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
+ return 0;
+ }
+ }
+ bnet_send(bsock);
+ }
+ if (ferror(bsock->spool_fd)) {
+ Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+
/*
* Send a message over the network. The send consists of
* two network packets. The first is sends a 32 bit integer containing
{
int32_t rc;
int32_t pktsiz;
+ int32_t msglen;
- if (bsock->errors) {
+ if (bsock->errors || bsock->terminated || bsock->msglen > 1000000) {
return 0;
}
+ msglen = bsock->msglen;
pktsiz = htonl((int32_t)bsock->msglen);
/* send int32_t containing size of data packet */
bsock->timer_start = watchdog_time; /* start timer */
rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
bsock->timer_start = 0; /* clear timer */
if (rc != sizeof(int32_t)) {
+ if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
+ bsock->terminated = 1;
+ return 0; /* ignore any errors */
+ }
bsock->errors++;
if (errno == 0) {
bsock->b_errno = EIO;
bsock->b_errno = errno;
}
if (rc < 0) {
- /****FIXME***** use Mmsg */
- Emsg4(M_ERROR, 0, "Write error sending to %s:%s:%d: ERR=%s\n",
- bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
+ if (!bsock->suppress_error_msgs && !bsock->timed_out) {
+ Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
+ bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
+ }
} else {
- Emsg5(M_ERROR, 0, "Wrote %d bytes to %s:%s:%d, but only %d accepted.\n",
+ Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
}
return 0;
/* send data packet */
bsock->timer_start = watchdog_time; /* start timer */
bsock->timed_out = 0;
- rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
+ rc = write_nbytes(bsock, mp_chr(bsock->msg), bsock->msglen);
bsock->timer_start = 0; /* clear timer */
if (rc != bsock->msglen) {
bsock->errors++;
bsock->b_errno = errno;
}
if (rc < 0) {
- /************FIXME********* use Pmsg() **/
- Emsg4(M_ERROR, 0, "Write error sending to %s:%s:%d: ERR=%s\n",
- bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
+ if (!bsock->suppress_error_msgs) {
+ Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
+ bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
+ }
} else {
- Emsg5(M_ERROR, 0, "Wrote %d bytes to %s:%s:%d, but only %d accepted.\n",
- bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
+ Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
+ bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
}
return 0;
}
return 1;
}
+/*
+ * Establish an SSL connection -- server side
+ * Codes that ssl_need and ssl_has can take
+ * BNET_SSL_NONE I cannot do ssl
+ * BNET_SSL_OK I can do ssl, but it is not required on my end
+ * BNET_SSL_REQUIRED ssl is required on my end
+ */
+int
+bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
+{
+ /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
+ /* The other side expects a response from us */
+ return 1;
+}
+
+/*
+ * Establish an SSL connection -- client side
+ */
+int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
+{
+ /* We are the client so we must wait for the server to notify us */
+ return 1;
+}
+
+
/*
* Wait for a specified time for data to appear on
* the BSOCK connection.
* -1 if error
*/
int
-bnet_wait_data(BSOCK *bsock, int sec)
+bnet_wait_data(BSOCK *bsock, int sec)
{
fd_set fdset;
struct timeval tv;
tv.tv_usec = 0;
for ( ;; ) {
switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
- case 0: /* timeout */
- bsock->b_errno = 0;
- return 0;
- case -1:
- bsock->b_errno = errno;
- if (errno == EINTR || errno == EAGAIN) {
- continue;
- }
- return -1; /* error return */
- default:
- bsock->b_errno = 0;
- return 1;
+ case 0: /* timeout */
+ bsock->b_errno = 0;
+ return 0;
+ case -1:
+ bsock->b_errno = errno;
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ return -1; /* error return */
+ default:
+ bsock->b_errno = 0;
+ return 1;
+ }
+ }
+}
+
+/*
+ * As above, but returns on interrupt
+ */
+int
+bnet_wait_data_intr(BSOCK *bsock, int sec)
+{
+ fd_set fdset;
+ struct timeval tv;
+
+ FD_ZERO(&fdset);
+ FD_SET(bsock->fd, &fdset);
+ tv.tv_sec = sec;
+ tv.tv_usec = 0;
+ for ( ;; ) {
+ switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
+ case 0: /* timeout */
+ bsock->b_errno = 0;
+ return 0;
+ case -1:
+ bsock->b_errno = errno;
+ return -1; /* error return */
+ default:
+ bsock->b_errno = 0;
+ return 1;
}
}
}
+#ifndef NETDB_INTERNAL
+#define NETDB_INTERNAL -1 /* See errno. */
+#endif
+#ifndef NETDB_SUCCESS
+#define NETDB_SUCCESS 0 /* No problem. */
+#endif
+#ifndef HOST_NOT_FOUND
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found. */
+#endif
+#ifndef TRY_AGAIN
+#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL. */
+#endif
+#ifndef NO_RECOVERY
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
+#endif
+#ifndef NO_DATA
+#define NO_DATA 4 /* Valid name, no data record of requested type. */
+#endif
+
+#ifndef HAVE_WIN32
+extern int h_errno; /* On error has one of the above */
+#endif
+/*
+ * Get human readable error for gethostbyname()
+ */
+static const char *gethost_strerror()
+{
+ switch (h_errno) {
+ case NETDB_INTERNAL:
+ return strerror(errno);
+ case NETDB_SUCCESS:
+ return "No problem.";
+ case HOST_NOT_FOUND:
+ return "Authoritative answer Host not found.";
+ case TRY_AGAIN:
+ return "Non-authoritative Host not found, or ServerFail.";
+ case NO_RECOVERY:
+ return "Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.";
+ case NO_DATA:
+ return "Valid name, no data record of resquested type.";
+ default:
+ return "Unknown error.";
+ }
+}
+
+
+static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
+
/*
* Convert a hostname or dotted IP address into
* a s_addr. We handle only IPv4.
*/
-static uint32_t *bget_host_ip(char *host)
+static uint32_t *bget_host_ip(JCR *jcr, char *host)
{
struct in_addr inaddr;
uint32_t *addr_list; /* this really should be struct in_addr */
addr_list[0] = inaddr.s_addr;
addr_list[1] = (uint32_t) -1;
} else {
- /******FIXME***** use gethostbyname_r or mutex ****/
+ P(ip_mutex);
if ((hp = gethostbyname(host)) == NULL) {
- Dmsg2(0, "gethostbyname() for %s failed: ERR=%s\n", host, strerror(errno));
+ Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for host \"%s\" failed: ERR=%s\n",
+ host, gethost_strerror());
+ V(ip_mutex);
return NULL;
}
if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
- Emsg2(M_WARNING, 0, "gethostbyname() network address length error.\n\
-Wanted %d got %d bytes for s_addr.\n", sizeof(inaddr.s_addr), hp->h_length);
- return NULL;
+ Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
+Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
+ V(ip_mutex);
+ return NULL;
}
i = 0;
for (p = hp->h_addr_list; *p != 0; p++) {
i++;
}
i++;
- addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
+ addr_list = (uint32_t *)malloc(sizeof(uint32_t) * i);
i = 0;
for (p = hp->h_addr_list; *p != 0; p++) {
addr_list[i++] = (*(struct in_addr **)p)->s_addr;
}
addr_list[i] = (uint32_t) -1;
+ V(ip_mutex);
}
return addr_list;
}
* ***FIXME*** implement service from /etc/services
*/
static BSOCK *
-bnet_open(char *name, char *host, char *service, int port)
+bnet_open(JCR *jcr, const char *name, char *host, char *service, int port, int *fatal)
{
int sockfd;
struct sockaddr_in tcp_serv_addr; /* socket information */
tcp_serv_addr.sin_family = AF_INET;
tcp_serv_addr.sin_port = htons(port);
- if ((addr_list=bget_host_ip(host)) == NULL) {
+ if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
+ *fatal = 1;
return NULL;
}
/* Open a TCP socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
free(addr_list);
+ *fatal = 1;
return NULL;
}
/*
* Receive notification when connection dies.
*/
- if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
- Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
+ if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
+ Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
}
for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
close(sockfd);
return NULL;
}
- return init_bsock(sockfd, name, host, port);
+ return init_bsock(jcr, sockfd, name, host, port, &tcp_serv_addr);
}
/*
* Try to connect to host for max_retry_time at retry_time intervals.
*/
BSOCK *
-bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
+bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, const char *name,
char *host, char *service, int port, int verbose)
{
int i;
BSOCK *bsock;
-
- for (i=0; (bsock = bnet_open(name, host, service, port)) == NULL; i -= retry_interval) {
- if (i <= 0) {
+ int fatal = 0;
+
+ for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
+ if (fatal || (jcr && job_canceled(jcr))) {
+ return NULL;
+ }
+ Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
+ name, host, port, strerror(errno));
+ if (i < 0) {
i = 60 * 5; /* complain again in 5 minutes */
if (verbose)
Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
Retrying ...\n", name, host, port, strerror(errno));
}
- sleep(retry_interval);
+ bmicrosleep(retry_interval, 0);
max_retry_time -= retry_interval;
if (max_retry_time <= 0) {
- Jmsg(jcr, M_FATAL, 0, "Unable to connect to %s on %s:%d.\n",
- name, host, port);
+ Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
+ name, host, port, strerror(errno));
return NULL;
}
}
*/
char *bnet_strerror(BSOCK *bsock)
{
- /* ***FIXME*** not thread safe */
return strerror(bsock->b_errno);
}
* 1 on success
*/
int
-bnet_fsend(BSOCK *bs, char *fmt, ...)
+bnet_fsend(BSOCK *bs, const char *fmt, ...)
{
va_list arg_ptr;
int maxlen;
+ if (bs->errors || bs->terminated) {
+ return 0;
+ }
/* 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
again:
maxlen = sizeof_pool_memory(bs->msg) - 1;
va_start(arg_ptr, fmt);
- bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
+ bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
va_end(arg_ptr);
if (bs->msglen < 0 || bs->msglen >= maxlen) {
- bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
+ bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
goto again;
}
- return bnet_send(bs) < 0 ? 0 : 1;
+ return bnet_send(bs);
}
/*
*/
int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
{
- uint32_t dbuf_size;
+ uint32_t dbuf_size, start_size;
#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
int opt;
opt = IPTOS_THROUGHPUT;
- setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
+ setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
#endif
- dbuf_size = size;
+ if (size != 0) {
+ dbuf_size = size;
+ } else {
+ dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
+ }
+ start_size = dbuf_size;
if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
- Emsg0(M_FATAL, 0, "Could not malloc 32K BSOCK data buffer\n");
+ Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
return 0;
}
if (rw & BNET_SETBUF_READ) {
while ((dbuf_size > TAPE_BSIZE) &&
- (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
- Emsg1(M_ERROR, 0, "sockopt error: %s\n", strerror(errno));
+ (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
+ Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
dbuf_size -= TAPE_BSIZE;
}
- Dmsg1(20, "set network buffer size=%d\n", dbuf_size);
- if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
- Emsg1(M_WARNING, 0, "Warning network buffer = %d bytes not max size.\n", dbuf_size);
+ Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
+ if (dbuf_size != start_size) {
+ Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
+ }
if (dbuf_size % TAPE_BSIZE != 0) {
- Emsg1(M_ABORT, 0, "Network buffer size %d not multiple of tape block size.\n",
+ Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
dbuf_size);
}
}
- dbuf_size = size;
+ if (size != 0) {
+ dbuf_size = size;
+ } else {
+ dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
+ }
+ start_size = dbuf_size;
if (rw & BNET_SETBUF_WRITE) {
while ((dbuf_size > TAPE_BSIZE) &&
- (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
- Emsg1(M_ERROR, 0, "sockopt error: %s\n", strerror(errno));
+ (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
+ Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
dbuf_size -= TAPE_BSIZE;
}
- Dmsg1(20, "set network buffer size=%d\n", dbuf_size);
- if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
- Emsg1(M_WARNING, 0, "Warning network buffer = %d bytes not max size.\n", dbuf_size);
+ Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
+ if (dbuf_size != start_size) {
+ Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
+ }
if (dbuf_size % TAPE_BSIZE != 0) {
- Emsg1(M_ABORT, 0, "Network buffer size %d not multiple of tape block size.\n",
+ Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
dbuf_size);
}
}
{
static char buf[30];
switch (bs->msglen) {
- case BNET_EOF:
- return "BNET_EOF";
case BNET_EOD:
- return "BNET_EOD";
+ return "BNET_EOD"; /* end of data stream */
case BNET_EOD_POLL:
return "BNET_EOD_POLL";
case BNET_STATUS:
return "BNET_STATUS";
case BNET_TERMINATE:
- return "BNET_TERMINATE";
+ return "BNET_TERMINATE"; /* terminate connection */
case BNET_POLL:
return "BNET_POLL";
case BNET_HEARTBEAT:
* This probably should be done in net_open
*/
BSOCK *
-init_bsock(int sockfd, char *who, char *host, int port)
+init_bsock(JCR *jcr, int sockfd, const char *who, char *host, int port,
+ struct sockaddr_in *client_addr)
{
BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
- if (bsock == NULL) {
- Emsg0(M_ABORT, 0, "Out of memory in init_bsock.\n");
- }
memset(bsock, 0, sizeof(BSOCK));
bsock->fd = sockfd;
bsock->errors = 0;
bsock->who = bstrdup(who);
bsock->host = bstrdup(host);
bsock->port = port;
+ 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->jcr = jcr;
return bsock;
}
BSOCK *
dup_bsock(BSOCK *osock)
{
- BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
- if (bsock == NULL) {
- Emsg0(M_ABORT, 0, "Out of memory in dup_bsock.\n");
- }
+ BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
memcpy(bsock, osock, sizeof(BSOCK));
bsock->msg = get_pool_memory(PM_MESSAGE);
bsock->errmsg = get_pool_memory(PM_MESSAGE);
+ if (osock->who) {
+ bsock->who = bstrdup(osock->who);
+ }
+ if (osock->host) {
+ bsock->host = bstrdup(osock->host);
+ }
bsock->duped = TRUE;
return bsock;
}
for ( ; bsock != NULL; bsock = next) {
next = bsock->next;
if (!bsock->duped) {
- shutdown(bsock->fd, SHUT_RDWR);
- close(bsock->fd);
- term_bsock(bsock);
- } else {
- free(bsock);
+ if (bsock->timed_out) {
+ shutdown(bsock->fd, 2); /* discard any pending I/O */
+ }
+ close(bsock->fd); /* normal close */
}
+ term_bsock(bsock);
}
return;
}
void
term_bsock(BSOCK *bsock)
{
- free_pool_memory(bsock->msg);
- free_pool_memory(bsock->errmsg);
- free(bsock->who);
- free(bsock->host);
+ if (bsock->msg) {
+ free_pool_memory(bsock->msg);
+ bsock->msg = NULL;
+ } else {
+ ASSERT(1==0); /* double close */
+ }
+ if (bsock->errmsg) {
+ free_pool_memory(bsock->errmsg);
+ bsock->errmsg = NULL;
+ }
+ if (bsock->who) {
+ free(bsock->who);
+ bsock->who = NULL;
+ }
+ if (bsock->host) {
+ free(bsock->host);
+ bsock->host = NULL;
+ }
free(bsock);
}