2 * Originally written by Kern Sibbald for inclusion in apcupsd,
3 * but heavily modified for Bacula
9 Bacula® - The Network Backup Solution
11 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
13 The main author of Bacula is Kern Sibbald, with contributions from
14 many others, a complete list can be found in the file AUTHORS.
15 This program is Free Software; you can redistribute it and/or
16 modify it under the terms of version two of the GNU General Public
17 License as published by the Free Software Foundation plus additions
18 that are listed in the file LICENSE.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 Bacula® is a registered trademark of John Walker.
31 The licensor of Bacula is the Free Software Foundation Europe
32 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33 Switzerland, email:ftf@fsfeurope.org.
38 #include <netinet/in.h>
39 #include <sys/socket.h>
41 #include <arpa/inet.h>
43 #ifdef HAVE_ARPA_NAMESER_H
44 #include <arpa/nameser.h>
51 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
55 int allow_severity = LOG_NOTICE;
56 int deny_severity = LOG_WARNING;
59 static bool quit = false;
61 void bnet_stop_thread_server(pthread_t tid)
64 if (!pthread_equal(tid, pthread_self())) {
65 pthread_kill(tid, TIMEOUT_SIGNAL);
70 Become Threaded Network Server
71 This function is able to handle multiple server ips in
72 ipv4 and ipv6 style. The Addresse are give in a comma
73 seperated string in bind_addr
74 In the moment it is inpossible to bind different ports.
77 bnet_thread_server(dlist *addrs, int max_clients, workq_t *client_wq,
78 void *handle_client_request(void *bsock))
82 struct sockaddr cli_addr; /* client's address */
86 struct request_info request;
90 dlink link; /* this MUST be the first item */
97 char allbuf[256 * 10];
98 Dmsg1(100, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf)));
100 foreach_dlist(p, addrs) {
101 /* Allocate on stack frame -- no need to free */
102 fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
103 fd_ptr->port = p->get_port_net_order();
107 for (tlog= 60; (fd_ptr->fd=socket(p->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
111 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
113 p->build_address_str(curbuf, sizeof(curbuf)),
114 build_addresses_str(addrs, allbuf, sizeof(allbuf)));
121 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
122 sizeof(turnon)) < 0) {
124 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
128 int tmax = 30 * (60 / 5); /* wait 30 minutes max */
129 for (tlog = 0; bind(fd_ptr->fd, p->get_sockaddr(), p->get_sockaddr_len()) < 0; tlog -= 5) {
132 tlog = 2 * 60; /* Complain every 2 minutes */
133 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
134 ntohs(fd_ptr->port), be.strerror());
138 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
142 listen(fd_ptr->fd, 5); /* tell system we are ready */
143 sockfds.append(fd_ptr);
145 /* Start work queue thread */
146 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
149 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.strerror());
152 * Wait for a connection from the client process.
155 unsigned int maxfd = 0;
158 foreach_dlist(fd_ptr, &sockfds) {
159 FD_SET((unsigned)fd_ptr->fd, &sockset);
160 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
163 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
164 berrno be; /* capture errno */
165 if (errno == EINTR) {
169 foreach_dlist(fd_ptr, &sockfds) {
172 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.strerror());
176 foreach_dlist(fd_ptr, &sockfds) {
177 if (FD_ISSET(fd_ptr->fd, &sockset)) {
178 /* Got a connection, now accept it. */
180 clilen = sizeof(cli_addr);
181 newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
182 } while (newsockfd < 0 && errno == EINTR);
187 P(mutex); /* hosts_access is not thread safe */
188 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
190 if (!hosts_access(&request)) {
192 Jmsg2(NULL, M_SECURITY, 0,
193 _("Connection from %s:%d refused by hosts.access\n"),
194 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)),
195 sockaddr_get_port(&cli_addr));
203 * Receive notification when connection dies.
205 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
206 sizeof(turnon)) < 0) {
208 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
212 /* see who client is. i.e. who connected to us. */
214 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
217 bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr);
219 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
222 /* Queue client to be served */
223 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
226 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
233 /* Stop work queue thread */
234 if ((stat = workq_destroy(client_wq)) != 0) {
237 Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),
245 * Bind an address so that we may accept connections
248 BSOCK *bnet_bind(int port)
251 struct sockaddr_in serv_addr; /* our address */
258 for (tlog = 0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10) {
259 if (errno == EINTR || errno == EAGAIN) {
264 Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), strerror(errno));
272 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
273 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
278 * Bind our local address so that the client can send to us.
280 bzero((char *)&serv_addr, sizeof(serv_addr));
281 serv_addr.sin_family = AF_INET;
282 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
283 serv_addr.sin_port = htons(port);
285 for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0;
288 if (errno == EINTR || errno == EAGAIN) {
293 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port,
298 listen(sockfd, 1); /* tell system we are ready */
299 return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port,
304 * Accept a single connection
306 BSOCK *bnet_accept(BSOCK * bsock, char *who)
308 fd_set ready, sockset;
309 int newsockfd, stat, len;
311 struct sockaddr_in cli_addr; /* client's address */
316 struct request_info request;
320 * Wait for a connection from the client process.
323 FD_SET((unsigned)bsock->fd, &sockset);
327 * Wait for a connection from a client process.
330 if ((stat = select(bsock->fd + 1, &ready, NULL, NULL, NULL)) < 0) {
331 if (errno == EINTR || errno = EAGAIN) {
335 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), strerror(errno));
340 clilen = sizeof(cli_addr);
341 newsockfd = accept(bsock->fd, (struct sockaddr *)&cli_addr, &clilen);
342 } while (newsockfd < 0 && (errno == EINTR || errno = EAGAIN));
343 if (newsockfd >= 0) {
350 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
352 if (!hosts_access(&request)) {
354 Emsg2(M_SECURITY, 0, _("Connection from %s:%d refused by hosts.access\n"),
355 inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
363 * Receive notification when connection dies.
365 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
366 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
370 /* see who client is. I.e. who connected to us.
371 * return it in the input message buffer.
373 if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
374 pm_strcpy(&bsock->msg, caller);
378 bsock->msglen = strlen(bsock->msg);
381 Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who,
385 if (caller == NULL) {
386 caller = _("unknown");
388 len = strlen(caller) + strlen(who) + 3;
389 buf = (char *)malloc(len);
390 bstrncpy(buf, len, who);
391 bstrncat(buf, len, ": ");
392 bstrncat(buf, len, caller);
393 bs = init_bsock(NULL, newsockfd, _("client"), buf, bsock->port, &cli_addr);
395 return bs; /* return new BSOCK */