/* * Copy the address from the configuration dlist that gets passed in */ void BSOCK::set_source_address(dlist *src_addr_list) { char allbuf[256 * 10]; IPADDR *addr = NULL; Dmsg1(100, "All source addresses %s\n", build_addresses_str(src_addr_list, allbuf, sizeof(allbuf))); /* * Delete the object we already have, if it's allocated */ if (src_addr) { free( src_addr); src_addr = NULL; } if (src_addr_list) { addr = (IPADDR*) src_addr_list->first(); src_addr = New(IPADDR(*addr)); } }
/* * Become Threaded Network Server * * This function is able to handle multiple server ips in * ipv4 and ipv6 style. The Addresse are give in a comma * seperated string in bind_addr * * At the moment it is impossible to bind to different ports. */ void bnet_thread_server(dlist *addr_list, int max_clients, alist *sockfds, workq_t *client_wq, void *handle_client_request(void *bsock)) { int newsockfd, status; socklen_t clilen; struct sockaddr cli_addr; /* client's address */ int tlog, tmax; int turnon = 1; #ifdef HAVE_LIBWRAP struct request_info request; #endif IPADDR *ipaddr, *next; s_sockfd *fd_ptr = NULL; char buf[128]; #ifdef HAVE_POLL nfds_t nfds; struct pollfd *pfds; #endif char allbuf[256 * 10]; /* * Remove any duplicate addresses. */ for (ipaddr = (IPADDR *)addr_list->first(); ipaddr; ipaddr = (IPADDR *)addr_list->next(ipaddr)) { for (next = (IPADDR *)addr_list->next(ipaddr); next; next = (IPADDR *)addr_list->next(next)) { if (ipaddr->get_sockaddr_len() == next->get_sockaddr_len() && memcmp(ipaddr->get_sockaddr(), next->get_sockaddr(), ipaddr->get_sockaddr_len()) == 0) { addr_list->remove(next); } } } Dmsg1(100, "Addresses %s\n", build_addresses_str(addr_list, allbuf, sizeof(allbuf))); #ifdef HAVE_POLL nfds = 0; #endif foreach_dlist(ipaddr, addr_list) { /* * Allocate on stack from -- no need to free */ fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd)); fd_ptr->port = ipaddr->get_port_net_order(); /* * Open a TCP socket */ for (tlog= 60; (fd_ptr->fd=socket(ipaddr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) { if (tlog <= 0) { berrno be; char curbuf[256]; Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"), be.bstrerror(), ipaddr->build_address_str(curbuf, sizeof(curbuf)), build_addresses_str(addr_list, allbuf, sizeof(allbuf))); } bmicrosleep(10, 0); } /* * Reuse old sockets */ if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) { berrno be; Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"), be.bstrerror()); } tmax = 30 * (60 / 5); /* wait 30 minutes max */ for (tlog = 0; bind(fd_ptr->fd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) < 0; tlog -= 5) { berrno be; if (tlog <= 0) { tlog = 2 * 60; /* Complain every 2 minutes */ Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"), ntohs(fd_ptr->port), be.bstrerror()); } bmicrosleep(5, 0); if (--tmax <= 0) { Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port), be.bstrerror()); } } listen(fd_ptr->fd, 50); /* tell system we are ready */ sockfds->append(fd_ptr); #ifdef HAVE_POLL nfds++; #endif }
/* * Open a TCP connection to the server * Returns NULL * Returns BSOCK * pointer on success * */ bool BSOCK::open(JCR *jcr, const char *name, char *host, char *service, int port, utime_t heart_beat, int *fatal) { int sockfd = -1; dlist *addr_list; IPADDR *ipaddr; bool connected = false; int turnon = 1; const char *errstr; int save_errno = 0; /* * Fill in the structure serv_addr with the address of * the server that we want to connect with. */ if ((addr_list = bnet_host2ipaddrs(host, 0, &errstr)) == NULL) { /* Note errstr is not malloc'ed */ Qmsg2(jcr, M_ERROR, 0, _("gethostbyname() for host \"%s\" failed: ERR=%s\n"), host, errstr); Dmsg2(100, "bnet_host2ipaddrs() for host %s failed: ERR=%s\n", host, errstr); *fatal = 1; return false; } foreach_dlist(ipaddr, addr_list) { ipaddr->set_port_net(htons(port)); char allbuf[256 * 10]; char curbuf[256]; Dmsg2(100, "Current %sAll %s\n", ipaddr->build_address_str(curbuf, sizeof(curbuf)), build_addresses_str(addr_list, allbuf, sizeof(allbuf))); /* Open a TCP socket */ if ((sockfd = socket(ipaddr->get_family(), SOCK_STREAM, 0)) < 0) { berrno be; save_errno = errno; *fatal = 1; Pmsg3(000, _("Socket open error. proto=%d port=%d. ERR=%s\n"), ipaddr->get_family(), ipaddr->get_port_host_order(), be.bstrerror()); continue; } /* Bind to the source address if it is set */ if (src_addr) { if (bind(sockfd, src_addr->get_sockaddr(), src_addr->get_sockaddr_len()) < 0) { berrno be; save_errno = errno; *fatal = 1; Pmsg2(000, _("Source address bind error. proto=%d. ERR=%s\n"), src_addr->get_family(), be.bstrerror() ); continue; } } /* * Keep socket from timing out from inactivity */ if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) { berrno be; Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), be.bstrerror()); } #if defined(TCP_KEEPIDLE) if (heart_beat) { int opt = heart_beat if (setsockopt(sockfd, IPPROTO_IP, TCP_KEEPIDLE, (sockopt_val_t)&opt, sizeof(opt)) < 0) { berrno be; Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPIDLE on socket: %s\n"), be.bstrerror()); } } #endif /* connect to server */ if (::connect(sockfd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) < 0) { save_errno = errno; socketClose(sockfd); continue; } *fatal = 0; connected = true; break; }