]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet.c
Add extern C to callback functions
[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-2004 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          Qmsg1(bsock->jcr, M_FATAL, 0, _("Attr 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((unsigned)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       Qmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), 
183             sizeof(int32_t), nbytes, 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          Qmsg3(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       Qmsg4(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       Qmsg5(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, bool 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, void update_attr_spool_size(ssize_t size), ssize_t tsize)
285 {
286    int32_t pktsiz;
287    size_t nbytes;
288    ssize_t last = 0, size = 0;
289    int count = 0;
290
291    rewind(bsock->spool_fd);
292    while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
293       size += sizeof(int32_t);
294       bsock->msglen = ntohl(pktsiz);
295       if (bsock->msglen > 0) {
296          if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
297             bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen + 1);
298          }
299          nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
300          if (nbytes != (size_t)bsock->msglen) {
301             Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
302             Qmsg1(bsock->jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"), strerror(errno));
303             update_attr_spool_size(tsize-last);
304             return 0;
305          }
306          size += nbytes;
307          if ((++count & 0x3F) == 0) {
308             update_attr_spool_size(size-last);
309             last = size;
310          }
311       }
312       bnet_send(bsock);
313    }
314    update_attr_spool_size(tsize-last);
315    if (ferror(bsock->spool_fd)) {
316       Qmsg1(bsock->jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"), strerror(errno));
317       return 0;
318    }
319    return 1;
320 }
321
322
323 /*
324  * Send a message over the network. The send consists of
325  * two network packets. The first is sends a 32 bit integer containing
326  * the length of the data packet which follows.
327  *
328  * Returns: 0 on failure
329  *          1 on success
330  */
331 int
332 bnet_send(BSOCK *bsock)
333 {
334    int32_t rc;
335    int32_t pktsiz;
336    int32_t msglen;
337
338    if (bsock->errors || bsock->terminated || bsock->msglen > 1000000) {
339       return 0;
340    }
341    msglen = bsock->msglen;
342    pktsiz = htonl((int32_t)bsock->msglen);
343    /* send int32_t containing size of data packet */
344    bsock->timer_start = watchdog_time; /* start timer */
345    bsock->timed_out = 0;               
346    rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
347    bsock->timer_start = 0;            /* clear timer */
348    if (rc != sizeof(int32_t)) {
349       if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
350          bsock->terminated = 1;
351          return 0;                    /* ignore any errors */
352       }
353       bsock->errors++;
354       if (errno == 0) {
355          bsock->b_errno = EIO;
356       } else {
357          bsock->b_errno = errno;
358       }
359       if (rc < 0) {
360          if (!bsock->suppress_error_msgs && !bsock->timed_out) {
361             Qmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), 
362                   bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
363          }
364       } else {
365          Qmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), 
366                bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
367       }
368       return 0;
369    }
370
371    bsock->out_msg_no++;               /* increment message number */
372    if (bsock->msglen <= 0) {          /* length only? */
373       return 1;                       /* yes, no data */
374    }
375
376    /* send data packet */
377    bsock->timer_start = watchdog_time; /* start timer */
378    bsock->timed_out = 0;               
379    rc = write_nbytes(bsock, mp_chr(bsock->msg), bsock->msglen);
380    bsock->timer_start = 0;            /* clear timer */
381    if (rc != bsock->msglen) {
382       bsock->errors++;
383       if (errno == 0) {
384          bsock->b_errno = EIO;
385       } else {
386          bsock->b_errno = errno;
387       }
388       if (rc < 0) {
389          if (!bsock->suppress_error_msgs) {
390             Qmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), 
391                   bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
392          }
393       } else {
394          Qmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), 
395                bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
396       }
397       return 0;
398    }
399    return 1;
400 }
401
402 /*
403  * Establish an SSL connection -- server side         
404  *  Codes that ssl_need and ssl_has can take
405  *    BNET_SSL_NONE      I cannot do ssl
406  *    BNET_SSL_OK        I can do ssl, but it is not required on my end
407  *    BNET_SSL_REQUIRED  ssl is required on my end
408  */
409 int     
410 bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
411 {
412    /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
413    /* The other side expects a response from us */
414    return 1;
415 }
416
417 /*
418  * Establish an SSL connection -- client side   
419  */
420 int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
421 {
422    /* We are the client so we must wait for the server to notify us */
423    return 1;
424 }
425
426
427 /*
428  * Wait for a specified time for data to appear on
429  * the BSOCK connection.
430  *
431  *   Returns: 1 if data available
432  *            0 if timeout
433  *           -1 if error
434  */
435 int 
436 bnet_wait_data(BSOCK *bsock, int sec)          
437 {
438    fd_set fdset;
439    struct timeval tv;
440
441    FD_ZERO(&fdset);
442    FD_SET((unsigned)bsock->fd, &fdset);
443    tv.tv_sec = sec;
444    tv.tv_usec = 0;
445    for ( ;; ) {
446       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
447       case 0:                         /* timeout */
448          bsock->b_errno = 0;
449          return 0;
450       case -1:
451          bsock->b_errno = errno;
452          if (errno == EINTR || errno == EAGAIN) {
453             continue;
454          }
455          return -1;                  /* error return */
456       default:
457          bsock->b_errno = 0;
458          return 1;
459       }
460    }
461 }
462
463 /*
464  * As above, but returns on interrupt
465  */
466 int
467 bnet_wait_data_intr(BSOCK *bsock, int sec)          
468 {
469    fd_set fdset;
470    struct timeval tv;
471
472    FD_ZERO(&fdset);
473    FD_SET((unsigned)bsock->fd, &fdset);
474    tv.tv_sec = sec;
475    tv.tv_usec = 0;
476    for ( ;; ) {
477       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
478       case 0:                         /* timeout */
479          bsock->b_errno = 0;
480          return 0;
481       case -1:
482          bsock->b_errno = errno;
483          return -1;                  /* error return */
484       default:
485          bsock->b_errno = 0;
486          return 1;
487       }
488    }
489 }
490
491 #ifndef NETDB_INTERNAL
492 #define NETDB_INTERNAL  -1      /* See errno. */
493 #endif
494 #ifndef NETDB_SUCCESS
495 #define NETDB_SUCCESS   0       /* No problem. */
496 #endif
497 #ifndef HOST_NOT_FOUND
498 #define HOST_NOT_FOUND  1       /* Authoritative Answer Host not found. */
499 #endif
500 #ifndef TRY_AGAIN
501 #define TRY_AGAIN       2       /* Non-Authoritative Host not found, or SERVERFAIL. */
502 #endif
503 #ifndef NO_RECOVERY
504 #define NO_RECOVERY     3       /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
505 #endif
506 #ifndef NO_DATA
507 #define NO_DATA         4       /* Valid name, no data record of requested type. */
508 #endif
509
510 /*
511  * Get human readable error for gethostbyname()
512  */
513 static const char *gethost_strerror() 
514 {
515    switch (h_errno) {
516    case NETDB_INTERNAL:
517       return strerror(errno);
518    case NETDB_SUCCESS:
519       return "No problem.";
520    case HOST_NOT_FOUND:
521       return "Authoritative answer Host not found.";
522    case TRY_AGAIN:
523       return "Non-authoritative Host not found, or ServerFail.";
524    case NO_RECOVERY:
525       return "Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.";
526    case NO_DATA:
527       return "Valid name, no data record of resquested type.";
528    default:
529       return "Unknown error.";
530    }
531 }
532
533
534 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
535
536 /*
537  * Convert a hostname or dotted IP address into   
538  * a s_addr.  We handle only IPv4.
539  */
540 static uint32_t *bget_host_ip(JCR *jcr, char *host)
541 {
542    struct in_addr inaddr;
543    uint32_t *addr_list;               /* this really should be struct in_addr */
544    struct hostent *hp;
545    char **p;
546    int i;
547
548    if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
549       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
550       addr_list[0] = inaddr.s_addr;
551       addr_list[1] = (uint32_t) -1;
552    } else {
553       P(ip_mutex);
554       if ((hp = gethostbyname(host)) == NULL) {
555          Qmsg2(jcr, M_ERROR, 0, "gethostbyname() for host \"%s\" failed: ERR=%s\n", 
556                host, gethost_strerror());
557          V(ip_mutex);
558          return NULL;
559       }
560       if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
561          Qmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
562 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
563          V(ip_mutex);
564          return NULL;
565       }
566       i = 0;
567       for (p = hp->h_addr_list; *p != 0; p++) {
568          i++;
569       }
570       i++;
571       addr_list = (uint32_t *)malloc(sizeof(uint32_t) * i);
572       i = 0;
573       for (p = hp->h_addr_list; *p != 0; p++) {
574          addr_list[i++] = (*(struct in_addr **)p)->s_addr;
575       }
576       addr_list[i] = (uint32_t) -1;
577       V(ip_mutex);
578    }
579    return addr_list;
580 }
581
582 /*     
583  * Open a TCP connection to the UPS network server
584  * Returns NULL
585  * Returns BSOCK * pointer on success
586  *
587  *  ***FIXME*** implement service from /etc/services
588  */
589 static BSOCK *
590 bnet_open(JCR *jcr, const char *name, char *host, char *service, int port, int *fatal)
591 {
592    int sockfd;
593    struct sockaddr_in tcp_serv_addr;     /* socket information */
594    uint32_t *addr_list;
595    int i, connected = 0;
596    int turnon = 1;
597
598    /* 
599     * Fill in the structure serv_addr with the address of
600     * the server that we want to connect with.
601     */
602    memset((char *)&tcp_serv_addr, 0,  sizeof(tcp_serv_addr));
603    tcp_serv_addr.sin_family = AF_INET;
604    tcp_serv_addr.sin_port = htons(port);
605
606    if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
607      *fatal = 1;
608      return NULL;
609    }
610
611    /* Open a TCP socket */
612    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
613       free(addr_list);
614       *fatal = 1;
615       return NULL;
616    }
617
618    /*
619     * Receive notification when connection dies.
620     */
621    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
622       Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
623    }
624    
625    for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
626       /* connect to server */
627       tcp_serv_addr.sin_addr.s_addr = addr_list[i];
628       if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
629          continue;
630       }
631       connected = 1;
632       break;
633    }
634
635    free(addr_list);
636    if (!connected) {
637       close(sockfd);
638       return NULL;
639    }
640    return init_bsock(jcr, sockfd, name, host, port, &tcp_serv_addr);
641 }
642
643 /*
644  * Try to connect to host for max_retry_time at retry_time intervals.
645  */
646 BSOCK *
647 bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, const char *name,
648              char *host, char *service, int port, int verbose)
649 {
650    int i;
651    BSOCK *bsock;
652    int fatal = 0;
653
654    for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
655      if (fatal || (jcr && job_canceled(jcr))) {
656         return NULL;
657      }
658      Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
659               name, host, port, strerror(errno));
660       if (i < 0) {
661          i = 60 * 5;                  /* complain again in 5 minutes */
662          if (verbose)
663             Qmsg4(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
664 Retrying ...\n", name, host, port, strerror(errno));
665       }
666       bmicrosleep(retry_interval, 0);
667       max_retry_time -= retry_interval;
668       if (max_retry_time <= 0) {
669          Qmsg4(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
670               name, host, port, strerror(errno));
671          return NULL;
672       }
673    }
674    return bsock;
675 }
676
677
678 /*
679  * Return the string for the error that occurred
680  * on the socket. Only the first error is retained.
681  */
682 char *bnet_strerror(BSOCK *bsock)
683 {
684    return strerror(bsock->b_errno);
685 }
686
687 /*
688  * Format and send a message
689  *  Returns: 0 on failure
690  *           1 on success
691  */
692 int
693 bnet_fsend(BSOCK *bs, const char *fmt, ...)
694 {
695    va_list arg_ptr;
696    int maxlen;
697
698    if (bs->errors || bs->terminated) {
699       return 0;
700    }
701    /* This probably won't work, but we vsnprintf, then if we
702     * get a negative length or a length greater than our buffer
703     * (depending on which library is used), the printf was truncated, so
704     * get a biger buffer and try again.
705     */
706 again:
707    maxlen = sizeof_pool_memory(bs->msg) - 1;
708    va_start(arg_ptr, fmt);
709    bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
710    va_end(arg_ptr);
711    if (bs->msglen < 0 || bs->msglen >= maxlen) {
712       bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
713       goto again;
714    }
715    return bnet_send(bs);
716 }
717
718 /* 
719  * Set the network buffer size, suggested size is in size.
720  *  Actual size obtained is returned in bs->msglen
721  *
722  *  Returns: 0 on failure
723  *           1 on success
724  */
725 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
726 {
727    uint32_t dbuf_size, start_size;
728 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
729    int opt;
730
731     opt = IPTOS_THROUGHPUT;
732     setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
733 #endif
734
735    if (size != 0) {
736       dbuf_size = size;
737    } else {
738       dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
739    }
740    start_size = dbuf_size;
741    if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
742       Qmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
743       return 0;
744    }
745    if (rw & BNET_SETBUF_READ) {
746       while ((dbuf_size > TAPE_BSIZE) &&
747          (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
748          Qmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
749          dbuf_size -= TAPE_BSIZE;
750       }
751       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
752       if (dbuf_size != start_size) {
753          Qmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
754       }
755       if (dbuf_size % TAPE_BSIZE != 0) {
756          Qmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
757               dbuf_size);
758       }
759    }
760    if (size != 0) {
761       dbuf_size = size;
762    } else {
763       dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
764    }
765    start_size = dbuf_size;
766    if (rw & BNET_SETBUF_WRITE) {
767       while ((dbuf_size > TAPE_BSIZE) &&
768          (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
769          Qmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
770          dbuf_size -= TAPE_BSIZE;
771       }
772       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
773       if (dbuf_size != start_size) {
774          Qmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
775       }
776       if (dbuf_size % TAPE_BSIZE != 0) {
777          Qmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
778               dbuf_size);
779       }
780    }
781
782    bs->msglen = dbuf_size;
783    return 1;
784 }
785
786 /*
787  * Send a network "signal" to the other end 
788  *  This consists of sending a negative packet length
789  *
790  *  Returns: 0 on failure
791  *           1 on success
792  */
793 int bnet_sig(BSOCK *bs, int sig)
794 {
795    bs->msglen = sig;
796    return bnet_send(bs);
797 }
798
799 /*
800  * Convert a network "signal" code into
801  * human readable ASCII.
802  */
803 const char *bnet_sig_to_ascii(BSOCK *bs)
804 {
805    static char buf[30];
806    switch (bs->msglen) {
807       case BNET_EOD:
808          return "BNET_EOD";           /* end of data stream */
809       case BNET_EOD_POLL:
810          return "BNET_EOD_POLL";
811       case BNET_STATUS:
812          return "BNET_STATUS";
813       case BNET_TERMINATE:
814          return "BNET_TERMINATE";     /* terminate connection */
815       case BNET_POLL:
816          return "BNET_POLL";
817       case BNET_HEARTBEAT:
818          return "BNET_HEARTBEAT";
819       case BNET_HB_RESPONSE:
820          return "BNET_HB_RESPONSE";
821       case BNET_PROMPT:
822          return "BNET_PROMPT";
823       default:
824          sprintf(buf, "Unknown sig %d", bs->msglen);
825          return buf;
826    }
827 }
828
829
830 /* Initialize internal socket structure.  
831  *  This probably should be done in net_open
832  */
833 BSOCK *
834 init_bsock(JCR *jcr, int sockfd, const char *who, const char *host, int port, 
835            struct sockaddr_in *client_addr) 
836 {
837    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
838    memset(bsock, 0, sizeof(BSOCK));
839    bsock->fd = sockfd;
840    bsock->errors = 0;
841    bsock->msg = get_pool_memory(PM_MESSAGE);
842    bsock->errmsg = get_pool_memory(PM_MESSAGE);
843    bsock->who = bstrdup(who);
844    bsock->host = bstrdup(host);
845    bsock->port = port;
846    memcpy(&bsock->client_addr, client_addr, sizeof(bsock->client_addr));
847    /*
848     * ****FIXME**** reduce this to a few hours once   
849     *   heartbeats are implemented
850     */
851    bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
852    bsock->jcr = jcr;
853    return bsock;
854 }
855
856 BSOCK *
857 dup_bsock(BSOCK *osock)
858 {
859    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
860    memcpy(bsock, osock, sizeof(BSOCK));
861    bsock->msg = get_pool_memory(PM_MESSAGE);
862    bsock->errmsg = get_pool_memory(PM_MESSAGE);
863    if (osock->who) {
864       bsock->who = bstrdup(osock->who);
865    }
866    if (osock->host) {
867       bsock->host = bstrdup(osock->host);
868    }
869    bsock->duped = TRUE;
870    return bsock;
871 }
872
873 /* Close the network connection */
874 void 
875 bnet_close(BSOCK *bsock)
876 {
877    BSOCK *next;
878
879    for ( ; bsock != NULL; bsock = next) {
880       next = bsock->next;
881       if (!bsock->duped) {
882          if (bsock->timed_out) {
883             shutdown(bsock->fd, 2);   /* discard any pending I/O */
884          }
885          close(bsock->fd);         /* normal close */
886       }
887       term_bsock(bsock);
888    }
889    return;
890 }
891
892 void
893 term_bsock(BSOCK *bsock)
894 {
895    if (bsock->msg) {
896       free_pool_memory(bsock->msg);
897       bsock->msg = NULL;
898    } else {
899       ASSERT(1==0);                   /* double close */
900    }
901    if (bsock->errmsg) {
902       free_pool_memory(bsock->errmsg);
903       bsock->errmsg = NULL;
904    }
905    if (bsock->who) {
906       free(bsock->who);
907       bsock->who = NULL;
908    }
909    if (bsock->host) {
910       free(bsock->host);
911       bsock->host = NULL;
912    }
913    free(bsock);
914 }
915