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