2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation plus additions
11 that are listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Network Utility Routines
33 * Adapted and enhanced for Bacula, originally written
34 * for inclusion in the Apcupsd package
44 extern time_t watchdog_time;
47 #define INADDR_NONE -1
51 #define socketRead(fd, buf, len) recv(fd, buf, len, 0)
52 #define socketWrite(fd, buf, len) send(fd, buf, len, 0)
53 #define socketClose(fd) closesocket(fd)
55 #define socketRead(fd, buf, len) read(fd, buf, len)
56 #define socketWrite(fd, buf, len) write(fd, buf, len)
57 #define socketClose(fd) close(fd)
60 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
63 * Read a nbytes from the network.
64 * It is possible that the total bytes require in several
68 int32_t read_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
75 return (tls_bsock_readn(bsock, ptr, nbytes));
82 nread = socketRead(bsock->fd, ptr, nleft);
83 if (bsock->timed_out || bsock->terminated) {
90 if (errno == EAGAIN) {
91 bmicrosleep(0, 200000); /* try again in 200ms */
96 return nread; /* error, or EOF */
101 return nbytes - nleft; /* return >= 0 */
105 * Write nbytes to the network.
106 * It may require several writes.
109 int32_t write_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
111 int32_t nleft, nwritten;
114 nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
115 if (nwritten != nbytes) {
117 bsock->b_errno = errno;
118 Qmsg1(bsock->jcr(), M_FATAL, 0, _("Attr spool write error. ERR=%s\n"),
120 Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
121 errno = bsock->b_errno;
130 return (tls_bsock_writen(bsock, ptr, nbytes));
132 #endif /* HAVE_TLS */
138 nwritten = socketWrite(bsock->fd, ptr, nleft);
139 if (bsock->timed_out || bsock->terminated) {
142 } while (nwritten == -1 && errno == EINTR);
144 * If connection is non-blocking, we will get EAGAIN, so
145 * use select() to keep from consuming all the CPU
148 if (nwritten == -1 && errno == EAGAIN) {
153 FD_SET((unsigned)bsock->fd, &fdset);
156 select(bsock->fd + 1, NULL, &fdset, NULL, &tv);
160 return nwritten; /* error */
165 return nbytes - nleft;
169 * Receive a message from the other end. Each message consists of
170 * two packets. The first is a header that contains the size
171 * of the data that follows in the second packet.
172 * Returns number of bytes read (may return zero)
173 * Returns -1 on signal (BNET_SIGNAL)
174 * Returns -2 on hard end of file (BNET_HARDEOF)
175 * Returns -3 on error (BNET_ERROR)
177 * Unfortunately, it is a bit complicated because we have these
180 * 2. Signal including end of data stream
181 * 3. Hard end of file
183 * Using is_bnet_stop() and is_bnet_error() you can figure this all out.
185 int32_t bnet_recv(BSOCK * bsock)
187 return bsock->recv();
192 * Return 1 if there are errors on this bsock or it is closed,
193 * i.e. stop communicating on this line.
195 bool is_bnet_stop(BSOCK * bsock)
197 return bsock->errors || bsock->terminated;
201 * Return number of errors on socket
203 int is_bnet_error(BSOCK * bsock)
205 errno = bsock->b_errno;
206 return bsock->errors;
210 * Call here after error during closing to suppress error
211 * messages which are due to the other end shutting down too.
213 void bnet_suppress_error_messages(BSOCK * bsock, bool flag)
215 bsock->suppress_error_msgs = flag;
219 * Send a message over the network. The send consists of
220 * two network packets. The first is sends a 32 bit integer containing
221 * the length of the data packet which follows.
223 * Returns: false on failure
226 bool bnet_send(BSOCK *bsock)
228 return bsock->send();
233 * Establish a TLS connection -- server side
234 * Returns: true on success
238 bool bnet_tls_server(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
242 tls = new_tls_connection(ctx, bsock->fd);
244 Qmsg0(bsock->jcr(), M_FATAL, 0, _("TLS connection initialization failed.\n"));
250 /* Initiate TLS Negotiation */
251 if (!tls_bsock_accept(bsock)) {
252 Qmsg0(bsock->jcr(), M_FATAL, 0, _("TLS Negotiation failed.\n"));
257 if (!tls_postconnect_verify_cn(tls, verify_list)) {
258 Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS certificate verification failed."
259 " Peer certificate did not match a required commonName\n"),
267 free_tls_connection(tls);
273 * Establish a TLS connection -- client side
274 * Returns: true on success
277 bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
281 tls = new_tls_connection(ctx, bsock->fd);
283 Qmsg0(bsock->jcr(), M_FATAL, 0, _("TLS connection initialization failed.\n"));
289 /* Initiate TLS Negotiation */
290 if (!tls_bsock_connect(bsock)) {
294 /* If there's an Allowed CN verify list, use that to validate the remote
295 * certificate's CN. Otherwise, we use standard host/CN matching. */
297 if (!tls_postconnect_verify_cn(tls, verify_list)) {
298 Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS certificate verification failed."
299 " Peer certificate did not match a required commonName\n"),
304 if (!tls_postconnect_verify_host(tls, bsock->host())) {
305 Qmsg1(bsock->jcr(), M_FATAL, 0, _("TLS host certificate verification failed. Host %s did not match presented certificate\n"),
314 free_tls_connection(tls);
320 bool bnet_tls_server(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
322 Jmsg(bsock->jcr(), M_ABORT, 0, _("TLS enabled but not configured.\n"));
326 bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list)
328 Jmsg(bsock->jcr(), M_ABORT, 0, _("TLS enable but not configured.\n"));
332 #endif /* HAVE_TLS */
335 * Wait for a specified time for data to appear on
336 * the BSOCK connection.
338 * Returns: 1 if data available
342 int bnet_wait_data(BSOCK * bsock, int sec)
348 FD_SET((unsigned)bsock->fd, &fdset);
352 switch (select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
353 case 0: /* timeout */
357 bsock->b_errno = errno;
358 if (errno == EINTR) {
361 return -1; /* error return */
370 * As above, but returns on interrupt
372 int bnet_wait_data_intr(BSOCK * bsock, int sec)
378 FD_SET((unsigned)bsock->fd, &fdset);
381 switch (select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
382 case 0: /* timeout */
386 bsock->b_errno = errno;
387 return -1; /* error return */
394 #ifndef NETDB_INTERNAL
395 #define NETDB_INTERNAL -1 /* See errno. */
397 #ifndef NETDB_SUCCESS
398 #define NETDB_SUCCESS 0 /* No problem. */
400 #ifndef HOST_NOT_FOUND
401 #define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found. */
404 #define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL. */
407 #define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
410 #define NO_DATA 4 /* Valid name, no data record of requested type. */
414 * Get human readable error for gethostbyname()
416 static const char *gethost_strerror()
422 msg = be.bstrerror();
425 msg = _("No problem.");
428 msg = _("Authoritative answer for host not found.");
431 msg = _("Non-authoritative for host not found, or ServerFail.");
434 msg = _("Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.");
437 msg = _("Valid name, no data record of resquested type.");
440 msg = _("Unknown error.");
448 static IPADDR *add_any(int family)
450 IPADDR *addr = New(IPADDR(family));
451 addr->set_type(IPADDR::R_MULTIPLE);
452 addr->set_addr_any();
456 static const char *resolv_host(int family, const char *host, dlist * addr_list)
461 P(ip_mutex); /* gethostbyname() is not thread safe */
462 #ifdef HAVE_GETHOSTBYNAME2
463 if ((hp = gethostbyname2(host, family)) == NULL) {
465 if ((hp = gethostbyname(host)) == NULL) {
467 /* may be the strerror give not the right result -:( */
468 errmsg = gethost_strerror();
473 for (p = hp->h_addr_list; *p != 0; p++) {
474 IPADDR *addr = New(IPADDR(hp->h_addrtype));
475 addr->set_type(IPADDR::R_MULTIPLE);
476 if (addr->get_family() == AF_INET) {
477 addr->set_addr4((struct in_addr*)*p);
481 addr->set_addr6((struct in6_addr*)*p);
484 addr_list->append(addr);
492 * i host = 0 mean INADDR_ANY only ipv4
494 dlist *bnet_host2ipaddrs(const char *host, int family, const char **errstr)
496 struct in_addr inaddr;
500 struct in6_addr inaddr6;
503 dlist *addr_list = New(dlist(addr, &addr->link));
504 if (!host || host[0] == '\0') {
506 addr_list->append(add_any(family));
508 addr_list->append(add_any(AF_INET));
510 addr_list->append(add_any(AF_INET6));
513 } else if (inet_aton(host, &inaddr)) { /* MA Bug 4 */
514 addr = New(IPADDR(AF_INET));
515 addr->set_type(IPADDR::R_MULTIPLE);
516 addr->set_addr4(&inaddr);
517 addr_list->append(addr);
520 if (inet_pton(AF_INET6, host, &inaddr6) > 1) {
521 addr = New(IPADDR(AF_INET6));
522 addr->set_type(IPADDR::R_MULTIPLE);
523 addr->set_addr6(&inaddr6);
524 addr_list->append(addr);
529 errmsg = resolv_host(family, host, addr_list);
532 free_addresses(addr_list);
536 errmsg = resolv_host(AF_INET, host, addr_list);
539 errmsg = resolv_host(AF_INET6, host, addr_list);
544 free_addresses(addr_list);
553 * Open a TCP connection to the UPS network server
555 * Returns BSOCK * pointer on success
558 static BSOCK *bnet_open(JCR *jcr, const char *name, char *host, char *service,
559 int port, utime_t heart_beat, int *fatal)
564 bool connected = false;
570 * Fill in the structure serv_addr with the address of
571 * the server that we want to connect with.
573 if ((addr_list = bnet_host2ipaddrs(host, 0, &errstr)) == NULL) {
574 /* Note errstr is not malloc'ed */
575 Qmsg2(jcr, M_ERROR, 0, _("gethostbyname() for host \"%s\" failed: ERR=%s\n"),
577 Dmsg2(100, "bnet_host2ipaddrs() for host %s failed: ERR=%s\n",
583 foreach_dlist(ipaddr, addr_list) {
584 ipaddr->set_port_net(htons(port));
585 char allbuf[256 * 10];
587 Dmsg2(100, "Current %sAll %s\n",
588 ipaddr->build_address_str(curbuf, sizeof(curbuf)),
589 build_addresses_str(addr_list, allbuf, sizeof(allbuf)));
590 /* Open a TCP socket */
591 if ((sockfd = socket(ipaddr->get_family(), SOCK_STREAM, 0)) < 0) {
595 Pmsg3(000, _("Socket open error. proto=%d port=%d. ERR=%s\n"),
596 ipaddr->get_family(), ipaddr->get_port_host_order(), be.bstrerror());
600 * Keep socket from timing out from inactivity
602 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
604 Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
607 #if defined(TCP_KEEPIDLE)
610 if (setsockopt(sockfd, IPPROTO_IP, TCP_KEEPIDLE, (sockopt_val_t)&opt, sizeof(opt)) < 0) {
612 Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPIDLE on socket: %s\n"),
618 /* connect to server */
619 if (connect(sockfd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) < 0) {
630 free_addresses(addr_list);
631 errno = save_errno | b_errno_win32;
635 * Keep socket from timing out from inactivity
636 * Do this a second time out of paranoia
638 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
640 Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
643 BSOCK* ret = init_bsock(jcr, sockfd, name, host, port, ipaddr->get_sockaddr());
644 free_addresses(addr_list);
649 * Try to connect to host for max_retry_time at retry_time intervals.
651 BSOCK *bnet_connect(JCR * jcr, int retry_interval, utime_t max_retry_time,
653 const char *name, char *host, char *service, int port,
659 time_t begin_time = time(NULL);
661 btimer_t *tid = NULL;
663 /* Try to trap out of OS call when time expires */
664 if (max_retry_time) {
665 tid = start_thread_timer(pthread_self(), (uint32_t)max_retry_time);
668 for (i = 0; (bsock = bnet_open(jcr, name, host, service, port, heart_beat, &fatal)) == NULL;
669 i -= retry_interval) {
671 if (fatal || (jcr && job_canceled(jcr))) {
675 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
676 name, host, port, be.bstrerror());
678 i = 60 * 5; /* complain again in 5 minutes */
680 Qmsg4(jcr, M_WARNING, 0, _(
681 "Could not connect to %s on %s:%d. ERR=%s\n"
682 "Retrying ...\n"), name, host, port, be.bstrerror());
684 bmicrosleep(retry_interval, 0);
686 if (begin_time + max_retry_time <= now) {
687 Qmsg4(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
688 name, host, port, be.bstrerror());
696 stop_thread_timer(tid);
703 * Return the string for the error that occurred
704 * on the socket. Only the first error is retained.
706 const char *bnet_strerror(BSOCK * bsock)
709 if (bsock->errmsg == NULL) {
710 bsock->errmsg = get_pool_memory(PM_MESSAGE);
712 pm_strcpy(bsock->errmsg, be.bstrerror(bsock->b_errno));
713 return bsock->errmsg;
717 * Format and send a message
718 * Returns: false on error
721 bool bnet_fsend(BSOCK * bs, const char *fmt, ...)
726 if (bs->errors || bs->terminated) {
729 /* This probably won't work, but we vsnprintf, then if we
730 * get a negative length or a length greater than our buffer
731 * (depending on which library is used), the printf was truncated, so
732 * get a bigger buffer and try again.
735 maxlen = sizeof_pool_memory(bs->msg) - 1;
736 va_start(arg_ptr, fmt);
737 bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
739 if (bs->msglen > 0 && bs->msglen < (maxlen - 5)) {
742 bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
747 int bnet_get_peer(BSOCK *bs, char *buf, socklen_t buflen)
749 #if !defined(HAVE_WIN32)
750 if (bs->peer_addr.sin_family == 0) {
751 socklen_t salen = sizeof(bs->peer_addr);
752 int rval = (getpeername)(bs->fd, (struct sockaddr *)&bs->peer_addr, &salen);
753 if (rval < 0) return rval;
755 if (!inet_ntop(bs->peer_addr.sin_family, &bs->peer_addr.sin_addr, buf, buflen))
764 * Set the network buffer size, suggested size is in size.
765 * Actual size obtained is returned in bs->msglen
767 * Returns: 0 on failure
770 bool bnet_set_buffer_size(BSOCK * bs, uint32_t size, int rw)
772 uint32_t dbuf_size, start_size;
773 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
775 opt = IPTOS_THROUGHPUT;
776 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
782 dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
784 start_size = dbuf_size;
785 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size + 100)) == NULL) {
786 Qmsg0(bs->jcr(), M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
789 if (rw & BNET_SETBUF_READ) {
790 while ((dbuf_size > TAPE_BSIZE) && (setsockopt(bs->fd, SOL_SOCKET,
791 SO_RCVBUF, (sockopt_val_t) & dbuf_size, sizeof(dbuf_size)) < 0)) {
793 Qmsg1(bs->jcr(), M_ERROR, 0, _("sockopt error: %s\n"), be.bstrerror());
794 dbuf_size -= TAPE_BSIZE;
796 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
797 if (dbuf_size != start_size) {
798 Qmsg1(bs->jcr(), M_WARNING, 0,
799 _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
801 if (dbuf_size % TAPE_BSIZE != 0) {
802 Qmsg1(bs->jcr(), M_ABORT, 0,
803 _("Network buffer size %d not multiple of tape block size.\n"),
810 dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
812 start_size = dbuf_size;
813 if (rw & BNET_SETBUF_WRITE) {
814 while ((dbuf_size > TAPE_BSIZE) && (setsockopt(bs->fd, SOL_SOCKET,
815 SO_SNDBUF, (sockopt_val_t) & dbuf_size, sizeof(dbuf_size)) < 0)) {
817 Qmsg1(bs->jcr(), M_ERROR, 0, _("sockopt error: %s\n"), be.bstrerror());
818 dbuf_size -= TAPE_BSIZE;
820 Dmsg1(900, "set network buffer size=%d\n", dbuf_size);
821 if (dbuf_size != start_size) {
822 Qmsg1(bs->jcr(), M_WARNING, 0,
823 _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
825 if (dbuf_size % TAPE_BSIZE != 0) {
826 Qmsg1(bs->jcr(), M_ABORT, 0,
827 _("Network buffer size %d not multiple of tape block size.\n"),
832 bs->msglen = dbuf_size;
837 * Set socket non-blocking
838 * Returns previous socket flag
840 int bnet_set_nonblocking (BSOCK *bsock) {
844 /* Get current flags */
845 if ((oflags = fcntl(bsock->fd, F_GETFL, 0)) < 0) {
847 Jmsg1(bsock->jcr(), M_ABORT, 0, _("fcntl F_GETFL error. ERR=%s\n"), be.bstrerror());
850 /* Set O_NONBLOCK flag */
851 if ((fcntl(bsock->fd, F_SETFL, oflags|O_NONBLOCK)) < 0) {
853 Jmsg1(bsock->jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
862 flags = bsock->blocking;
863 ioctlsocket(bsock->fd, FIONBIO, &ioctlArg);
871 * Set socket blocking
872 * Returns previous socket flags
874 int bnet_set_blocking (BSOCK *bsock)
878 /* Get current flags */
879 if ((oflags = fcntl(bsock->fd, F_GETFL, 0)) < 0) {
881 Jmsg1(bsock->jcr(), M_ABORT, 0, _("fcntl F_GETFL error. ERR=%s\n"), be.bstrerror());
884 /* Set O_NONBLOCK flag */
885 if ((fcntl(bsock->fd, F_SETFL, oflags & ~O_NONBLOCK)) < 0) {
887 Jmsg1(bsock->jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
896 flags = bsock->blocking;
897 ioctlsocket(bsock->fd, FIONBIO, &ioctlArg);
905 * Restores socket flags
907 void bnet_restore_blocking (BSOCK *bsock, int flags)
910 if ((fcntl(bsock->fd, F_SETFL, flags)) < 0) {
912 Jmsg1(bsock->jcr(), M_ABORT, 0, _("fcntl F_SETFL error. ERR=%s\n"), be.bstrerror());
915 bsock->blocking = (flags & O_NONBLOCK);
917 u_long ioctlArg = flags;
919 ioctlsocket(bsock->fd, FIONBIO, &ioctlArg);
926 * Send a network "signal" to the other end
927 * This consists of sending a negative packet length
929 * Returns: false on failure
932 bool bnet_sig(BSOCK * bs, int signal)
934 return bs->signal(signal);
938 * Convert a network "signal" code into
939 * human readable ASCII.
941 const char *bnet_sig_to_ascii(BSOCK * bs)
944 switch (bs->msglen) {
946 return "BNET_EOD"; /* end of data stream */
948 return "BNET_EOD_POLL";
950 return "BNET_STATUS";
952 return "BNET_TERMINATE"; /* terminate connection */
956 return "BNET_HEARTBEAT";
957 case BNET_HB_RESPONSE:
958 return "BNET_HB_RESPONSE";
960 return "BNET_PROMPT";
962 sprintf(buf, _("Unknown sig %d"), (int)bs->msglen);
968 /* Initialize internal socket structure.
969 * This probably should be done in net_open
971 BSOCK *init_bsock(JCR * jcr, int sockfd, const char *who, const char *host, int port,
972 struct sockaddr *client_addr)
974 Dmsg3(100, "who=%s host=%s port=%d\n", who, host, port);
975 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
976 memset(bsock, 0, sizeof(BSOCK));
981 bsock->msg = get_pool_memory(PM_MESSAGE);
982 bsock->errmsg = get_pool_memory(PM_MESSAGE);
983 bsock->set_who(bstrdup(who));
984 bsock->set_host(bstrdup(host));
985 bsock->set_port(port);
986 memset(&bsock->peer_addr, 0, sizeof(bsock->peer_addr));
987 memcpy(&bsock->client_addr, client_addr, sizeof(bsock->client_addr));
989 * ****FIXME**** reduce this to a few hours once
990 * heartbeats are implemented
992 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
997 BSOCK *dup_bsock(BSOCK * osock)
999 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
1000 memcpy(bsock, osock, sizeof(BSOCK));
1001 bsock->msg = get_pool_memory(PM_MESSAGE);
1002 bsock->errmsg = get_pool_memory(PM_MESSAGE);
1004 bsock->set_who(bstrdup(osock->who()));
1006 if (osock->host()) {
1007 bsock->set_host(bstrdup(osock->host()));
1009 bsock->duped = true;
1013 /* Close the network connection */
1014 void bnet_close(BSOCK * bsock)
1016 bsock->close(); /* this calls destroy */
1019 void term_bsock(BSOCK * bsock)