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