]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet_server.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / lib / bnet_server.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20  /*
21   * Originally written by Kern Sibbald for inclusion in apcupsd,
22   *  but heavily modified for Bacula
23   *
24   */
25
26 #include "bacula.h"
27 #include <netinet/in.h>
28 #include <sys/socket.h>
29 #include <stdlib.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #ifdef HAVE_ARPA_NAMESER_H
33 #include <arpa/nameser.h>
34 #endif
35 #ifdef HAVE_RESOLV_H
36 //#include <resolv.h>
37 #endif
38
39
40 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
41
42 #ifdef HAVE_LIBWRAP
43 #include "tcpd.h"
44 int allow_severity = LOG_NOTICE;
45 int deny_severity = LOG_WARNING;
46 #endif
47
48 static bool quit = false;
49
50 void bnet_stop_thread_server(pthread_t tid)
51 {
52    quit = true;
53    if (!pthread_equal(tid, pthread_self())) {
54       pthread_kill(tid, TIMEOUT_SIGNAL);
55    }
56 }
57
58  /*
59      Become Threaded Network Server
60      This function is able to handle multiple server ips in
61      ipv4 and ipv6 style. The Addresse are give in a comma
62      seperated string in bind_addr
63      In the moment it is inpossible to bind different ports.
64   */
65 void bnet_thread_server(dlist *addrs, int max_clients, 
66         workq_t *client_wq, void *handle_client_request(void *bsock))
67 {
68    int newsockfd, stat;
69    socklen_t clilen;
70    struct sockaddr_storage clientaddr;   /* client's address */
71    int tlog;
72    int turnon = 1;
73 #ifdef HAVE_LIBWRAP
74    struct request_info request;
75 #endif
76    IPADDR *addr;
77    struct s_sockfd {
78       dlink link;                     /* this MUST be the first item */
79       int fd;
80       int port;
81    } *fd_ptr = NULL;
82    char buf[128];
83    dlist sockfds;
84
85    char allbuf[256 * 10];
86    remove_duplicate_addresses(addrs);
87    Dmsg1(20, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf)));
88    /*
89     * Listen on each address provided.
90     */
91    foreach_dlist(addr, addrs) {
92       /* Allocate on stack from -- no need to free */
93       fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
94       fd_ptr->port = addr->get_port_net_order();
95       /*
96        * Open a TCP socket
97        */
98       for (tlog= 60; (fd_ptr->fd=socket(addr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
99          if (tlog <= 0) {
100             berrno be;
101             char curbuf[256];
102             Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
103                        be.bstrerror(),
104                        addr->build_address_str(curbuf, sizeof(curbuf)),
105                        build_addresses_str(addrs, allbuf, sizeof(allbuf)));
106          }
107          bmicrosleep(10, 0);
108       }
109       /*
110        * Reuse old sockets
111        */
112       if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
113            sizeof(turnon)) < 0) {
114          berrno be;
115          Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
116                be.bstrerror());
117       }
118
119       int tmax = 1 * (60 / 5);    /* wait 1 minute max */
120       for (tlog = 0; bind(fd_ptr->fd, addr->get_sockaddr(), addr->get_sockaddr_len()) == SOCKET_ERROR; tlog -= 5) {
121          berrno be;
122          if (tlog <= 0) {
123             tlog = 1 * 60;         /* Complain every 1 minute */
124             Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
125                   ntohs(fd_ptr->port), be.bstrerror());
126             Dmsg2(20, "Cannot bind port %d: ERR=%s: Retrying ...\n",
127                   ntohs(fd_ptr->port), be.bstrerror());
128
129          }
130          bmicrosleep(5, 0);
131          if (--tmax <= 0) {
132             Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
133                   be.bstrerror());
134             Pmsg2(000, "Aborting cannot bind port %d: ERR=%s.\n", ntohs(fd_ptr->port),
135                   be.bstrerror());
136          }
137       }
138       if (listen(fd_ptr->fd, 50) < 0) {      /* tell system we are ready */
139          berrno be;
140          Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
141                be.bstrerror());
142       } else {
143          sockfds.append(fd_ptr);
144       }
145    }
146    if (sockfds.size() == 0) {
147       Emsg0(M_ABORT, 0, _("No addr/port found to listen on.\n"));
148    }
149    /* Start work queue thread */
150    if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
151       berrno be;
152       be.set_errno(stat);
153       Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror());
154    }
155    /*
156     * Wait for a connection from the client process.
157     */
158    for (; !quit;) {
159       unsigned int maxfd = 0;
160       fd_set sockset;
161       FD_ZERO(&sockset);
162       foreach_dlist(fd_ptr, &sockfds) {
163          FD_SET((unsigned)fd_ptr->fd, &sockset);
164          maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
165       }
166       errno = 0;
167       if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
168          berrno be;                   /* capture errno */
169          if (errno == EINTR) {
170             continue;
171          }
172          Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
173          break;
174       }
175
176       foreach_dlist(fd_ptr, &sockfds) {
177          if (FD_ISSET(fd_ptr->fd, &sockset)) {
178             /* Got a connection, now accept it. */
179             do {
180                clilen = sizeof(clientaddr);
181                newsockfd = accept(fd_ptr->fd, (struct sockaddr *)&clientaddr, &clilen);
182                newsockfd = set_socket_errno(newsockfd);
183             } while (newsockfd == SOCKET_ERROR && (errno == EINTR || errno == EAGAIN));
184             if (newsockfd == SOCKET_ERROR) {
185                Dmsg2(20, "Accept=%d errno=%d\n", newsockfd, errno);
186                continue;
187             }
188 #ifdef HAVE_LIBWRAP
189             P(mutex);              /* hosts_access is not thread safe */
190             request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
191             fromhost(&request);
192             if (!hosts_access(&request)) {
193                V(mutex);
194                Jmsg2(NULL, M_SECURITY, 0,
195                      _("Connection from %s:%d refused by hosts.access\n"),
196                      sockaddr_to_ascii((struct sockaddr *)&clientaddr,
197                                        sizeof(clientaddr), buf, sizeof(buf)),
198                      sockaddr_get_port((struct sockaddr *)&clientaddr));
199                close(newsockfd);
200                continue;
201             }
202             V(mutex);
203 #endif
204
205             /*
206              * Receive notification when connection dies.
207              */
208             if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon,
209                  sizeof(turnon)) < 0) {
210                berrno be;
211                Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
212                      be.bstrerror());
213             }
214
215             /* see who client is. i.e. who connected to us. */
216             P(mutex);
217             sockaddr_to_ascii((struct sockaddr *)&clientaddr, sizeof(clientaddr), buf, sizeof(buf));
218             V(mutex);
219             BSOCK *bs;
220             bs = init_bsock(NULL, newsockfd, "client", buf, ntohs(fd_ptr->port),
221                     (struct sockaddr *)&clientaddr);
222             if (bs == NULL) {
223                Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n"));
224             }
225
226             /* Queue client to be served */
227             if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) {
228                berrno be;
229                be.set_errno(stat);
230                Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"),
231                      be.bstrerror());
232             }
233          }
234       }
235    }
236
237    /* Cleanup open files and pointers to them */
238    while ((fd_ptr = (s_sockfd *)sockfds.first())) {
239       close(fd_ptr->fd);
240       sockfds.remove(fd_ptr);     /* don't free() item it is on stack */
241    }
242
243    /* Stop work queue thread */
244    if ((stat = workq_destroy(client_wq)) != 0) {
245       berrno be;
246       be.set_errno(stat);
247       Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"),
248             be.bstrerror());
249    }
250 }