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