2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 two of the GNU 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 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 John Walker.
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
36 #include <netinet/in.h>
37 #include <sys/socket.h>
39 #include <arpa/inet.h>
41 #ifdef HAVE_ARPA_NAMESER_H
42 #include <arpa/nameser.h>
49 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
53 int allow_severity = LOG_NOTICE;
54 int deny_severity = LOG_WARNING;
57 static bool quit = false;
59 void bnet_stop_thread_server(pthread_t tid)
62 if (!pthread_equal(tid, pthread_self())) {
63 pthread_kill(tid, TIMEOUT_SIGNAL);
68 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
72 In the moment it is inpossible to bind different ports.
75 bnet_thread_server(dlist *addrs, 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;
88 dlink link; /* this MUST be the first item */
95 char allbuf[256 * 10];
96 Dmsg1(100, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf)));
98 foreach_dlist(p, addrs) {
99 fd_ptr = (s_sockfd *)malloc(sizeof(s_sockfd));
100 fd_ptr->port = p->get_port_net_order();
104 for (tlog= 60; (fd_ptr->fd=socket(p->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
108 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
110 p->build_address_str(curbuf, sizeof(curbuf)),
111 build_addresses_str(addrs, allbuf, sizeof(allbuf)));
118 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
119 sizeof(turnon)) < 0) {
121 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
125 int tmax = 30 * (60 / 5); /* wait 30 minutes max */
126 for (tlog = 0; bind(fd_ptr->fd, p->get_sockaddr(), p->get_sockaddr_len()) < 0; tlog -= 5) {
129 tlog = 2 * 60; /* Complain every 2 minutes */
130 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
131 ntohs(fd_ptr->port), be.bstrerror());
135 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
139 listen(fd_ptr->fd, 5); /* tell system we are ready */
140 sockfds.append(fd_ptr);
142 /* Start work queue thread */
143 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
146 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
149 * Wait for a connection from the client process.
152 unsigned int maxfd = 0;
155 foreach_dlist(fd_ptr, &sockfds) {
156 FD_SET((unsigned)fd_ptr->fd, &sockset);
157 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
160 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
161 berrno be; /* capture errno */
162 if (errno == EINTR) {
166 foreach_dlist(fd_ptr, &sockfds) {
169 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
173 foreach_dlist(fd_ptr, &sockfds) {
174 if (FD_ISSET(fd_ptr->fd, &sockset)) {
175 /* Got a connection, now accept it. */
177 clilen = sizeof(cli_addr);
178 newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
179 } while (newsockfd < 0 && errno == EINTR);
184 P(mutex); /* hosts_access is not thread safe */
185 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
187 if (!hosts_access(&request)) {
189 Jmsg2(NULL, M_SECURITY, 0,
190 _("Connection from %s:%d refused by hosts.access\n"),
191 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)),
192 sockaddr_get_port(&cli_addr));
200 * Receive notification when connection dies.
202 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
203 sizeof(turnon)) < 0) {
205 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
209 /* see who client is. i.e. who connected to us. */
211 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
214 bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr);
216 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
219 /* Queue client to be served */
220 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
223 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
230 /* Stop work queue thread */
231 if ((stat = workq_destroy(client_wq)) != 0) {
234 Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),
242 * Bind an address so that we may accept connections
245 BSOCK *bnet_bind(int port)
248 struct sockaddr_in serv_addr; /* our address */
255 for (tlog = 0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10) {
257 if (errno == EINTR || errno == EAGAIN) {
262 Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), be.bstrerror());
270 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
272 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
277 * Bind our local address so that the client can send to us.
279 bzero((char *)&serv_addr, sizeof(serv_addr));
280 serv_addr.sin_family = AF_INET;
281 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
282 serv_addr.sin_port = htons(port);
284 for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0;
287 if (errno == EINTR || errno == EAGAIN) {
292 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port,
297 listen(sockfd, 1); /* tell system we are ready */
298 return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port,
303 * Accept a single connection
305 BSOCK *bnet_accept(BSOCK * bsock, char *who)
307 fd_set ready, sockset;
308 int newsockfd, stat, len;
310 struct sockaddr_in cli_addr; /* client's address */
315 struct request_info request;
319 * Wait for a connection from the client process.
322 FD_SET((unsigned)bsock->fd, &sockset);
326 * Wait for a connection from a client process.
329 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"), be.bstrerror());
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) {
367 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
371 /* see who client is. I.e. who connected to us.
372 * return it in the input message buffer.
374 if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
375 pm_strcpy(&bsock->msg, caller);
379 bsock->msglen = strlen(bsock->msg);
383 Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who,
387 if (caller == NULL) {
388 caller = _("unknown");
390 len = strlen(caller) + strlen(who) + 3;
391 buf = (char *)malloc(len);
392 bstrncpy(buf, len, who);
393 bstrncat(buf, len, ": ");
394 bstrncat(buf, len, caller);
395 bs = init_bsock(NULL, newsockfd, _("client"), buf, bsock->port, &cli_addr);
397 return bs; /* return new BSOCK */