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