2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Originally written by Kern Sibbald for inclusion in apcupsd,
21 * but heavily modified for Bacula
26 #include <netinet/in.h>
27 #include <sys/socket.h>
29 #include <arpa/inet.h>
31 #ifdef HAVE_ARPA_NAMESER_H
32 #include <arpa/nameser.h>
39 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
43 int allow_severity = LOG_NOTICE;
44 int deny_severity = LOG_WARNING;
47 static bool quit = false;
49 void bnet_stop_thread_server(pthread_t tid)
52 if (!pthread_equal(tid, pthread_self())) {
53 pthread_kill(tid, TIMEOUT_SIGNAL);
58 Become Threaded Network Server
59 This function is able to handle multiple server ips in
60 ipv4 and ipv6 style. The Addresse are give in a comma
61 seperated string in bind_addr
62 In the moment it is inpossible to bind different ports.
64 void bnet_thread_server(dlist *addrs, int max_clients,
65 workq_t *client_wq, void *handle_client_request(void *bsock))
69 struct sockaddr_storage clientaddr; /* client's address */
73 struct request_info request;
77 dlink link; /* this MUST be the first item */
84 char allbuf[256 * 10];
85 remove_duplicate_addresses(addrs);
86 Dmsg1(20, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf)));
88 * Listen on each address provided.
90 foreach_dlist(addr, addrs) {
91 /* Allocate on stack from -- no need to free */
92 fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
93 fd_ptr->port = addr->get_port_net_order();
97 for (tlog= 60; (fd_ptr->fd=socket(addr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
101 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
103 addr->build_address_str(curbuf, sizeof(curbuf)),
104 build_addresses_str(addrs, allbuf, sizeof(allbuf)));
111 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
112 sizeof(turnon)) < 0) {
114 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
118 int tmax = 1 * (60 / 5); /* wait 1 minute max */
119 for (tlog = 0; bind(fd_ptr->fd, addr->get_sockaddr(), addr->get_sockaddr_len()) == SOCKET_ERROR; tlog -= 5) {
122 tlog = 1 * 60; /* Complain every 1 minute */
123 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
124 ntohs(fd_ptr->port), be.bstrerror());
125 Dmsg2(20, "Cannot bind port %d: ERR=%s: Retrying ...\n",
126 ntohs(fd_ptr->port), be.bstrerror());
131 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
133 Pmsg2(000, "Aborting cannot bind port %d: ERR=%s.\n", ntohs(fd_ptr->port),
137 if (listen(fd_ptr->fd, 50) < 0) { /* tell system we are ready */
139 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
142 sockfds.append(fd_ptr);
145 if (sockfds.size() == 0) {
146 Emsg0(M_ABORT, 0, _("No addr/port found to listen on.\n"));
148 /* Start work queue thread */
149 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
152 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
155 * Wait for a connection from the client process.
158 unsigned int maxfd = 0;
161 foreach_dlist(fd_ptr, &sockfds) {
162 FD_SET((unsigned)fd_ptr->fd, &sockset);
163 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
166 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
167 berrno be; /* capture errno */
168 if (errno == EINTR) {
171 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
175 foreach_dlist(fd_ptr, &sockfds) {
176 if (FD_ISSET(fd_ptr->fd, &sockset)) {
177 /* Got a connection, now accept it. */
179 clilen = sizeof(clientaddr);
180 newsockfd = accept(fd_ptr->fd, (struct sockaddr *)&clientaddr, &clilen);
181 newsockfd = set_socket_errno(newsockfd);
182 } while (newsockfd == SOCKET_ERROR && (errno == EINTR || errno == EAGAIN));
183 if (newsockfd == SOCKET_ERROR) {
184 Dmsg2(20, "Accept=%d errno=%d\n", newsockfd, errno);
188 P(mutex); /* hosts_access is not thread safe */
189 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
191 if (!hosts_access(&request)) {
193 Jmsg2(NULL, M_SECURITY, 0,
194 _("Connection from %s:%d refused by hosts.access\n"),
195 sockaddr_to_ascii((struct sockaddr *)&clientaddr,
196 sizeof(clientaddr), buf, sizeof(buf)),
197 sockaddr_get_port((struct sockaddr *)&clientaddr));
205 * Receive notification when connection dies.
207 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
208 sizeof(turnon)) < 0) {
210 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
214 /* see who client is. i.e. who connected to us. */
216 sockaddr_to_ascii((struct sockaddr *)&clientaddr, sizeof(clientaddr), buf, sizeof(buf));
219 bs = init_bsock(NULL, newsockfd, "client", buf, ntohs(fd_ptr->port),
220 (struct sockaddr *)&clientaddr);
222 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
225 /* Queue client to be served */
226 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
229 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
236 /* Cleanup open files and pointers to them */
237 while ((fd_ptr = (s_sockfd *)sockfds.first())) {
239 sockfds.remove(fd_ptr); /* don't free() item it is on stack */
242 /* Stop work queue thread */
243 if ((stat = workq_destroy(client_wq)) != 0) {
246 Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),