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 /* Allocate on stack from -- no need to free */
100 fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
101 fd_ptr->port = p->get_port_net_order();
105 for (tlog= 60; (fd_ptr->fd=socket(p->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
109 Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
111 p->build_address_str(curbuf, sizeof(curbuf)),
112 build_addresses_str(addrs, allbuf, sizeof(allbuf)));
119 if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
120 sizeof(turnon)) < 0) {
122 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
126 int tmax = 30 * (60 / 5); /* wait 30 minutes max */
127 for (tlog = 0; bind(fd_ptr->fd, p->get_sockaddr(), p->get_sockaddr_len()) < 0; tlog -= 5) {
130 tlog = 2 * 60; /* Complain every 2 minutes */
131 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
132 ntohs(fd_ptr->port), be.bstrerror());
136 Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
140 listen(fd_ptr->fd, 5); /* tell system we are ready */
141 sockfds.append(fd_ptr);
143 /* Start work queue thread */
144 if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
147 Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
150 * Wait for a connection from the client process.
153 unsigned int maxfd = 0;
156 foreach_dlist(fd_ptr, &sockfds) {
157 FD_SET((unsigned)fd_ptr->fd, &sockset);
158 maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
161 if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
162 berrno be; /* capture errno */
163 if (errno == EINTR) {
166 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
170 foreach_dlist(fd_ptr, &sockfds) {
171 if (FD_ISSET(fd_ptr->fd, &sockset)) {
172 /* Got a connection, now accept it. */
174 clilen = sizeof(cli_addr);
175 newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
176 } while (newsockfd < 0 && errno == EINTR);
181 P(mutex); /* hosts_access is not thread safe */
182 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
184 if (!hosts_access(&request)) {
186 Jmsg2(NULL, M_SECURITY, 0,
187 _("Connection from %s:%d refused by hosts.access\n"),
188 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)),
189 sockaddr_get_port(&cli_addr));
197 * Receive notification when connection dies.
199 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
200 sizeof(turnon)) < 0) {
202 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
206 /* see who client is. i.e. who connected to us. */
208 sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
211 bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr);
213 Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
216 /* Queue client to be served */
217 if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
220 Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
227 /* Cleanup open files and pointers to them */
228 while ((fd_ptr = (s_sockfd *)sockfds.first())) {
230 sockfds.remove(fd_ptr); /* don't free() item it is on stack */
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) {
260 if (errno == EINTR || errno == EAGAIN) {
265 Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), be.bstrerror());
273 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
275 Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
280 * Bind our local address so that the client can send to us.
282 bzero((char *)&serv_addr, sizeof(serv_addr));
283 serv_addr.sin_family = AF_INET;
284 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
285 serv_addr.sin_port = htons(port);
287 for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0;
290 if (errno == EINTR || errno == EAGAIN) {
295 Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port,
300 listen(sockfd, 1); /* tell system we are ready */
301 return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port,
306 * Accept a single connection
308 BSOCK *bnet_accept(BSOCK * bsock, char *who)
310 fd_set ready, sockset;
311 int newsockfd, stat, len;
313 struct sockaddr_in cli_addr; /* client's address */
318 struct request_info request;
322 * Wait for a connection from the client process.
325 FD_SET((unsigned)bsock->fd, &sockset);
329 * Wait for a connection from a client process.
332 if ((stat = select(bsock->fd + 1, &ready, NULL, NULL, NULL)) < 0) {
334 if (errno == EINTR || errno = EAGAIN) {
338 Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
343 clilen = sizeof(cli_addr);
344 newsockfd = accept(bsock->fd, (struct sockaddr *)&cli_addr, &clilen);
345 } while (newsockfd < 0 && (errno == EINTR || errno = EAGAIN));
346 if (newsockfd >= 0) {
353 request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
355 if (!hosts_access(&request)) {
357 Emsg2(M_SECURITY, 0, _("Connection from %s:%d refused by hosts.access\n"),
358 inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
366 * Receive notification when connection dies.
368 if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
370 Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
374 /* see who client is. I.e. who connected to us.
375 * return it in the input message buffer.
377 if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
378 pm_strcpy(&bsock->msg, caller);
382 bsock->msglen = strlen(bsock->msg);
386 Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who,
390 if (caller == NULL) {
391 caller = _("unknown");
393 len = strlen(caller) + strlen(who) + 3;
394 buf = (char *)malloc(len);
395 bstrncpy(buf, len, who);
396 bstrncat(buf, len, ": ");
397 bstrncat(buf, len, caller);
398 bs = init_bsock(NULL, newsockfd, _("client"), buf, bsock->port, &cli_addr);
400 return bs; /* return new BSOCK */