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