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