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