X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fbnet_server.c;h=45c0dd0448819bb72e4e5e40717f1bcbeb560177;hb=fad06408677ccf4e01bf28c01702ab337da2ec05;hp=0b9f6ebee29e8334edcf3551e89c22e9c6275e0e;hpb=9f8c89965e9f2d7e4fb55e9fd79a2aa83b85c985;p=bacula%2Fbacula diff --git a/bacula/src/lib/bnet_server.c b/bacula/src/lib/bnet_server.c index 0b9f6ebee2..45c0dd0448 100644 --- a/bacula/src/lib/bnet_server.c +++ b/bacula/src/lib/bnet_server.c @@ -25,29 +25,38 @@ */ #include "bacula.h" +#undef DEV_BSIZE #include #include #include #include +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif +#ifdef HAVE_RESOLV_H +#include +#endif + + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #ifdef HAVE_LIBWRAP #include "tcpd.h" int allow_severity = LOG_NOTICE; int deny_severity = LOG_WARNING; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #endif /* Become Threaded Network Server */ void -bnet_thread_server(int port, int max_clients, workq_t *client_wq, - void handle_client_request(void *bsock)) +bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq, + void *handle_client_request(void *bsock)) { int newsockfd, sockfd, stat; socklen_t clilen; struct sockaddr_in cli_addr; /* client's address */ struct sockaddr_in serv_addr; /* our address */ + struct in_addr bind_ip; /* address to bind to */ int tlog; - fd_set ready, sockset; int turnon = 1; char *caller; #ifdef HAVE_LIBWRAP @@ -62,22 +71,34 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, tlog = 60; Emsg1(M_ERROR, 0, _("Cannot open stream socket: %s. Retrying ...\n"), strerror(errno)); } - sleep(10); + bmicrosleep(10, 0); } /* * Reuse old sockets */ - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &turnon, sizeof(turnon)) < 0) { + 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)); + bind_ip.s_addr = htonl(INADDR_ANY); + if (bind_addr && bind_addr[0]) { +#ifdef HAVE_INET_PTON + if (inet_pton(AF_INET, bind_addr, &bind_ip) <= 0) { +#else + if (inet_aton(bind_addr, &bind_ip) <= 0) { +#endif + Emsg1(M_WARNING, 0, _("Invalid bind address: %s, using INADDR_ANY\n"), + bind_addr); + bind_ip.s_addr = htonl(INADDR_ANY); + } + } + memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_addr.s_addr = bind_ip.s_addr; serv_addr.sin_port = htons(port); int tmax = 30 * (60 / 5); /* wait 30 minutes max */ @@ -86,37 +107,45 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, tlog = 2*60; /* Complain every 2 minutes */ Emsg2(M_WARNING, 0, _("Cannot bind port %d: %s. Retrying ...\n"), port, strerror(errno)); } - sleep(5); + bmicrosleep(5, 0); if (--tmax <= 0) { Emsg2(M_ABORT, 0, _("Cannot bind port %d: %s.\n"), port, strerror(errno)); } } listen(sockfd, 5); /* tell system we are ready */ - FD_ZERO(&sockset); - FD_SET(sockfd, &sockset); - /* Start work queue thread */ if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) { Emsg1(M_ABORT, 0, _("Could not init client queue: ERR=%s\n"), strerror(stat)); } + /* + * Wait for a connection from the client process. + */ for (;;) { - /* - * Wait for a connection from a client process. - */ - ready = sockset; - if ((stat = select(sockfd+1, &ready, NULL, NULL, NULL)) < 0) { + fd_set sockset; + FD_ZERO(&sockset); + FD_SET(sockfd, &sockset); + errno = 0; + if ((stat = select(sockfd+1, &sockset, NULL, NULL, NULL)) < 0) { if (errno == EINTR || errno == EAGAIN) { - errno = 0; continue; } + /* Error, get out */ close(sockfd); Emsg1(M_FATAL, 0, _("Error in select: %s\n"), strerror(errno)); break; } - clilen = sizeof(cli_addr); - newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); + + /* Got a connection, now accept it. */ + do { + clilen = sizeof(cli_addr); + newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); + } while (newsockfd < 0 && (errno == EINTR || errno == EAGAIN)); + if (newsockfd < 0) { + continue; + } + #ifdef HAVE_LIBWRAP P(mutex); /* hosts_access is not thread safe */ @@ -124,7 +153,7 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, fromhost(&request); if (!hosts_access(&request)) { V(mutex); - Jmsg2(NULL, M_WARNING, 0, _("Connection from %s:%d refused by hosts.access"), + Jmsg2(NULL, 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); continue; @@ -135,21 +164,33 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, /* * Receive notification when connection dies. */ - if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) { + 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. */ - caller = inet_ntoa(cli_addr.sin_addr); + P(mutex); + caller = inet_ntoa(cli_addr.sin_addr); /* NOT thread safe, use mutex */ if (caller == NULL) { - caller = "unknown client"; + caller = _("unknown client"); + } + + BSOCK *bs = init_bsock(NULL, newsockfd, "client", caller, port, &cli_addr); + 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 *)init_bsock(NULL, newsockfd, "client", caller, port))) != 0) { + if ((stat = workq_add(client_wq, (void *)bs, NULL, 0)) != 0) { + V(mutex); Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"), strerror(stat)); } + V(mutex); + } + + /* Stop work queue thread */ + if ((stat = workq_destroy(client_wq)) != 0) { + Emsg1(M_FATAL, 0, _("Could not destroy client queue: ERR=%s\n"), strerror(stat)); } } @@ -171,17 +212,20 @@ bnet_bind(int port) * 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)); } - sleep(60); + bmicrosleep(60, 0); } /* * Reuse old sockets */ - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &turnon, sizeof(turnon)) < 0) { + 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)); } @@ -194,14 +238,17 @@ bnet_bind(int port) serv_addr.sin_port = htons(port); for (tlog=0; bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0; tlog -= 5 ) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } if (tlog <= 0) { tlog = 2*60; Emsg2(M_WARNING, 0, _("Cannot bind port %d: %s: retrying ...\n"), port, strerror(errno)); } - sleep(5); + bmicrosleep(5, 0); } listen(sockfd, 1); /* tell system we are ready */ - return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port); + return init_bsock(NULL, sockfd, _("Server socket"), _("client"), port, &serv_addr); } /* @@ -233,7 +280,7 @@ bnet_accept(BSOCK *bsock, char *who) */ ready = sockset; if ((stat = select(bsock->fd+1, &ready, NULL, NULL, NULL)) < 0) { - if (errno == EINTR || errno == EAGAIN) { + if (errno == EINTR || errno = EAGAIN) { errno = 0; continue; } @@ -241,9 +288,13 @@ bnet_accept(BSOCK *bsock, char *who) newsockfd = -1; break; } - clilen = sizeof(cli_addr); - newsockfd = accept(bsock->fd, (struct sockaddr *)&cli_addr, &clilen); - 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 @@ -252,7 +303,7 @@ bnet_accept(BSOCK *bsock, char *who) fromhost(&request); if (!hosts_access(&request)) { V(mutex); - Emsg2(M_WARNING, 0, _("Connection from %s:%d refused by hosts.access"), + 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; @@ -263,7 +314,7 @@ bnet_accept(BSOCK *bsock, char *who) /* * Receive notification when connection dies. */ - if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) { + 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)); } @@ -271,7 +322,7 @@ bnet_accept(BSOCK *bsock, char *who) * return it in the input message buffer. */ if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) { - strcpy(bsock->msg, caller); + pm_strcpy(&bsock->msg, caller); } else { bsock->msg[0] = 0; } @@ -290,7 +341,7 @@ bnet_accept(BSOCK *bsock, char *who) strcpy(buf, who); strcat(buf, ": "); strcat(buf, caller); - bs = init_bsock(NULL, newsockfd, "client", buf, bsock->port); + bs = init_bsock(NULL, newsockfd, "client", buf, bsock->port, &cli_addr); free(buf); return bs; /* return new BSOCK */ }