2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 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 Bacula® is a registered trademark of Kern Sibbald.
17 * Originally written by Kern Sibbald for inclusion in apcupsd,
18 * but heavily modified for Bacula
23 #include <netinet/in.h>
24 #include <sys/socket.h>
26 #include <arpa/inet.h>
28 #ifdef HAVE_ARPA_NAMESER_H
29 #include <arpa/nameser.h>
36 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
40 int allow_severity = LOG_NOTICE;
41 int deny_severity = LOG_WARNING;
44 static bool quit = false;
46 void bnet_stop_thread_server(pthread_t tid)
49 if (!pthread_equal(tid, pthread_self())) {
50 pthread_kill(tid, TIMEOUT_SIGNAL);
55 * Become Threaded Network Server
57 * This function is able to handle multiple server ips in
58 * ipv4 and ipv6 style. The Addresses are given in a comma
59 * seperated string in bind_addr
61 * At the moment it is inpossible to bind different ports.
63 void bnet_thread_server(dlist *addr_list, int max_clients, workq_t *client_wq,
64 void *handle_client_request(void *bsock))
68 struct sockaddr_storage clientaddr; /* client's address */
72 struct request_info request;
76 dlink link; /* this MUST be the first item */
83 char allbuf[256 * 10];
85 remove_duplicate_addresses(addr_list);
87 Dmsg1(20, "Addresses %s\n", build_addresses_str(addr_list, allbuf, sizeof(allbuf)));
90 * Listen on each address provided.
92 foreach_dlist(ipaddr, addr_list) {
93 /* Allocate on stack from -- no need to free */
94 fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
95 fd_ptr->port = ipaddr->get_port_net_order();
99 for (tlog= 60; (fd_ptr->fd=socket(ipaddr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
103 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
105 ipaddr->build_address_str(curbuf, sizeof(curbuf)),
106 build_addresses_str(addr_list, allbuf, sizeof(allbuf)));
113 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
114 sizeof(turnon)) < 0) {
116 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
120 int tmax = 1 * (60 / 5); /* wait 1 minute max */
121 for (tlog = 0; bind(fd_ptr->fd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) == SOCKET_ERROR; tlog -= 5) {
124 tlog = 1 * 60; /* Complain every 1 minute */
125 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
126 ntohs(fd_ptr->port), be.bstrerror());
127 Dmsg2(20, "Cannot bind port %d: ERR=%s: Retrying ...\n",
128 ntohs(fd_ptr->port), be.bstrerror());
133 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
135 Pmsg2(000, "Aborting cannot bind port %d: ERR=%s.\n", ntohs(fd_ptr->port),
139 if (listen(fd_ptr->fd, 50) < 0) { /* tell system we are ready */
141 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
144 sockfds.append(fd_ptr);
147 if (sockfds.size() == 0) {
148 Emsg0(M_ABORT, 0, _("No addr/port found to listen on.\n"));
150 /* Start work queue thread */
151 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
154 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
157 * Wait for a connection from the client process.
160 unsigned int maxfd = 0;
163 foreach_dlist(fd_ptr, &sockfds) {
164 FD_SET((unsigned)fd_ptr->fd, &sockset);
165 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
168 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
169 berrno be; /* capture errno */
170 if (errno == EINTR) {
173 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
177 foreach_dlist(fd_ptr, &sockfds) {
178 if (FD_ISSET(fd_ptr->fd, &sockset)) {
179 /* Got a connection, now accept it. */
181 clilen = sizeof(clientaddr);
182 newsockfd = accept(fd_ptr->fd, (struct sockaddr *)&clientaddr, &clilen);
183 newsockfd = set_socket_errno(newsockfd);
184 } while (newsockfd == SOCKET_ERROR && (errno == EINTR || errno == EAGAIN));
185 if (newsockfd == SOCKET_ERROR) {
186 Dmsg2(20, "Accept=%d errno=%d\n", newsockfd, errno);
190 P(mutex); /* hosts_access is not thread safe */
191 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
193 if (!hosts_access(&request)) {
195 Jmsg2(NULL, M_SECURITY, 0,
196 _("Connection from %s:%d refused by hosts.access\n"),
197 sockaddr_to_ascii((struct sockaddr *)&clientaddr,
198 sizeof(clientaddr), buf, sizeof(buf)),
199 sockaddr_get_port((struct sockaddr *)&clientaddr));
207 * Receive notification when connection dies.
209 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
210 sizeof(turnon)) < 0) {
212 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
216 /* see who client is. i.e. who connected to us. */
218 sockaddr_to_ascii((struct sockaddr *)&clientaddr, sizeof(clientaddr), buf, sizeof(buf));
221 bs = init_bsock(NULL, newsockfd, "client", buf, ntohs(fd_ptr->port),
222 (struct sockaddr *)&clientaddr);
224 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
227 /* Queue client to be served */
228 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
231 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
238 /* Cleanup open files and pointers to them */
239 while ((fd_ptr = (s_sockfd *)sockfds.first())) {
241 sockfds.remove(fd_ptr); /* don't free() item it is on stack */
244 /* Stop work queue thread */
245 if ((stat = workq_destroy(client_wq)) != 0) {
248 Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),