]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet.c
Fix reporting jobs from state file + misc
[bacula/bacula] / bacula / src / lib / bnet.c
1 /*
2  * Network Utility Routines
3  *
4  *  by Kern Sibbald
5  *
6  * Adapted and enhanced for Bacula, originally written 
7  * for inclusion in the Apcupsd package
8  *
9  *   Version $Id$
10  */
11 /*
12    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
13
14    This library is free software; you can redistribute it and/or
15    modify it under the terms of the GNU Lesser General Public
16    License as published by the Free Software Foundation; either
17    version 2.1 of the License, or (at your option) any later version.
18
19    This library is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22    Lesser General Public License for more details.
23
24    You should have received a copy of the GNU Lesser General Public
25    License along with this library; if not, write to the Free
26    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27    MA 02111-1307, USA.
28
29  */
30
31
32 #include "bacula.h"
33 #include "jcr.h"
34 #include <netdb.h>
35
36 extern time_t watchdog_time;
37
38 #ifndef   INADDR_NONE
39 #define   INADDR_NONE    -1
40 #endif
41
42 #ifndef ENODATA                       /* not defined on BSD systems */
43 #define ENODATA EPIPE
44 #endif
45
46 #ifdef HAVE_WIN32
47 #define socketRead(fd, buf, len) recv(fd, buf, len, 0)
48 #define socketWrite(fd, buf, len) send(fd, buf, len, 0)
49 #else
50 #define socketRead(fd, buf, len) read(fd, buf, len)
51 #define socketWrite(fd, buf, len) write(fd, buf, len)
52 #endif
53
54
55 /*
56  * Read a nbytes from the network.
57  * It is possible that the total bytes require in several
58  * read requests
59  */
60
61 static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
62 {
63    int32_t nleft, nread;
64       
65    nleft = nbytes;
66    while (nleft > 0) {
67       do {
68          errno = 0;
69          nread = socketRead(bsock->fd, ptr, nleft);      
70          if (bsock->timed_out || bsock->terminated) {
71             return nread;
72          }
73       } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
74       if (nread <= 0) {
75          return nread;               /* error, or EOF */
76       }
77       nleft -= nread;
78       ptr += nread;
79    }
80    return nbytes - nleft;            /* return >= 0 */
81 }
82
83 /*
84  * Write nbytes to the network.
85  * It may require several writes.
86  */
87
88 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
89 {
90    int32_t nleft, nwritten;
91
92    if (bsock->spool) {
93       nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
94       if (nwritten != nbytes) {
95          Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno));
96          Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
97          return -1;
98       }
99       return nbytes;
100    }
101    nleft = nbytes;
102    while (nleft > 0) {
103       do {
104          errno = 0;
105          nwritten = socketWrite(bsock->fd, ptr, nleft);
106          if (bsock->timed_out || bsock->terminated) {
107             return nwritten;
108          }
109       } while (nwritten == -1 && errno == EINTR);
110       /*
111        * If connection is non-blocking, we will get EAGAIN, so
112        * use select() to keep from consuming all the CPU
113        * and try again.
114        */
115       if (nwritten == -1 && errno == EAGAIN) {
116          fd_set fdset;
117          struct timeval tv;
118
119          FD_ZERO(&fdset);
120          FD_SET(bsock->fd, &fdset);
121          tv.tv_sec = 10;
122          tv.tv_usec = 0;
123          select(bsock->fd + 1, NULL, &fdset, NULL, &tv);
124          continue;
125       }
126       if (nwritten <= 0) {
127          return nwritten;            /* error */
128       }
129       nleft -= nwritten;
130       ptr += nwritten;
131    }
132    return nbytes-nleft;
133 }
134
135 /* 
136  * Receive a message from the other end. Each message consists of
137  * two packets. The first is a header that contains the size
138  * of the data that follows in the second packet.
139  * Returns number of bytes read (may return zero)
140  * Returns -1 on signal (BNET_SIGNAL) 
141  * Returns -2 on hard end of file (BNET_HARDEOF)
142  * Returns -3 on error  (BNET_ERROR)
143  *
144  *  Unfortunately, it is a bit complicated because we have these
145  *    four return types:
146  *    1. Normal data
147  *    2. Signal including end of data stream
148  *    3. Hard end of file                 
149  *    4. Error
150  *  Using is_bnet_stop() and is_bnet_error() you can figure this all out.
151  */
152 int32_t bnet_recv(BSOCK *bsock)
153 {
154    int32_t nbytes;
155    int32_t pktsiz;
156
157    ASSERT(bsock != NULL);
158    mp_chr(bsock->msg)[0] = 0;
159    if (bsock->errors || bsock->terminated) {
160       return BNET_HARDEOF;
161    }
162
163    bsock->read_seqno++;               /* bump sequence number */
164    bsock->timer_start = watchdog_time;  /* set start wait time */
165    bsock->timed_out = 0;
166    /* get data size -- in int32_t */
167    if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
168       bsock->timer_start = 0;         /* clear timer */
169       /* probably pipe broken because client died */
170       if (errno == 0) {
171          bsock->b_errno = ENODATA;
172       } else {
173          bsock->b_errno = errno;
174       }
175       bsock->errors++;
176       return BNET_HARDEOF;            /* assume hard EOF received */
177    }
178    bsock->timer_start = 0;            /* clear timer */
179    if (nbytes != sizeof(int32_t)) {
180       bsock->errors++;
181       bsock->b_errno = EIO;
182       Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
183             bsock->who, bsock->host, bsock->port);
184       return BNET_ERROR;
185    }
186
187    pktsiz = ntohl(pktsiz);            /* decode no. of bytes that follow */
188
189    if (pktsiz == 0) {                 /* No data transferred */
190       bsock->timer_start = 0;         /* clear timer */
191       bsock->in_msg_no++;
192       bsock->msglen = 0;
193       return 0;                       /* zero bytes read */
194    }
195
196    /* If signal or packet size too big */
197    if (pktsiz < 0 || pktsiz > 1000000) {
198       if (pktsiz > 0) {               /* if packet too big */
199          Jmsg3(bsock->jcr, M_FATAL, 0, 
200             _("Packet size too big from \"%s:%s:%d. Terminating connection.\n"),
201             bsock->who, bsock->host, bsock->port);
202          pktsiz = BNET_TERMINATE;     /* hang up */
203       }
204       if (pktsiz == BNET_TERMINATE) {
205          bsock->terminated = 1;
206       }
207       bsock->timer_start = 0;         /* clear timer */
208       bsock->b_errno = ENODATA;
209       bsock->msglen = pktsiz;         /* signal code */
210       return BNET_SIGNAL;             /* signal */
211    }
212
213    /* Make sure the buffer is big enough + one byte for EOS */
214    if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
215       bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
216    }
217
218    bsock->timer_start = watchdog_time;  /* set start wait time */
219    bsock->timed_out = 0;
220    /* now read the actual data */
221    if ((nbytes = read_nbytes(bsock, mp_chr(bsock->msg), pktsiz)) <=  0) {
222       bsock->timer_start = 0;         /* clear timer */
223       if (errno == 0) {
224          bsock->b_errno = ENODATA;
225       } else {
226          bsock->b_errno = errno;
227       }
228       bsock->errors++;
229       Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"), 
230             bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
231       return BNET_ERROR;
232    }
233    bsock->timer_start = 0;            /* clear timer */
234    bsock->in_msg_no++;
235    bsock->msglen = nbytes;
236    if (nbytes != pktsiz) {
237       bsock->b_errno = EIO;
238       bsock->errors++;
239       Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
240             bsock->who, bsock->host, bsock->port);
241       return BNET_ERROR;
242    }
243    /* always add a zero by to properly terminate any
244     * string that was send to us. Note, we ensured above that the
245     * buffer is at least one byte longer than the message length.
246     */
247    mp_chr(bsock->msg)[nbytes] = 0;    /* terminate in case it is a string */
248    sm_check(__FILE__, __LINE__, False);
249    return nbytes;                     /* return actual length of message */
250 }
251
252
253 /*
254  * Return 1 if there are errors on this bsock or it is closed,  
255  *   i.e. stop communicating on this line.
256  */
257 int is_bnet_stop(BSOCK *bsock) 
258 {
259    return bsock->errors || bsock->terminated;
260 }
261
262 /*
263  * Return number of errors on socket 
264  */
265 int is_bnet_error(BSOCK *bsock)
266 {
267    return bsock->errors;
268 }
269
270 /*
271  * Call here after error during closing to suppress error
272  *  messages which are due to the other end shutting down too.
273  */
274 void
275 bnet_suppress_error_messages(BSOCK *bsock, int flag)
276 {      
277    bsock->suppress_error_msgs = flag;
278 }
279
280
281 /*
282  * Transmit spooled data now to a BSOCK
283  */
284 int bnet_despool_to_bsock(BSOCK *bsock)
285 {
286    int32_t pktsiz;
287    size_t nbytes;
288
289    rewind(bsock->spool_fd);
290    while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
291       bsock->msglen = ntohl(pktsiz);
292       if (bsock->msglen > 0) {
293          if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
294             bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen + 1);
295          }
296          nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
297          if (nbytes != (size_t)bsock->msglen) {
298             Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
299             Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
300             return 0;
301          }
302       }
303       bnet_send(bsock);
304    }
305    if (ferror(bsock->spool_fd)) {
306       Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
307       return 0;
308    }
309    return 1;
310 }
311
312
313 /*
314  * Send a message over the network. The send consists of
315  * two network packets. The first is sends a 32 bit integer containing
316  * the length of the data packet which follows.
317  *
318  * Returns: 0 on failure
319  *          1 on success
320  */
321 int
322 bnet_send(BSOCK *bsock)
323 {
324    int32_t rc;
325    int32_t pktsiz;
326    int32_t msglen;
327
328    if (bsock->errors || bsock->terminated || bsock->msglen > 1000000) {
329       return 0;
330    }
331    msglen = bsock->msglen;
332    pktsiz = htonl((int32_t)bsock->msglen);
333    /* send int32_t containing size of data packet */
334    bsock->timer_start = watchdog_time; /* start timer */
335    bsock->timed_out = 0;               
336    rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
337    bsock->timer_start = 0;            /* clear timer */
338    if (rc != sizeof(int32_t)) {
339       if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
340          bsock->terminated = 1;
341          return 0;                    /* ignore any errors */
342       }
343       bsock->errors++;
344       if (errno == 0) {
345          bsock->b_errno = EIO;
346       } else {
347          bsock->b_errno = errno;
348       }
349       if (rc < 0) {
350          if (!bsock->suppress_error_msgs && !bsock->timed_out) {
351             Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), 
352                   bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
353          }
354       } else {
355          Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), 
356                bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
357       }
358       return 0;
359    }
360
361    bsock->out_msg_no++;               /* increment message number */
362    if (bsock->msglen <= 0) {          /* length only? */
363       return 1;                       /* yes, no data */
364    }
365
366    /* send data packet */
367    bsock->timer_start = watchdog_time; /* start timer */
368    bsock->timed_out = 0;               
369    rc = write_nbytes(bsock, mp_chr(bsock->msg), bsock->msglen);
370    bsock->timer_start = 0;            /* clear timer */
371    if (rc != bsock->msglen) {
372       bsock->errors++;
373       if (errno == 0) {
374          bsock->b_errno = EIO;
375       } else {
376          bsock->b_errno = errno;
377       }
378       if (rc < 0) {
379          if (!bsock->suppress_error_msgs) {
380             Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), 
381                   bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
382          }
383       } else {
384          Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), 
385                bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
386       }
387       return 0;
388    }
389    return 1;
390 }
391
392 /*
393  * Establish an SSL connection -- server side         
394  *  Codes that ssl_need and ssl_has can take
395  *    BNET_SSL_NONE      I cannot do ssl
396  *    BNET_SSL_OK        I can do ssl, but it is not required on my end
397  *    BNET_SSL_REQUIRED  ssl is required on my end
398  */
399 int     
400 bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
401 {
402    /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
403    /* The other side expects a response from us */
404    return 1;
405 }
406
407 /*
408  * Establish an SSL connection -- client side   
409  */
410 int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
411 {
412    /* We are the client so we must wait for the server to notify us */
413    return 1;
414 }
415
416
417 /*
418  * Wait for a specified time for data to appear on
419  * the BSOCK connection.
420  *
421  *   Returns: 1 if data available
422  *            0 if timeout
423  *           -1 if error
424  */
425 int 
426 bnet_wait_data(BSOCK *bsock, int sec)          
427 {
428    fd_set fdset;
429    struct timeval tv;
430
431    FD_ZERO(&fdset);
432    FD_SET(bsock->fd, &fdset);
433    tv.tv_sec = sec;
434    tv.tv_usec = 0;
435    for ( ;; ) {
436       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
437       case 0:                         /* timeout */
438          bsock->b_errno = 0;
439          return 0;
440       case -1:
441          bsock->b_errno = errno;
442          if (errno == EINTR || errno == EAGAIN) {
443             continue;
444          }
445          return -1;                  /* error return */
446       default:
447          bsock->b_errno = 0;
448          return 1;
449       }
450    }
451 }
452
453 /*
454  * As above, but returns on interrupt
455  */
456 int
457 bnet_wait_data_intr(BSOCK *bsock, int sec)          
458 {
459    fd_set fdset;
460    struct timeval tv;
461
462    FD_ZERO(&fdset);
463    FD_SET(bsock->fd, &fdset);
464    tv.tv_sec = sec;
465    tv.tv_usec = 0;
466    for ( ;; ) {
467       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
468       case 0:                         /* timeout */
469          bsock->b_errno = 0;
470          return 0;
471       case -1:
472          bsock->b_errno = errno;
473          return -1;                  /* error return */
474       default:
475          bsock->b_errno = 0;
476          return 1;
477       }
478    }
479 }
480
481 #ifndef NETDB_INTERNAL
482 #define NETDB_INTERNAL  -1      /* See errno. */
483 #endif
484 #ifndef NETDB_SUCCESS
485 #define NETDB_SUCCESS   0       /* No problem. */
486 #endif
487 #ifndef HOST_NOT_FOUND
488 #define HOST_NOT_FOUND  1       /* Authoritative Answer Host not found. */
489 #endif
490 #ifndef TRY_AGAIN
491 #define TRY_AGAIN       2       /* Non-Authoritative Host not found, or SERVERFAIL. */
492 #endif
493 #ifndef NO_RECOVERY
494 #define NO_RECOVERY     3       /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
495 #endif
496 #ifndef NO_DATA
497 #define NO_DATA         4       /* Valid name, no data record of requested type. */
498 #endif
499
500 /*
501  * Get human readable error for gethostbyname()
502  */
503 static const char *gethost_strerror() 
504 {
505    switch (h_errno) {
506    case NETDB_INTERNAL:
507       return strerror(errno);
508    case NETDB_SUCCESS:
509       return "No problem.";
510    case HOST_NOT_FOUND:
511       return "Authoritative answer Host not found.";
512    case TRY_AGAIN:
513       return "Non-authoritative Host not found, or ServerFail.";
514    case NO_RECOVERY:
515       return "Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.";
516    case NO_DATA:
517       return "Valid name, no data record of resquested type.";
518    default:
519       return "Unknown error.";
520    }
521 }
522
523
524 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
525
526 /*
527  * Convert a hostname or dotted IP address into   
528  * a s_addr.  We handle only IPv4.
529  */
530 static uint32_t *bget_host_ip(JCR *jcr, char *host)
531 {
532    struct in_addr inaddr;
533    uint32_t *addr_list;               /* this really should be struct in_addr */
534    struct hostent *hp;
535    char **p;
536    int i;
537
538    if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
539       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
540       addr_list[0] = inaddr.s_addr;
541       addr_list[1] = (uint32_t) -1;
542    } else {
543       P(ip_mutex);
544       if ((hp = gethostbyname(host)) == NULL) {
545          Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for host \"%s\" failed: ERR=%s\n", 
546                host, gethost_strerror());
547          V(ip_mutex);
548          return NULL;
549       }
550       if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
551          Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
552 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
553          V(ip_mutex);
554          return NULL;
555       }
556       i = 0;
557       for (p = hp->h_addr_list; *p != 0; p++) {
558          i++;
559       }
560       i++;
561       addr_list = (uint32_t *)malloc(sizeof(uint32_t) * i);
562       i = 0;
563       for (p = hp->h_addr_list; *p != 0; p++) {
564          addr_list[i++] = (*(struct in_addr **)p)->s_addr;
565       }
566       addr_list[i] = (uint32_t) -1;
567       V(ip_mutex);
568    }
569    return addr_list;
570 }
571
572 /*     
573  * Open a TCP connection to the UPS network server
574  * Returns NULL
575  * Returns BSOCK * pointer on success
576  *
577  *  ***FIXME*** implement service from /etc/services
578  */
579 static BSOCK *
580 bnet_open(JCR *jcr, const char *name, char *host, char *service, int port, int *fatal)
581 {
582    int sockfd;
583    struct sockaddr_in tcp_serv_addr;     /* socket information */
584    uint32_t *addr_list;
585    int i, connected = 0;
586    int turnon = 1;
587
588    /* 
589     * Fill in the structure serv_addr with the address of
590     * the server that we want to connect with.
591     */
592    memset((char *)&tcp_serv_addr, 0,  sizeof(tcp_serv_addr));
593    tcp_serv_addr.sin_family = AF_INET;
594    tcp_serv_addr.sin_port = htons(port);
595
596    if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
597      *fatal = 1;
598      return NULL;
599    }
600
601    /* Open a TCP socket */
602    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
603       free(addr_list);
604       *fatal = 1;
605       return NULL;
606    }
607
608    /*
609     * Receive notification when connection dies.
610     */
611    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
612       Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
613    }
614    
615    for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
616       /* connect to server */
617       tcp_serv_addr.sin_addr.s_addr = addr_list[i];
618       if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
619          continue;
620       }
621       connected = 1;
622       break;
623    }
624
625    free(addr_list);
626    if (!connected) {
627       close(sockfd);
628       return NULL;
629    }
630    return init_bsock(jcr, sockfd, name, host, port, &tcp_serv_addr);
631 }
632
633 /*
634  * Try to connect to host for max_retry_time at retry_time intervals.
635  */
636 BSOCK *
637 bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, const char *name,
638              char *host, char *service, int port, int verbose)
639 {
640    int i;
641    BSOCK *bsock;
642    int fatal = 0;
643
644    for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
645      if (fatal || (jcr && job_canceled(jcr))) {
646         return NULL;
647      }
648      Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
649               name, host, port, strerror(errno));
650       if (i < 0) {
651          i = 60 * 5;                  /* complain again in 5 minutes */
652          if (verbose)
653             Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
654 Retrying ...\n", name, host, port, strerror(errno));
655       }
656       bmicrosleep(retry_interval, 0);
657       max_retry_time -= retry_interval;
658       if (max_retry_time <= 0) {
659          Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
660               name, host, port, strerror(errno));
661          return NULL;
662       }
663    }
664    return bsock;
665 }
666
667
668 /*
669  * Return the string for the error that occurred
670  * on the socket. Only the first error is retained.
671  */
672 char *bnet_strerror(BSOCK *bsock)
673 {
674    return strerror(bsock->b_errno);
675 }
676
677 /*
678  * Format and send a message
679  *  Returns: 0 on failure
680  *           1 on success
681  */
682 int
683 bnet_fsend(BSOCK *bs, const char *fmt, ...)
684 {
685    va_list arg_ptr;
686    int maxlen;
687
688    if (bs->errors || bs->terminated) {
689       return 0;
690    }
691    /* This probably won't work, but we vsnprintf, then if we
692     * get a negative length or a length greater than our buffer
693     * (depending on which library is used), the printf was truncated, so
694     * get a biger buffer and try again.
695     */
696 again:
697    maxlen = sizeof_pool_memory(bs->msg) - 1;
698    va_start(arg_ptr, fmt);
699    bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
700    va_end(arg_ptr);
701    if (bs->msglen < 0 || bs->msglen >= maxlen) {
702       bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
703       goto again;
704    }
705    return bnet_send(bs);
706 }
707
708 /* 
709  * Set the network buffer size, suggested size is in size.
710  *  Actual size obtained is returned in bs->msglen
711  *
712  *  Returns: 0 on failure
713  *           1 on success
714  */
715 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
716 {
717    uint32_t dbuf_size, start_size;
718 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
719    int opt;
720
721     opt = IPTOS_THROUGHPUT;
722     setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
723 #endif
724
725    if (size != 0) {
726       dbuf_size = size;
727    } else {
728       dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
729    }
730    start_size = dbuf_size;
731    if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
732       Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
733       return 0;
734    }
735    if (rw & BNET_SETBUF_READ) {
736       while ((dbuf_size > TAPE_BSIZE) &&
737          (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
738          Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
739          dbuf_size -= TAPE_BSIZE;
740       }
741       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
742       if (dbuf_size != start_size) {
743          Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
744       }
745       if (dbuf_size % TAPE_BSIZE != 0) {
746          Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
747               dbuf_size);
748       }
749    }
750    if (size != 0) {
751       dbuf_size = size;
752    } else {
753       dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
754    }
755    start_size = dbuf_size;
756    if (rw & BNET_SETBUF_WRITE) {
757       while ((dbuf_size > TAPE_BSIZE) &&
758          (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
759          Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
760          dbuf_size -= TAPE_BSIZE;
761       }
762       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
763       if (dbuf_size != start_size) {
764          Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
765       }
766       if (dbuf_size % TAPE_BSIZE != 0) {
767          Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
768               dbuf_size);
769       }
770    }
771
772    bs->msglen = dbuf_size;
773    return 1;
774 }
775
776 /*
777  * Send a network "signal" to the other end 
778  *  This consists of sending a negative packet length
779  *
780  *  Returns: 0 on failure
781  *           1 on success
782  */
783 int bnet_sig(BSOCK *bs, int sig)
784 {
785    bs->msglen = sig;
786    return bnet_send(bs);
787 }
788
789 /*
790  * Convert a network "signal" code into
791  * human readable ASCII.
792  */
793 char *bnet_sig_to_ascii(BSOCK *bs)
794 {
795    static char buf[30];
796    switch (bs->msglen) {
797       case BNET_EOD:
798          return "BNET_EOD";           /* end of data stream */
799       case BNET_EOD_POLL:
800          return "BNET_EOD_POLL";
801       case BNET_STATUS:
802          return "BNET_STATUS";
803       case BNET_TERMINATE:
804          return "BNET_TERMINATE";     /* terminate connection */
805       case BNET_POLL:
806          return "BNET_POLL";
807       case BNET_HEARTBEAT:
808          return "BNET_HEARTBEAT";
809       case BNET_HB_RESPONSE:
810          return "BNET_HB_RESPONSE";
811       case BNET_PROMPT:
812          return "BNET_PROMPT";
813       default:
814          sprintf(buf, "Unknown sig %d", bs->msglen);
815          return buf;
816    }
817 }
818
819
820 /* Initialize internal socket structure.  
821  *  This probably should be done in net_open
822  */
823 BSOCK *
824 init_bsock(JCR *jcr, int sockfd, const char *who, char *host, int port, 
825            struct sockaddr_in *client_addr) 
826 {
827    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
828    memset(bsock, 0, sizeof(BSOCK));
829    bsock->fd = sockfd;
830    bsock->errors = 0;
831    bsock->msg = get_pool_memory(PM_MESSAGE);
832    bsock->errmsg = get_pool_memory(PM_MESSAGE);
833    bsock->who = bstrdup(who);
834    bsock->host = bstrdup(host);
835    bsock->port = port;
836    memcpy(&bsock->client_addr, client_addr, sizeof(bsock->client_addr));
837    /*
838     * ****FIXME**** reduce this to a few hours once   
839     *   heartbeats are implemented
840     */
841    bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
842    bsock->jcr = jcr;
843    return bsock;
844 }
845
846 BSOCK *
847 dup_bsock(BSOCK *osock)
848 {
849    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
850    memcpy(bsock, osock, sizeof(BSOCK));
851    bsock->msg = get_pool_memory(PM_MESSAGE);
852    bsock->errmsg = get_pool_memory(PM_MESSAGE);
853    if (osock->who) {
854       bsock->who = bstrdup(osock->who);
855    }
856    if (osock->host) {
857       bsock->host = bstrdup(osock->host);
858    }
859    bsock->duped = TRUE;
860    return bsock;
861 }
862
863 /* Close the network connection */
864 void 
865 bnet_close(BSOCK *bsock)
866 {
867    BSOCK *next;
868
869    for ( ; bsock != NULL; bsock = next) {
870       next = bsock->next;
871       if (!bsock->duped) {
872          if (bsock->timed_out) {
873             shutdown(bsock->fd, 2);   /* discard any pending I/O */
874          }
875          close(bsock->fd);         /* normal close */
876       }
877       term_bsock(bsock);
878    }
879    return;
880 }
881
882 void
883 term_bsock(BSOCK *bsock)
884 {
885    if (bsock->msg) {
886       free_pool_memory(bsock->msg);
887       bsock->msg = NULL;
888    } else {
889       ASSERT(1==0);                   /* double close */
890    }
891    if (bsock->errmsg) {
892       free_pool_memory(bsock->errmsg);
893       bsock->errmsg = NULL;
894    }
895    if (bsock->who) {
896       free(bsock->who);
897       bsock->who = NULL;
898    }
899    if (bsock->host) {
900       free(bsock->host);
901       bsock->host = NULL;
902    }
903    free(bsock);
904 }
905