2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 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 three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
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 Affero 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 Kern Sibbald.
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 * Originally written by Kern Sibbald for inclusion in apcupsd,
30 * but heavily modified for Bacula
35 #include <netinet/in.h>
36 #include <sys/socket.h>
38 #include <arpa/inet.h>
40 #ifdef HAVE_ARPA_NAMESER_H
41 #include <arpa/nameser.h>
48 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
52 int allow_severity = LOG_NOTICE;
53 int deny_severity = LOG_WARNING;
56 static bool quit = false;
58 void bnet_stop_thread_server(pthread_t tid)
61 if (!pthread_equal(tid, pthread_self())) {
62 pthread_kill(tid, TIMEOUT_SIGNAL);
67 * Become Threaded Network Server
69 * This function is able to handle multiple server ips in
70 * ipv4 and ipv6 style. The Addresse are give in a comma
71 * seperated string in bind_addr
73 * At the moment it is inpossible to bind different ports.
75 void bnet_thread_server(dlist *addr_list, int max_clients, workq_t *client_wq,
76 void *handle_client_request(void *bsock))
80 struct sockaddr cli_addr; /* client's address */
84 struct request_info request;
86 IPADDR *ipaddr, *next;
88 dlink link; /* this MUST be the first item */
95 char allbuf[256 * 10];
98 * Remove any duplicate addresses.
100 for (ipaddr = (IPADDR *)addr_list->first(); ipaddr;
101 ipaddr = (IPADDR *)addr_list->next(ipaddr)) {
102 for (next = (IPADDR *)addr_list->next(ipaddr); next;
103 next = (IPADDR *)addr_list->next(next)) {
104 if (ipaddr->get_sockaddr_len() == next->get_sockaddr_len() &&
105 memcmp(ipaddr->get_sockaddr(), next->get_sockaddr(),
106 ipaddr->get_sockaddr_len()) == 0) {
107 addr_list->remove(next);
112 Dmsg1(100, "Addresses %s\n", build_addresses_str(addr_list, allbuf, sizeof(allbuf)));
114 foreach_dlist(ipaddr, addr_list) {
115 /* Allocate on stack from -- no need to free */
116 fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
117 fd_ptr->port = ipaddr->get_port_net_order();
121 for (tlog= 60; (fd_ptr->fd=socket(ipaddr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
125 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
127 ipaddr->build_address_str(curbuf, sizeof(curbuf)),
128 build_addresses_str(addr_list, allbuf, sizeof(allbuf)));
135 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
136 sizeof(turnon)) < 0) {
138 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
142 int tmax = 30 * (60 / 5); /* wait 30 minutes max */
143 for (tlog = 0; bind(fd_ptr->fd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) < 0; tlog -= 5) {
146 tlog = 2 * 60; /* Complain every 2 minutes */
147 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
148 ntohs(fd_ptr->port), be.bstrerror());
152 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
156 listen(fd_ptr->fd, 50); /* tell system we are ready */
157 sockfds.append(fd_ptr);
159 /* Start work queue thread */
160 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
163 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
166 * Wait for a connection from the client process.
169 unsigned int maxfd = 0;
172 foreach_dlist(fd_ptr, &sockfds) {
173 FD_SET((unsigned)fd_ptr->fd, &sockset);
174 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
177 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
178 berrno be; /* capture errno */
179 if (errno == EINTR) {
182 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
186 foreach_dlist(fd_ptr, &sockfds) {
187 if (FD_ISSET(fd_ptr->fd, &sockset)) {
188 /* Got a connection, now accept it. */
190 clilen = sizeof(cli_addr);
191 newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
192 } while (newsockfd < 0 && errno == EINTR);
197 P(mutex); /* hosts_access is not thread safe */
198 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
200 if (!hosts_access(&request)) {
202 Jmsg2(NULL, M_SECURITY, 0,
203 _("Connection from %s:%d refused by hosts.access\n"),
204 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)),
205 sockaddr_get_port(&cli_addr));
213 * Receive notification when connection dies.
215 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
216 sizeof(turnon)) < 0) {
218 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
222 /* see who client is. i.e. who connected to us. */
224 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
227 bs = init_bsock(NULL, newsockfd, "client", buf, ntohs(fd_ptr->port), &cli_addr);
229 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
232 /* Queue client to be served */
233 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
236 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
243 /* Cleanup open files and pointers to them */
244 while ((fd_ptr = (s_sockfd *)sockfds.first())) {
246 sockfds.remove(fd_ptr); /* don't free() item it is on stack */
249 /* Stop work queue thread */
250 if ((stat = workq_destroy(client_wq)) != 0) {
253 Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),