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