X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fbnet_server.c;h=ef153327b48fea42847a904a931f7e9cacde80ce;hb=d8628580f5e43ec26d4816ac521cf2b1675a129b;hp=8d8cfbb15e3e04768a04403675f183738f60a28a;hpb=92d78b2e7c68f4a7e83574c7c60e329940e777cf;p=bacula%2Fbacula diff --git a/bacula/src/lib/bnet_server.c b/bacula/src/lib/bnet_server.c index 8d8cfbb15e..ef153327b4 100644 --- a/bacula/src/lib/bnet_server.c +++ b/bacula/src/lib/bnet_server.c @@ -1,23 +1,31 @@ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Bacula® - The Network Backup Solution - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - */ - /* + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ + /* * Originally written by Kern Sibbald for inclusion in apcupsd, * but heavily modified for Bacula * @@ -25,7 +33,6 @@ */ #include "bacula.h" -#undef DEV_BSIZE #include #include #include @@ -35,7 +42,7 @@ #include #endif #ifdef HAVE_RESOLV_H -#include +//#include #endif @@ -57,8 +64,8 @@ void bnet_stop_thread_server(pthread_t tid) } } -/* - Become Threaded Network Server +/* + Become Threaded Network Server This function is able to handle multiple server ips in ipv4 and ipv6 style. The Addresse are give in a comma seperated string in bind_addr @@ -66,7 +73,7 @@ void bnet_stop_thread_server(pthread_t tid) */ void bnet_thread_server(dlist *addrs, int max_clients, workq_t *client_wq, - void *handle_client_request(void *bsock)) + void *handle_client_request(void *bsock)) { int newsockfd, stat; socklen_t clilen; @@ -78,7 +85,7 @@ bnet_thread_server(dlist *addrs, int max_clients, workq_t *client_wq, #endif IPADDR *p; struct s_sockfd { - dlink link; /* this MUST be the first item */ + dlink link; /* this MUST be the first item */ int fd; int port; } *fd_ptr = NULL; @@ -89,58 +96,57 @@ bnet_thread_server(dlist *addrs, int max_clients, workq_t *client_wq, Dmsg1(100, "Addresses %s\n", build_addresses_str(addrs, allbuf, sizeof(allbuf))); foreach_dlist(p, addrs) { - /* Allocate on stack frame -- no need to free */ + /* Allocate on stack from -- no need to free */ fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd)); fd_ptr->port = p->get_port_net_order(); /* - * Open a TCP socket + * Open a TCP socket */ for (tlog= 60; (fd_ptr->fd=socket(p->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) { - if (tlog <= 0) { - berrno be; - char curbuf[256]; + if (tlog <= 0) { + berrno be; + char curbuf[256]; Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"), - be.strerror(), - p->build_address_str(curbuf, sizeof(curbuf)), - build_addresses_str(addrs, allbuf, sizeof(allbuf))); - } - bmicrosleep(10, 0); + be.bstrerror(), + p->build_address_str(curbuf, sizeof(curbuf)), + build_addresses_str(addrs, allbuf, sizeof(allbuf))); + } + bmicrosleep(10, 0); } /* - * Reuse old sockets + * Reuse old sockets */ if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, - sizeof(turnon)) < 0) { - berrno be; + sizeof(turnon)) < 0) { + berrno be; Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"), - be.strerror()); + be.bstrerror()); } int tmax = 30 * (60 / 5); /* wait 30 minutes max */ - /* FIXME i can go to a endless loop i get a invalid address */ for (tlog = 0; bind(fd_ptr->fd, p->get_sockaddr(), p->get_sockaddr_len()) < 0; tlog -= 5) { - berrno be; - if (tlog <= 0) { - tlog = 2 * 60; /* Complain every 2 minutes */ - Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s. Retrying ...\n"), - ntohs(fd_ptr->port), be.strerror()); - } - bmicrosleep(5, 0); - if (--tmax <= 0) { + berrno be; + if (tlog <= 0) { + tlog = 2 * 60; /* Complain every 2 minutes */ + Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"), + ntohs(fd_ptr->port), be.bstrerror()); + } + bmicrosleep(5, 0); + if (--tmax <= 0) { Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port), - be.strerror()); - } + be.bstrerror()); + } } - listen(fd_ptr->fd, 5); /* tell system we are ready */ + listen(fd_ptr->fd, 50); /* tell system we are ready */ sockfds.append(fd_ptr); } /* Start work queue thread */ if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) { berrno be; be.set_errno(stat); - Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.strerror()); + Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), be.bstrerror()); } - /* + /* * Wait for a connection from the client process. */ for (; !quit;) { @@ -148,260 +154,87 @@ bnet_thread_server(dlist *addrs, int max_clients, workq_t *client_wq, fd_set sockset; FD_ZERO(&sockset); foreach_dlist(fd_ptr, &sockfds) { - FD_SET((unsigned)fd_ptr->fd, &sockset); - maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd; + FD_SET((unsigned)fd_ptr->fd, &sockset); + maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd; } errno = 0; if ((stat = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) { - berrno be; /* capture errno */ - if (errno == EINTR || errno == EAGAIN) { - continue; - } - /* Error, get out */ - foreach_dlist(fd_ptr, &sockfds) { - close(fd_ptr->fd); - free((void *)fd_ptr); - } - Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.strerror()); - break; + berrno be; /* capture errno */ + if (errno == EINTR) { + continue; + } + Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror()); + break; } foreach_dlist(fd_ptr, &sockfds) { - if (FD_ISSET(fd_ptr->fd, &sockset)) { - /* Got a connection, now accept it. */ - do { - clilen = sizeof(cli_addr); - newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen); - } while (newsockfd < 0 && (errno == EINTR || errno == EAGAIN)); - if (newsockfd < 0) { - continue; - } + if (FD_ISSET(fd_ptr->fd, &sockset)) { + /* Got a connection, now accept it. */ + do { + clilen = sizeof(cli_addr); + newsockfd = accept(fd_ptr->fd, &cli_addr, &clilen); + } while (newsockfd < 0 && errno == EINTR); + if (newsockfd < 0) { + continue; + } #ifdef HAVE_LIBWRAP - P(mutex); /* hosts_access is not thread safe */ - request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0); - fromhost(&request); - if (!hosts_access(&request)) { - V(mutex); -#ifndef HAVE_INET_NTOP - Jmsg2(NULL, M_SECURITY, 0, - _("Connection from %s:%d refused by hosts.access\n"), - inet_ntoa(((sockaddr_in *)&cli_addr)->sin_addr), - ntohs(((sockaddr_in *)&cli_addr)->sin_port)); -#else - Jmsg2(NULL, M_SECURITY, 0, + P(mutex); /* hosts_access is not thread safe */ + request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0); + fromhost(&request); + if (!hosts_access(&request)) { + V(mutex); + Jmsg2(NULL, M_SECURITY, 0, _("Connection from %s:%d refused by hosts.access\n"), - inet_ntop(clilen == sizeof(sockaddr_in) ? AF_INET : AF_INET6, - &clilen, buf, clilen), - ntohs(clilen == sizeof(sockaddr_in) ? - ((sockaddr_in *)&cli_addr)->sin_port : - ((sockaddr_in6 *)&cli_addr)->sin6_port)); -#endif - close(newsockfd); - continue; - } - V(mutex); + sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)), + sockaddr_get_port(&cli_addr)); + close(newsockfd); + continue; + } + V(mutex); #endif - /* - * Receive notification when connection dies. - */ - if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, - sizeof(turnon)) < 0) { - berrno be; + /* + * Receive notification when connection dies. + */ + if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, + sizeof(turnon)) < 0) { + berrno be; Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), - be.strerror()); - } - - /* see who client is. i.e. who connected to us. */ - P(mutex); -#ifdef HAVE_INET_NTOP - inet_ntop(clilen == sizeof(sockaddr_in) ? AF_INET : AF_INET6, &clilen, - buf, sizeof(buf)); -#else - bstrncpy(buf, inet_ntoa(((sockaddr_in *)&cli_addr)->sin_addr), sizeof(buf)); /* NOT thread safe, use mutex */ -#endif - V(mutex); - BSOCK *bs; + be.bstrerror()); + } + + /* see who client is. i.e. who connected to us. */ + P(mutex); + sockaddr_to_ascii(&cli_addr, buf, sizeof(buf)); + V(mutex); + BSOCK *bs; bs = init_bsock(NULL, newsockfd, "client", buf, fd_ptr->port, &cli_addr); - if (bs == NULL) { + if (bs == NULL) { Jmsg0(NULL, M_ABORT, 0, _("Could not create client BSOCK.\n")); - } + } - /* Queue client to be served */ - if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) { - berrno be; - be.set_errno(stat); + /* Queue client to be served */ + if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) { + berrno be; + be.set_errno(stat); Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"), - be.strerror()); - } - } + be.bstrerror()); + } + } } } + /* Cleanup open files and pointers to them */ + while ((fd_ptr = (s_sockfd *)sockfds.first())) { + close(fd_ptr->fd); + sockfds.remove(fd_ptr); /* don't free() item it is on stack */ + } + /* Stop work queue thread */ if ((stat = workq_destroy(client_wq)) != 0) { berrno be; be.set_errno(stat); Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"), - be.strerror()); - } -} - - -#ifdef REALLY_USED -/* - * Bind an address so that we may accept connections - * one at a time. - */ -BSOCK *bnet_bind(int port) -{ - int sockfd; - struct sockaddr_in serv_addr; /* our address */ - int tlog; - int turnon = 1; - - /* - * Open a TCP socket - */ - for (tlog = 0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - if (tlog <= 0) { - tlog = 2 * 60; - Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s\n"), strerror(errno)); - } - bmicrosleep(60, 0); - } - - /* - * Reuse old sockets - */ - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) { - Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"), - strerror(errno)); - } - - /* - * Bind our local address so that the client can send to us. - */ - bzero((char *)&serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - serv_addr.sin_port = htons(port); - - for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0; - tlog -= 5) { - berrno be; - if (errno == EINTR || errno == EAGAIN) { - continue; - } - if (tlog <= 0) { - tlog = 2 * 60; - Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: retrying ...\n"), port, - be.strerror()); - } - bmicrosleep(5, 0); + be.bstrerror()); } - listen(sockfd, 1); /* tell system we are ready */ - return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port, - &serv_addr); } - -/* - * Accept a single connection - */ -BSOCK *bnet_accept(BSOCK * bsock, char *who) -{ - fd_set ready, sockset; - int newsockfd, stat, len; - socklen_t clilen; - struct sockaddr_in cli_addr; /* client's address */ - char *caller, *buf; - BSOCK *bs; - int turnon = 1; -#ifdef HAVE_LIBWRAP - struct request_info request; -#endif - - /* - * Wait for a connection from the client process. - */ - FD_ZERO(&sockset); - FD_SET((unsigned)bsock->fd, &sockset); - - for (;;) { - /* - * Wait for a connection from a client process. - */ - ready = sockset; - if ((stat = select(bsock->fd + 1, &ready, NULL, NULL, NULL)) < 0) { - if (errno == EINTR || errno = EAGAIN) { - errno = 0; - continue; - } - Emsg1(M_FATAL, 0, _("Error in select: %s\n"), strerror(errno)); - newsockfd = -1; - break; - } - do { - clilen = sizeof(cli_addr); - newsockfd = accept(bsock->fd, (struct sockaddr *)&cli_addr, &clilen); - } while (newsockfd < 0 && (errno == EINTR || errno = EAGAIN)); - if (newsockfd >= 0) { - break; - } - } - -#ifdef HAVE_LIBWRAP - P(mutex); - request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0); - fromhost(&request); - if (!hosts_access(&request)) { - V(mutex); - Emsg2(M_SECURITY, 0, _("Connection from %s:%d refused by hosts.access\n"), - inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); - close(newsockfd); - return NULL; - } - V(mutex); -#endif - - /* - * Receive notification when connection dies. - */ - if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) { - Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), - strerror(errno)); - } - - /* see who client is. I.e. who connected to us. - * return it in the input message buffer. - */ - if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) { - pm_strcpy(&bsock->msg, caller); - } else { - bsock->msg[0] = 0; - } - bsock->msglen = strlen(bsock->msg); - - if (newsockfd < 0) { - Emsg2(M_FATAL, 0, _("Socket accept error for %s. ERR=%s\n"), who, - strerror(errno)); - return NULL; - } else { - if (caller == NULL) { - caller = "unknown"; - } - len = strlen(caller) + strlen(who) + 3; - buf = (char *)malloc(len); - bstrncpy(buf, len, who); - bstrncat(buf, len, ": "); - bstrncat(buf, len, caller); - bs = init_bsock(NULL, newsockfd, "client", buf, bsock->port, &cli_addr); - free(buf); - return bs; /* return new BSOCK */ - } -} - -#endif