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