]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet.c
Important protocol change -- see kes29Oct02
[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 /*
366  * Convert a hostname or dotted IP address into   
367  * a s_addr.  We handle only IPv4.
368  */
369 static uint32_t *bget_host_ip(void *jcr, char *host)
370 {
371    struct in_addr inaddr;
372    uint32_t *addr_list;               /* this really should be struct in_addr */
373    struct hostent *hp;
374    char **p;
375    int i;
376
377    if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
378       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
379       addr_list[0] = inaddr.s_addr;
380       addr_list[1] = (uint32_t) -1;
381    } else {
382       /******FIXME***** use gethostbyname_r or mutex ****/
383       if ((hp = gethostbyname(host)) == NULL) {
384          Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n", 
385                host, strerror(errno));
386          return NULL;
387       }
388       if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
389           Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
390 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
391           return NULL;
392       }
393       i = 0;
394       for (p = hp->h_addr_list; *p != 0; p++) {
395          i++;
396       }
397       i++;
398       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
399       i = 0;
400       for (p = hp->h_addr_list; *p != 0; p++) {
401          addr_list[i++] = (*(struct in_addr **)p)->s_addr;
402       }
403       addr_list[i] = (uint32_t) -1;
404    }
405    return addr_list;
406 }
407
408 /*     
409  * Open a TCP connection to the UPS network server
410  * Returns NULL
411  * Returns BSOCK * pointer on success
412  *
413  *  ***FIXME*** implement service from /etc/services
414  */
415 static BSOCK *
416 bnet_open(void *jcr, char *name, char *host, char *service, int port)
417 {
418    int sockfd;
419    struct sockaddr_in tcp_serv_addr;     /* socket information */
420    uint32_t *addr_list;
421    int i, connected = 0;
422    int turnon = 1;
423
424    /* 
425     * Fill in the structure serv_addr with the address of
426     * the server that we want to connect with.
427     */
428    memset((char *)&tcp_serv_addr, 0,  sizeof(tcp_serv_addr));
429    tcp_serv_addr.sin_family = AF_INET;
430    tcp_serv_addr.sin_port = htons(port);
431
432    if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
433      return NULL;
434    }
435
436    /* Open a TCP socket */
437    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
438       free(addr_list);
439       return NULL;
440    }
441
442    /*
443     * Receive notification when connection dies.
444     */
445    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
446       Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
447    }
448    
449    for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
450       /* connect to server */
451       tcp_serv_addr.sin_addr.s_addr = addr_list[i];
452       if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
453          continue;
454       }
455       connected = 1;
456       break;
457    }
458
459    free(addr_list);
460    if (!connected) {
461       close(sockfd);
462       return NULL;
463    }
464    return init_bsock(jcr, sockfd, name, host, port);
465 }
466
467 /*
468  * Try to connect to host for max_retry_time at retry_time intervals.
469  */
470 BSOCK *
471 bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
472              char *host, char *service, int port, int verbose)
473 {
474    int i;
475    BSOCK *bsock;
476
477    for (i=0; (bsock = bnet_open(jcr, name, host, service, port)) == NULL; i -= retry_interval) {
478      Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
479               name, host, port, strerror(errno));
480       if (i < 0) {
481          i = 60 * 5;                  /* complain again in 5 minutes */
482          if (verbose)
483             Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
484 Retrying ...\n", name, host, port, strerror(errno));
485       }
486       sleep(retry_interval);
487       max_retry_time -= retry_interval;
488       if (max_retry_time <= 0) {
489          Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
490               name, host, port, strerror(errno));
491          return NULL;
492       }
493    }
494    return bsock;
495 }
496
497
498 /*
499  * Return the string for the error that occurred
500  * on the socket. Only the first error is retained.
501  */
502 char *bnet_strerror(BSOCK *bsock)
503 {
504    return strerror(bsock->b_errno);
505 }
506
507 /*
508  * Format and send a message
509  *  Returns: 0 on failure
510  *           1 on success
511  */
512 int
513 bnet_fsend(BSOCK *bs, char *fmt, ...)
514 {
515    va_list arg_ptr;
516    int maxlen;
517
518    /* This probably won't work, but we vsnprintf, then if we
519     * get a negative length or a length greater than our buffer
520     * (depending on which library is used), the printf was truncated, so
521     * get a biger buffer and try again.
522     */
523 again:
524    maxlen = sizeof_pool_memory(bs->msg) - 1;
525    va_start(arg_ptr, fmt);
526    bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
527    va_end(arg_ptr);
528    if (bs->msglen < 0 || bs->msglen >= maxlen) {
529       bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
530       goto again;
531    }
532    return bnet_send(bs) < 0 ? 0 : 1;
533 }
534
535 /* 
536  * Set the network buffer size, suggested size is in size.
537  *  Actual size obtained is returned in bs->msglen
538  *
539  *  Returns: 0 on failure
540  *           1 on success
541  */
542 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
543 {
544    uint32_t dbuf_size;
545 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
546    int opt;
547
548     opt = IPTOS_THROUGHPUT;
549     setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
550 #endif
551
552    dbuf_size = size;
553    if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
554       Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
555       return 0;
556    }
557    if (rw & BNET_SETBUF_READ) {
558       while ((dbuf_size > TAPE_BSIZE) &&
559          (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
560          Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
561          dbuf_size -= TAPE_BSIZE;
562       }
563       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
564       if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
565          Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
566       if (dbuf_size % TAPE_BSIZE != 0) {
567          Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
568               dbuf_size);
569       }
570    }
571    dbuf_size = size;
572    if (rw & BNET_SETBUF_WRITE) {
573       while ((dbuf_size > TAPE_BSIZE) &&
574          (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
575          Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
576          dbuf_size -= TAPE_BSIZE;
577       }
578       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
579       if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
580          Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
581       if (dbuf_size % TAPE_BSIZE != 0) {
582          Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
583               dbuf_size);
584       }
585    }
586
587    bs->msglen = dbuf_size;
588    return 1;
589 }
590
591 /*
592  * Send a network "signal" to the other end 
593  *  This consists of sending a negative packet length
594  *
595  *  Returns: 0 on failure
596  *           1 on success
597  */
598 int bnet_sig(BSOCK *bs, int sig)
599 {
600    bs->msglen = sig;
601    return bnet_send(bs);
602 }
603
604 /*
605  * Convert a network "signal" code into
606  * human readable ASCII.
607  */
608 char *bnet_sig_to_ascii(BSOCK *bs)
609 {
610    static char buf[30];
611    switch (bs->msglen) {
612       case BNET_EOD:
613          return "BNET_EOD";           /* end of data stream */
614       case BNET_EOD_POLL:
615          return "BNET_EOD_POLL";
616       case BNET_STATUS:
617          return "BNET_STATUS";
618       case BNET_TERMINATE:
619          return "BNET_TERMINATE";     /* terminate connection */
620       case BNET_POLL:
621          return "BNET_POLL";
622       case BNET_HEARTBEAT:
623          return "BNET_HEARTBEAT";
624       case BNET_HB_RESPONSE:
625          return "BNET_HB_RESPONSE";
626       case BNET_PROMPT:
627          return "BNET_PROMPT";
628       default:
629          sprintf(buf, "Unknown sig %d", bs->msglen);
630          return buf;
631    }
632 }
633
634
635 /* Initialize internal socket structure.  
636  *  This probably should be done in net_open
637  */
638 BSOCK *
639 init_bsock(void *jcr, int sockfd, char *who, char *host, int port) 
640 {
641    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
642    memset(bsock, 0, sizeof(BSOCK));
643    bsock->fd = sockfd;
644    bsock->errors = 0;
645    bsock->msg = get_pool_memory(PM_MESSAGE);
646    bsock->errmsg = get_pool_memory(PM_MESSAGE);
647    bsock->who = bstrdup(who);
648    bsock->host = bstrdup(host);
649    bsock->port = port;
650    /*
651     * ****FIXME**** reduce this to a few hours once   
652     *   heartbeats are implemented
653     */
654    bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
655    bsock->jcr = jcr;
656    return bsock;
657 }
658
659 BSOCK *
660 dup_bsock(BSOCK *osock)
661 {
662    BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
663    memcpy(bsock, osock, sizeof(BSOCK));
664    bsock->msg = get_pool_memory(PM_MESSAGE);
665    bsock->errmsg = get_pool_memory(PM_MESSAGE);
666    bsock->duped = TRUE;
667    return bsock;
668 }
669
670 /* Close the network connection */
671 void 
672 bnet_close(BSOCK *bsock)
673 {
674    BSOCK *next;
675
676    for ( ; bsock != NULL; bsock = next) {
677       next = bsock->next;
678       if (!bsock->duped) {
679 //       shutdown(bsock->fd, SHUT_RDWR);
680          close(bsock->fd);
681          term_bsock(bsock);
682       } else {
683          free(bsock);
684       }
685    }
686    return;
687 }
688
689 void
690 term_bsock(BSOCK *bsock)
691 {
692    if (bsock->msg) {
693       free_pool_memory(bsock->msg);
694       bsock->msg = NULL;
695    } else {
696       ASSERT(1==0);                   /* double close */
697    }
698    if (bsock->errmsg) {
699       free_pool_memory(bsock->errmsg);
700       bsock->errmsg = NULL;
701    }
702    if (bsock->who) {
703       free(bsock->who);
704       bsock->who = NULL;
705    }
706    if (bsock->host) {
707       free(bsock->host);
708       bsock->host = NULL;
709    }
710    free(bsock);
711 }
712