]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet_server.c
kes Fix configure so that it puts config.out in the cwd rather than
[bacula/bacula] / bacula / src / lib / bnet_server.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28  /*
29   * Originally written by Kern Sibbald for inclusion in apcupsd,
30   *  but heavily modified for Bacula
31   *
32   *   Version $Id$
33   */
34
35 #include "bacula.h"
36 #include <netinet/in.h>
37 #include <sys/socket.h>
38 #include <stdlib.h>
39 #include <arpa/inet.h>
40 #include <netdb.h>
41 #ifdef HAVE_ARPA_NAMESER_H
42 #include <arpa/nameser.h>
43 #endif
44 #ifdef HAVE_RESOLV_H
45 #include <resolv.h>
46 #endif
47
48
49 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
50
51 #ifdef HAVE_LIBWRAP
52 #include "tcpd.h"
53 int allow_severity = LOG_NOTICE;
54 int deny_severity = LOG_WARNING;
55 #endif
56
57 static bool quit = false;
58
59 void bnet_stop_thread_server(pthread_t tid)
60 {
61    quit = true;
62    if (!pthread_equal(tid, pthread_self())) {
63       pthread_kill(tid, TIMEOUT_SIGNAL);
64    }
65 }
66
67 /*
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.
73 */
74 void
75 bnet_thread_server(dlist *addrs, int max_clients, workq_t *client_wq,
76                    void *handle_client_request(void *bsock))
77 {
78    int newsockfd, stat;
79    socklen_t clilen;
80    struct sockaddr cli_addr;       /* client's address */
81    int tlog;
82    int turnon = 1;
83 #ifdef HAVE_LIBWRAP
84    struct request_info request;
85 #endif
86    IPADDR *p;
87    struct s_sockfd {
88       dlink link;                     /* this MUST be the first item */
89       int fd;
90       int port;
91    } *fd_ptr = NULL;
92    char buf[128];
93    dlist sockfds;
94
95    char allbuf[256 * 10];
96    Dmsg1(100, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf)));
97
98    foreach_dlist(p, addrs) {
99       fd_ptr = (s_sockfd *)malloc(sizeof(s_sockfd));
100       fd_ptr->port = p->get_port_net_order();
101       /*
102        * Open a TCP socket
103        */
104       for (tlog= 60; (fd_ptr->fd=socket(p->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
105          if (tlog <= 0) {
106             berrno be;
107             char curbuf[256];
108             Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
109                        be.bstrerror(),
110                        p->build_address_str(curbuf, sizeof(curbuf)),
111                        build_addresses_str(addrs, allbuf, sizeof(allbuf)));
112          }
113          bmicrosleep(10, 0);
114       }
115       /*
116        * Reuse old sockets
117        */
118       if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
119            sizeof(turnon)) < 0) {
120          berrno be;
121          Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
122                be.bstrerror());
123       }
124
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) {
127          berrno be;
128          if (tlog <= 0) {
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());
132          }
133          bmicrosleep(5, 0);
134          if (--tmax <= 0) {
135             Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
136                   be.bstrerror());
137          }
138       }
139       listen(fd_ptr->fd, 5);       /* tell system we are ready */
140       sockfds.append(fd_ptr);
141    }
142    /* Start work queue thread */
143    if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
144       berrno be;
145       be.set_errno(stat);
146       Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
147    }
148    /*
149     * Wait for a connection from the client process.
150     */
151    for (; !quit;) {
152       unsigned int maxfd = 0;
153       fd_set sockset;
154       FD_ZERO(&sockset);
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;
158       }
159       errno = 0;
160       if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
161          berrno be;                   /* capture errno */
162          if (errno == EINTR) {
163             continue;
164          }
165          /* Error, get out */
166          foreach_dlist(fd_ptr, &sockfds) {
167             close(fd_ptr->fd);
168          }
169          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
170          break;
171       }
172
173       foreach_dlist(fd_ptr, &sockfds) {
174          if (FD_ISSET(fd_ptr->fd, &sockset)) {
175             /* Got a connection, now accept it. */
176             do {
177                clilen = sizeof(cli_addr);
178                newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
179             } while (newsockfd < 0 && errno == EINTR);
180             if (newsockfd < 0) {
181                continue;
182             }
183 #ifdef HAVE_LIBWRAP
184             P(mutex);              /* hosts_access is not thread safe */
185             request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
186             fromhost(&request);
187             if (!hosts_access(&request)) {
188                V(mutex);
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));
193                close(newsockfd);
194                continue;
195             }
196             V(mutex);
197 #endif
198
199             /*
200              * Receive notification when connection dies.
201              */
202             if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
203                  sizeof(turnon)) < 0) {
204                berrno be;
205                Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
206                      be.bstrerror());
207             }
208
209             /* see who client is. i.e. who connected to us. */
210             P(mutex);
211             sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
212             V(mutex);
213             BSOCK *bs;
214             bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr);
215             if (bs == NULL) {
216                Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
217             }
218
219             /* Queue client to be served */
220             if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
221                berrno be;
222                be.set_errno(stat);
223                Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
224                      be.bstrerror());
225             }
226          }
227       }
228    }
229
230    /* Stop work queue thread */
231    if ((stat = workq_destroy(client_wq)) != 0) {
232       berrno be;
233       be.set_errno(stat);
234       Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),
235             be.bstrerror());
236    }
237 }
238
239
240 #ifdef REALLY_USED
241 /*
242  * Bind an address so that we may accept connections
243  * one at a time.
244  */
245 BSOCK *bnet_bind(int port)
246 {
247    int sockfd;
248    struct sockaddr_in serv_addr;   /* our address */
249    int tlog;
250    int turnon = 1;
251
252    /*
253     * Open a TCP socket
254     */
255    for (tlog = 0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10) {
256       berrno be;
257       if (errno == EINTR || errno == EAGAIN) {
258          continue;
259       }
260       if (tlog <= 0) {
261          tlog = 2 * 60;
262          Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), be.bstrerror());
263       }
264       bmicrosleep(60, 0);
265    }
266
267    /*
268     * Reuse old sockets
269     */
270    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
271       berrno be;
272       Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
273             be.bstrerror());
274    }
275
276    /*
277     * Bind our local address so that the client can send to us.
278     */
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);
283
284    for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0;
285         tlog -= 5) {
286       berrno be;
287       if (errno == EINTR || errno == EAGAIN) {
288          continue;
289       }
290       if (tlog <= 0) {
291          tlog = 2 * 60;
292          Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port,
293                be.bstrerror());
294       }
295       bmicrosleep(5, 0);
296    }
297    listen(sockfd, 1);              /* tell system we are ready */
298    return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port,
299                      &serv_addr);
300 }
301
302 /*
303  * Accept a single connection
304  */
305 BSOCK *bnet_accept(BSOCK * bsock, char *who)
306 {
307    fd_set ready, sockset;
308    int newsockfd, stat, len;
309    socklen_t clilen;
310    struct sockaddr_in cli_addr;    /* client's address */
311    char *caller, *buf;
312    BSOCK *bs;
313    int turnon = 1;
314 #ifdef HAVE_LIBWRAP
315    struct request_info request;
316 #endif
317
318    /*
319     * Wait for a connection from the client process.
320     */
321    FD_ZERO(&sockset);
322    FD_SET((unsigned)bsock->fd, &sockset);
323
324    for (;;) {
325       /*
326        * Wait for a connection from a client process.
327        */
328       ready = sockset;
329       if ((stat = select(bsock->fd + 1, &ready, NULL, NULL, NULL)) < 0) {
330          berrno be;
331          if (errno == EINTR || errno = EAGAIN) {
332             errno = 0;
333             continue;
334          }
335          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
336          newsockfd = -1;
337          break;
338       }
339       do {
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) {
344          break;
345       }
346    }
347
348 #ifdef HAVE_LIBWRAP
349    P(mutex);
350    request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
351    fromhost(&request);
352    if (!hosts_access(&request)) {
353       V(mutex);
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));
356       close(newsockfd);
357       return NULL;
358    }
359    V(mutex);
360 #endif
361
362    /*
363     * Receive notification when connection dies.
364     */
365    if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
366       berrno be;
367       Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
368             be.bstrerror());
369    }
370
371    /* see who client is. I.e. who connected to us.
372     * return it in the input message buffer.
373     */
374    if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
375       pm_strcpy(&bsock->msg, caller);
376    } else {
377       bsock->msg[0] = 0;
378    }
379    bsock->msglen = strlen(bsock->msg);
380
381    if (newsockfd < 0) {
382       berrno be;
383       Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who,
384             be.bstrerror());
385       return NULL;
386    } else {
387       if (caller == NULL) {
388          caller = _("unknown");
389       }
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);
396       free(buf);
397       return bs;                   /* return new BSOCK */
398    }
399 }
400
401 #endif