]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet_server.c
Update
[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 frame -- 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          /* Error, get out */
167          foreach_dlist(fd_ptr, &sockfds) {
168             close(fd_ptr->fd);
169          }
170          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
171          break;
172       }
173
174       foreach_dlist(fd_ptr, &sockfds) {
175          if (FD_ISSET(fd_ptr->fd, &sockset)) {
176             /* Got a connection, now accept it. */
177             do {
178                clilen = sizeof(cli_addr);
179                newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
180             } while (newsockfd < 0 && errno == EINTR);
181             if (newsockfd < 0) {
182                continue;
183             }
184 #ifdef HAVE_LIBWRAP
185             P(mutex);              /* hosts_access is not thread safe */
186             request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
187             fromhost(&request);
188             if (!hosts_access(&request)) {
189                V(mutex);
190                Jmsg2(NULL, M_SECURITY, 0,
191                      _("Connection from %s:%d refused by hosts.access\n"),
192                      sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)),
193                      sockaddr_get_port(&cli_addr));
194                close(newsockfd);
195                continue;
196             }
197             V(mutex);
198 #endif
199
200             /*
201              * Receive notification when connection dies.
202              */
203             if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
204                  sizeof(turnon)) < 0) {
205                berrno be;
206                Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
207                      be.bstrerror());
208             }
209
210             /* see who client is. i.e. who connected to us. */
211             P(mutex);
212             sockaddr_to_ascii(&cli_addr, buf, sizeof(buf));
213             V(mutex);
214             BSOCK *bs;
215             bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr);
216             if (bs == NULL) {
217                Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
218             }
219
220             /* Queue client to be served */
221             if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
222                berrno be;
223                be.set_errno(stat);
224                Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
225                      be.bstrerror());
226             }
227          }
228       }
229    }
230
231    /* Stop work queue thread */
232    if ((stat = workq_destroy(client_wq)) != 0) {
233       berrno be;
234       be.set_errno(stat);
235       Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),
236             be.bstrerror());
237    }
238 }
239
240
241 #ifdef REALLY_USED
242 /*
243  * Bind an address so that we may accept connections
244  * one at a time.
245  */
246 BSOCK *bnet_bind(int port)
247 {
248    int sockfd;
249    struct sockaddr_in serv_addr;   /* our address */
250    int tlog;
251    int turnon = 1;
252
253    /*
254     * Open a TCP socket
255     */
256    for (tlog = 0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10) {
257       berrno be;
258       if (errno == EINTR || errno == EAGAIN) {
259          continue;
260       }
261       if (tlog <= 0) {
262          tlog = 2 * 60;
263          Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), be.bstrerror());
264       }
265       bmicrosleep(60, 0);
266    }
267
268    /*
269     * Reuse old sockets
270     */
271    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
272       berrno be;
273       Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
274             be.bstrerror());
275    }
276
277    /*
278     * Bind our local address so that the client can send to us.
279     */
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);
284
285    for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0;
286         tlog -= 5) {
287       berrno be;
288       if (errno == EINTR || errno == EAGAIN) {
289          continue;
290       }
291       if (tlog <= 0) {
292          tlog = 2 * 60;
293          Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port,
294                be.bstrerror());
295       }
296       bmicrosleep(5, 0);
297    }
298    listen(sockfd, 1);              /* tell system we are ready */
299    return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port,
300                      &serv_addr);
301 }
302
303 /*
304  * Accept a single connection
305  */
306 BSOCK *bnet_accept(BSOCK * bsock, char *who)
307 {
308    fd_set ready, sockset;
309    int newsockfd, stat, len;
310    socklen_t clilen;
311    struct sockaddr_in cli_addr;    /* client's address */
312    char *caller, *buf;
313    BSOCK *bs;
314    int turnon = 1;
315 #ifdef HAVE_LIBWRAP
316    struct request_info request;
317 #endif
318
319    /*
320     * Wait for a connection from the client process.
321     */
322    FD_ZERO(&sockset);
323    FD_SET((unsigned)bsock->fd, &sockset);
324
325    for (;;) {
326       /*
327        * Wait for a connection from a client process.
328        */
329       ready = sockset;
330       if ((stat = select(bsock->fd + 1, &ready, NULL, NULL, NULL)) < 0) {
331          berrno be;
332          if (errno == EINTR || errno = EAGAIN) {
333             errno = 0;
334             continue;
335          }
336          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
337          newsockfd = -1;
338          break;
339       }
340       do {
341          clilen = sizeof(cli_addr);
342          newsockfd = accept(bsock->fd, (struct sockaddr *)&cli_addr, &clilen);
343       } while (newsockfd < 0 && (errno == EINTR || errno = EAGAIN));
344       if (newsockfd >= 0) {
345          break;
346       }
347    }
348
349 #ifdef HAVE_LIBWRAP
350    P(mutex);
351    request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
352    fromhost(&request);
353    if (!hosts_access(&request)) {
354       V(mutex);
355       Emsg2(M_SECURITY, 0, _("Connection from %s:%d refused by hosts.access\n"),
356             inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
357       close(newsockfd);
358       return NULL;
359    }
360    V(mutex);
361 #endif
362
363    /*
364     * Receive notification when connection dies.
365     */
366    if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
367       berrno be;
368       Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
369             be.bstrerror());
370    }
371
372    /* see who client is. I.e. who connected to us.
373     * return it in the input message buffer.
374     */
375    if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
376       pm_strcpy(&bsock->msg, caller);
377    } else {
378       bsock->msg[0] = 0;
379    }
380    bsock->msglen = strlen(bsock->msg);
381
382    if (newsockfd < 0) {
383       berrno be;
384       Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who,
385             be.bstrerror());
386       return NULL;
387    } else {
388       if (caller == NULL) {
389          caller = _("unknown");
390       }
391       len = strlen(caller) + strlen(who) + 3;
392       buf = (char *)malloc(len);
393       bstrncpy(buf, len, who);
394       bstrncat(buf, len, ": ");
395       bstrncat(buf, len, caller);
396       bs = init_bsock(NULL, newsockfd, _("client"), buf, bsock->port, &cli_addr);
397       free(buf);
398       return bs;                   /* return new BSOCK */
399    }
400 }
401
402 #endif