]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet_server.c
d6bac6de0523b447fa8a1a045c41efa2fa793b63
[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       /* 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();
102       /*
103        * Open a TCP socket
104        */
105       for (tlog= 60; (fd_ptr->fd=socket(p->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
106          if (tlog <= 0) {
107             berrno be;
108             char curbuf[256];
109             Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
110                        be.bstrerror(),
111                        p->build_address_str(curbuf, sizeof(curbuf)),
112                        build_addresses_str(addrs, allbuf, sizeof(allbuf)));
113          }
114          bmicrosleep(10, 0);
115       }
116       /*
117        * Reuse old sockets
118        */
119       if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
120            sizeof(turnon)) < 0) {
121          berrno be;
122          Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
123                be.bstrerror());
124       }
125
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) {
128          berrno be;
129          if (tlog <= 0) {
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());
133          }
134          bmicrosleep(5, 0);
135          if (--tmax <= 0) {
136             Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
137                   be.bstrerror());
138          }
139       }
140       listen(fd_ptr->fd, 5);       /* tell system we are ready */
141       sockfds.append(fd_ptr);
142    }
143    /* Start work queue thread */
144    if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
145       berrno be;
146       be.set_errno(stat);
147       Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
148    }
149    /*
150     * Wait for a connection from the client process.
151     */
152    for (; !quit;) {
153       unsigned int maxfd = 0;
154       fd_set sockset;
155       FD_ZERO(&sockset);
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;
159       }
160       errno = 0;
161       if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
162          berrno be;                   /* capture errno */
163          if (errno == EINTR) {
164             continue;
165          }
166          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
167          break;
168       }
169
170       foreach_dlist(fd_ptr, &sockfds) {
171          if (FD_ISSET(fd_ptr->fd, &sockset)) {
172             /* Got a connection, now accept it. */
173             do {
174                clilen = sizeof(cli_addr);
175                newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
176             } while (newsockfd < 0 && errno == EINTR);
177             if (newsockfd < 0) {
178                continue;
179             }
180 #ifdef HAVE_LIBWRAP
181             P(mutex);              /* hosts_access is not thread safe */
182             request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
183             fromhost(&request);
184             if (!hosts_access(&request)) {
185                V(mutex);
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));
190                close(newsockfd);
191                continue;
192             }
193             V(mutex);
194 #endif
195
196             /*
197              * Receive notification when connection dies.
198              */
199             if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
200                  sizeof(turnon)) < 0) {
201                berrno be;
202                Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
203                      be.bstrerror());
204             }
205
206             /* see who client is. i.e. who connected to us. */
207             P(mutex);
208             sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
209             V(mutex);
210             BSOCK *bs;
211             bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr);
212             if (bs == NULL) {
213                Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
214             }
215
216             /* Queue client to be served */
217             if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
218                berrno be;
219                be.set_errno(stat);
220                Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
221                      be.bstrerror());
222             }
223          }
224       }
225    }
226
227    /* Cleanup open files and pointers to them */
228    while ((fd_ptr = (s_sockfd *)sockfds.first())) {
229       close(fd_ptr->fd);
230       sockfds.remove(fd_ptr);     /* don't free() item it is on stack */
231    }
232
233    /* Stop work queue thread */
234    if ((stat = workq_destroy(client_wq)) != 0) {
235       berrno be;
236       be.set_errno(stat);
237       Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),
238             be.bstrerror());
239    }
240 }
241
242
243 #ifdef REALLY_USED
244 /*
245  * Bind an address so that we may accept connections
246  * one at a time.
247  */
248 BSOCK *bnet_bind(int port)
249 {
250    int sockfd;
251    struct sockaddr_in serv_addr;   /* our address */
252    int tlog;
253    int turnon = 1;
254
255    /*
256     * Open a TCP socket
257     */
258    for (tlog = 0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10) {
259       berrno be;
260       if (errno == EINTR || errno == EAGAIN) {
261          continue;
262       }
263       if (tlog <= 0) {
264          tlog = 2 * 60;
265          Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), be.bstrerror());
266       }
267       bmicrosleep(60, 0);
268    }
269
270    /*
271     * Reuse old sockets
272     */
273    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
274       berrno be;
275       Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
276             be.bstrerror());
277    }
278
279    /*
280     * Bind our local address so that the client can send to us.
281     */
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);
286
287    for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0;
288         tlog -= 5) {
289       berrno be;
290       if (errno == EINTR || errno == EAGAIN) {
291          continue;
292       }
293       if (tlog <= 0) {
294          tlog = 2 * 60;
295          Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port,
296                be.bstrerror());
297       }
298       bmicrosleep(5, 0);
299    }
300    listen(sockfd, 1);              /* tell system we are ready */
301    return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port,
302                      &serv_addr);
303 }
304
305 /*
306  * Accept a single connection
307  */
308 BSOCK *bnet_accept(BSOCK * bsock, char *who)
309 {
310    fd_set ready, sockset;
311    int newsockfd, stat, len;
312    socklen_t clilen;
313    struct sockaddr_in cli_addr;    /* client's address */
314    char *caller, *buf;
315    BSOCK *bs;
316    int turnon = 1;
317 #ifdef HAVE_LIBWRAP
318    struct request_info request;
319 #endif
320
321    /*
322     * Wait for a connection from the client process.
323     */
324    FD_ZERO(&sockset);
325    FD_SET((unsigned)bsock->fd, &sockset);
326
327    for (;;) {
328       /*
329        * Wait for a connection from a client process.
330        */
331       ready = sockset;
332       if ((stat = select(bsock->fd + 1, &ready, NULL, NULL, NULL)) < 0) {
333          berrno be;
334          if (errno == EINTR || errno = EAGAIN) {
335             errno = 0;
336             continue;
337          }
338          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
339          newsockfd = -1;
340          break;
341       }
342       do {
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) {
347          break;
348       }
349    }
350
351 #ifdef HAVE_LIBWRAP
352    P(mutex);
353    request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
354    fromhost(&request);
355    if (!hosts_access(&request)) {
356       V(mutex);
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));
359       close(newsockfd);
360       return NULL;
361    }
362    V(mutex);
363 #endif
364
365    /*
366     * Receive notification when connection dies.
367     */
368    if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
369       berrno be;
370       Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
371             be.bstrerror());
372    }
373
374    /* see who client is. I.e. who connected to us.
375     * return it in the input message buffer.
376     */
377    if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
378       pm_strcpy(&bsock->msg, caller);
379    } else {
380       bsock->msg[0] = 0;
381    }
382    bsock->msglen = strlen(bsock->msg);
383
384    if (newsockfd < 0) {
385       berrno be;
386       Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who,
387             be.bstrerror());
388       return NULL;
389    } else {
390       if (caller == NULL) {
391          caller = _("unknown");
392       }
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);
399       free(buf);
400       return bs;                   /* return new BSOCK */
401    }
402 }
403
404 #endif