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