#include "bacula.h"
#include "jcr.h"
+#include <netdb.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);
+ nread = socketRead(bsock->fd, ptr, nleft);
if (bsock->timed_out || bsock->terminated) {
return nread;
}
while (nleft > 0) {
do {
errno = 0;
- nwritten = write(bsock->fd, ptr, nleft);
+ 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
- * sleep long enough to keep from consuming all the CPU
+ * 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) {
- bmicrosleep(0, 50); /* sleep 50 ms */
+ 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) {
int32_t nbytes;
int32_t pktsiz;
+ ASSERT(bsock != NULL);
mp_chr(bsock->msg)[0] = 0;
if (bsock->errors || bsock->terminated) {
return BNET_HARDEOF;
if (nbytes != sizeof(int32_t)) {
bsock->errors++;
bsock->b_errno = EIO;
- Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
- bsock->who);
+ 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;
}
/* 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) {
/*
- * Transmit spooled data now
+ * Transmit spooled data now to a BSOCK
*/
-int bnet_despool(BSOCK *bsock)
+int bnet_despool_to_bsock(BSOCK *bsock)
{
int32_t pktsiz;
size_t nbytes;
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);
+ 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) {
{
int32_t rc;
int32_t pktsiz;
+ int32_t msglen;
- if (bsock->errors || bsock->terminated) {
+ 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 */
bsock->b_errno = errno;
}
if (rc < 0) {
- if (!bsock->suppress_error_msgs) {
+ 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));
}
}
}
+#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
+
+/*
+ * 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;
} else {
P(ip_mutex);
if ((hp = gethostbyname(host)) == NULL) {
- Jmsg2(jcr, M_ERROR, 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;
}
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;
* ***FIXME*** implement service from /etc/services
*/
static BSOCK *
-bnet_open(JCR *jcr, char *name, char *host, char *service, int port, int *fatal)
+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 */
close(sockfd);
return NULL;
}
- return init_bsock(jcr, 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(JCR *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;
* 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
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;
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) {
Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
return 0;
dbuf_size -= TAPE_BSIZE;
}
Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
- if (dbuf_size != MAX_NETWORK_BUFFER_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) {
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, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
dbuf_size -= TAPE_BSIZE;
}
Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
- if (dbuf_size != MAX_NETWORK_BUFFER_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) {
Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
dbuf_size);
* This probably should be done in net_open
*/
BSOCK *
-init_bsock(JCR *jcr, 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));
memset(bsock, 0, sizeof(BSOCK));
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
for ( ; bsock != NULL; bsock = next) {
next = bsock->next;
if (!bsock->duped) {
- close(bsock->fd);
+ if (bsock->timed_out) {
+ shutdown(bsock->fd, 2); /* discard any pending I/O */
+ }
+ close(bsock->fd); /* normal close */
}
term_bsock(bsock);
}