2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Originally written by Kern Sibbald for inclusion in apcupsd,
22 * but heavily modified for Bacula
27 #include <netinet/in.h>
28 #include <sys/socket.h>
30 #include <arpa/inet.h>
32 #ifdef HAVE_ARPA_NAMESER_H
33 #include <arpa/nameser.h>
40 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
44 int allow_severity = LOG_NOTICE;
45 int deny_severity = LOG_WARNING;
48 static bool quit = false;
50 void bnet_stop_thread_server(pthread_t tid)
53 if (!pthread_equal(tid, pthread_self())) {
54 pthread_kill(tid, TIMEOUT_SIGNAL);
59 Become Threaded Network Server
60 This function is able to handle multiple server ips in
61 ipv4 and ipv6 style. The Addresse are give in a comma
62 seperated string in bind_addr
63 In the moment it is inpossible to bind different ports.
65 void bnet_thread_server(dlist *addrs, int max_clients,
66 workq_t *client_wq, void *handle_client_request(void *bsock))
70 struct sockaddr_storage clientaddr; /* client's address */
74 struct request_info request;
78 dlink link; /* this MUST be the first item */
85 char allbuf[256 * 10];
86 remove_duplicate_addresses(addrs);
87 Dmsg1(20, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf)));
89 * Listen on each address provided.
91 foreach_dlist(addr, addrs) {
92 /* Allocate on stack from -- no need to free */
93 fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
94 fd_ptr->port = addr->get_port_net_order();
98 for (tlog= 60; (fd_ptr->fd=socket(addr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
102 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
104 addr->build_address_str(curbuf, sizeof(curbuf)),
105 build_addresses_str(addrs, allbuf, sizeof(allbuf)));
112 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
113 sizeof(turnon)) < 0) {
115 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
119 int tmax = 1 * (60 / 5); /* wait 1 minute max */
120 for (tlog = 0; bind(fd_ptr->fd, addr->get_sockaddr(), addr->get_sockaddr_len()) == SOCKET_ERROR; tlog -= 5) {
123 tlog = 1 * 60; /* Complain every 1 minute */
124 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
125 ntohs(fd_ptr->port), be.bstrerror());
126 Dmsg2(20, "Cannot bind port %d: ERR=%s: Retrying ...\n",
127 ntohs(fd_ptr->port), be.bstrerror());
132 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
134 Pmsg2(000, "Aborting cannot bind port %d: ERR=%s.\n", ntohs(fd_ptr->port),
138 if (listen(fd_ptr->fd, 50) < 0) { /* tell system we are ready */
140 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
143 sockfds.append(fd_ptr);
146 if (sockfds.size() == 0) {
147 Emsg0(M_ABORT, 0, _("No addr/port found to listen on.\n"));
149 /* Start work queue thread */
150 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
153 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
156 * Wait for a connection from the client process.
159 unsigned int maxfd = 0;
162 foreach_dlist(fd_ptr, &sockfds) {
163 FD_SET((unsigned)fd_ptr->fd, &sockset);
164 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
167 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
168 berrno be; /* capture errno */
169 if (errno == EINTR) {
172 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
176 foreach_dlist(fd_ptr, &sockfds) {
177 if (FD_ISSET(fd_ptr->fd, &sockset)) {
178 /* Got a connection, now accept it. */
180 clilen = sizeof(clientaddr);
181 newsockfd = accept(fd_ptr->fd, (struct sockaddr *)&clientaddr, &clilen);
182 newsockfd = set_socket_errno(newsockfd);
183 } while (newsockfd == SOCKET_ERROR && (errno == EINTR || errno == EAGAIN));
184 if (newsockfd == SOCKET_ERROR) {
185 Dmsg2(20, "Accept=%d errno=%d\n", newsockfd, errno);
189 P(mutex); /* hosts_access is not thread safe */
190 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
192 if (!hosts_access(&request)) {
194 Jmsg2(NULL, M_SECURITY, 0,
195 _("Connection from %s:%d refused by hosts.access\n"),
196 sockaddr_to_ascii((struct sockaddr *)&clientaddr,
197 sizeof(clientaddr), buf, sizeof(buf)),
198 sockaddr_get_port((struct sockaddr *)&clientaddr));
206 * Receive notification when connection dies.
208 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
209 sizeof(turnon)) < 0) {
211 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
215 /* see who client is. i.e. who connected to us. */
217 sockaddr_to_ascii((struct sockaddr *)&clientaddr, sizeof(clientaddr), buf, sizeof(buf));
220 bs = init_bsock(NULL, newsockfd, "client", buf, ntohs(fd_ptr->port),
221 (struct sockaddr *)&clientaddr);
223 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
226 /* Queue client to be served */
227 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
230 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
237 /* Cleanup open files and pointers to them */
238 while ((fd_ptr = (s_sockfd *)sockfds.first())) {
240 sockfds.remove(fd_ptr); /* don't free() item it is on stack */
243 /* Stop work queue thread */
244 if ((stat = workq_destroy(client_wq)) != 0) {
247 Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),