2 * Network Utility Routines
6 * Adapted and enhanced for Bacula, originally written
7 * for inclusion in the Apcupsd package
12 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 2.1 of the License, or (at your option) any later version.
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, write to the Free
26 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
35 extern time_t watchdog_time;
38 #define INADDR_NONE -1
41 #ifndef ENODATA /* not defined on BSD systems */
47 * Read a nbytes from the network.
48 * It is possible that the total bytes require in several
52 static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
60 nread = read(bsock->fd, ptr, nleft);
61 if (bsock->timed_out || bsock->terminated) {
64 } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
66 return nread; /* error, or EOF */
71 return nbytes - nleft; /* return >= 0 */
75 * Write nbytes to the network.
76 * It may require several writes.
79 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
81 int32_t nleft, nwritten;
84 nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
85 if (nwritten != nbytes) {
86 Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno));
87 Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
96 nwritten = write(bsock->fd, ptr, nleft);
97 if (bsock->timed_out || bsock->terminated) {
100 } while (nwritten == -1 && errno == EINTR);
102 * If connection is non-blocking, we will get eagain, so
103 * sleep long enough to keep from consuming all the CPU
106 if (nwritten == -1 && errno == EAGAIN) {
107 bmicrosleep(0, 50); /* sleep 50 ms */
111 return nwritten; /* error */
120 * Receive a message from the other end. Each message consists of
121 * two packets. The first is a header that contains the size
122 * of the data that follows in the second packet.
123 * Returns number of bytes read (may return zero)
124 * Returns -1 on signal (BNET_SIGNAL)
125 * Returns -2 on hard end of file (BNET_HARDEOF)
126 * Returns -3 on error (BNET_ERROR)
128 * Unfortunately, it is a bit complicated because we have these
131 * 2. Signal including end of data stream
132 * 3. Hard end of file
134 * Using is_bnet_stop() and is_bnet_error() you can figure this all out.
136 int32_t bnet_recv(BSOCK *bsock)
142 if (bsock->errors || bsock->terminated) {
146 bsock->read_seqno++; /* bump sequence number */
147 bsock->timer_start = watchdog_time; /* set start wait time */
148 bsock->timed_out = 0;
149 /* get data size -- in int32_t */
150 if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
151 bsock->timer_start = 0; /* clear timer */
152 /* probably pipe broken because client died */
154 bsock->b_errno = ENODATA;
156 bsock->b_errno = errno;
159 return BNET_HARDEOF; /* assume hard EOF received */
161 bsock->timer_start = 0; /* clear timer */
162 if (nbytes != sizeof(int32_t)) {
164 bsock->b_errno = EIO;
165 Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
170 pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
172 if (pktsiz == 0) { /* No data transferred */
173 bsock->timer_start = 0; /* clear timer */
176 return 0; /* zero bytes read */
179 /* If signal or packet size too big */
180 if (pktsiz < 0 || pktsiz > 1000000) {
181 if (pktsiz > 0) { /* if packet too big */
182 pktsiz = BNET_TERMINATE; /* hang up */
184 if (pktsiz == BNET_TERMINATE) {
185 bsock->terminated = 1;
187 bsock->timer_start = 0; /* clear timer */
188 bsock->b_errno = ENODATA;
189 bsock->msglen = pktsiz; /* signal code */
190 return BNET_SIGNAL; /* signal */
193 /* Make sure the buffer is big enough + one byte for EOS */
194 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
195 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
198 bsock->timer_start = watchdog_time; /* set start wait time */
199 bsock->timed_out = 0;
200 /* now read the actual data */
201 if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <= 0) {
202 bsock->timer_start = 0; /* clear timer */
204 bsock->b_errno = ENODATA;
206 bsock->b_errno = errno;
209 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
210 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
213 bsock->timer_start = 0; /* clear timer */
215 bsock->msglen = nbytes;
216 if (nbytes != pktsiz) {
217 bsock->b_errno = EIO;
219 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
220 bsock->who, bsock->host, bsock->port);
223 /* always add a zero by to properly terminate any
224 * string that was send to us. Note, we ensured above that the
225 * buffer is at least one byte longer than the message length.
227 bsock->msg[nbytes] = 0; /* terminate in case it is a string */
228 sm_check(__FILE__, __LINE__, False);
229 return nbytes; /* return actual length of message */
234 * Return 1 if there are errors on this bsock or it is closed,
235 * i.e. stop communicating on this line.
237 int is_bnet_stop(BSOCK *bsock)
239 return bsock->errors || bsock->terminated;
243 * Return number of errors on socket
245 int is_bnet_error(BSOCK *bsock)
247 return bsock->errors;
251 * Call here after error during closing to suppress error
252 * messages which are due to the other end shutting down too.
255 bnet_suppress_error_messages(BSOCK *bsock, int flag)
257 bsock->suppress_error_msgs = flag;
262 * Transmit spooled data now
264 int bnet_despool(BSOCK *bsock)
269 rewind(bsock->spool_fd);
270 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
271 bsock->msglen = ntohl(pktsiz);
272 if (bsock->msglen > 0) {
273 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
274 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
276 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
277 if (nbytes != (size_t)bsock->msglen) {
278 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
279 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
285 if (ferror(bsock->spool_fd)) {
286 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
294 * Send a message over the network. The send consists of
295 * two network packets. The first is sends a 32 bit integer containing
296 * the length of the data packet which follows.
298 * Returns: 0 on failure
302 bnet_send(BSOCK *bsock)
307 if (bsock->errors || bsock->terminated) {
310 pktsiz = htonl((int32_t)bsock->msglen);
311 /* send int32_t containing size of data packet */
312 bsock->timer_start = watchdog_time; /* start timer */
313 bsock->timed_out = 0;
314 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
315 bsock->timer_start = 0; /* clear timer */
316 if (rc != sizeof(int32_t)) {
317 if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
318 bsock->terminated = 1;
319 return 0; /* ignore any errors */
323 bsock->b_errno = EIO;
325 bsock->b_errno = errno;
328 if (!bsock->suppress_error_msgs) {
329 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
330 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
333 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
334 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
339 bsock->out_msg_no++; /* increment message number */
340 if (bsock->msglen <= 0) { /* length only? */
341 return 1; /* yes, no data */
344 /* send data packet */
345 bsock->timer_start = watchdog_time; /* start timer */
346 bsock->timed_out = 0;
347 rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
348 bsock->timer_start = 0; /* clear timer */
349 if (rc != bsock->msglen) {
352 bsock->b_errno = EIO;
354 bsock->b_errno = errno;
357 if (!bsock->suppress_error_msgs) {
358 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
359 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
362 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
363 bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
371 * Establish an SSL connection -- server side
372 * Codes that ssl_need and ssl_has can take
373 * BNET_SSL_NONE I cannot do ssl
374 * BNET_SSL_OK I can do ssl, but it is not required on my end
375 * BNET_SSL_REQUIRED ssl is required on my end
378 bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
380 /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
381 /* The other side expects a response from us */
386 * Establish an SSL connection -- client side
388 int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
390 /* We are the client so we must wait for the server to notify us */
396 * Wait for a specified time for data to appear on
397 * the BSOCK connection.
399 * Returns: 1 if data available
404 bnet_wait_data(BSOCK *bsock, int sec)
410 FD_SET(bsock->fd, &fdset);
414 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
415 case 0: /* timeout */
419 bsock->b_errno = errno;
420 if (errno == EINTR || errno == EAGAIN) {
423 return -1; /* error return */
432 * As above, but returns on interrupt
435 bnet_wait_data_intr(BSOCK *bsock, int sec)
441 FD_SET(bsock->fd, &fdset);
445 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
446 case 0: /* timeout */
450 bsock->b_errno = errno;
451 return -1; /* error return */
460 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
463 * Convert a hostname or dotted IP address into
464 * a s_addr. We handle only IPv4.
466 static uint32_t *bget_host_ip(JCR *jcr, char *host)
468 struct in_addr inaddr;
469 uint32_t *addr_list; /* this really should be struct in_addr */
474 if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
475 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
476 addr_list[0] = inaddr.s_addr;
477 addr_list[1] = (uint32_t) -1;
480 if ((hp = gethostbyname(host)) == NULL) {
481 Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n",
482 host, strerror(errno));
486 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
487 Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
488 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
493 for (p = hp->h_addr_list; *p != 0; p++) {
497 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
499 for (p = hp->h_addr_list; *p != 0; p++) {
500 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
502 addr_list[i] = (uint32_t) -1;
509 * Open a TCP connection to the UPS network server
511 * Returns BSOCK * pointer on success
513 * ***FIXME*** implement service from /etc/services
516 bnet_open(JCR *jcr, char *name, char *host, char *service, int port, int *fatal)
519 struct sockaddr_in tcp_serv_addr; /* socket information */
521 int i, connected = 0;
525 * Fill in the structure serv_addr with the address of
526 * the server that we want to connect with.
528 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
529 tcp_serv_addr.sin_family = AF_INET;
530 tcp_serv_addr.sin_port = htons(port);
532 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
537 /* Open a TCP socket */
538 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
545 * Receive notification when connection dies.
547 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
548 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
551 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
552 /* connect to server */
553 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
554 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
566 return init_bsock(jcr, sockfd, name, host, port);
570 * Try to connect to host for max_retry_time at retry_time intervals.
573 bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, char *name,
574 char *host, char *service, int port, int verbose)
580 for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
581 if (fatal || (jcr && job_canceled(jcr))) {
584 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
585 name, host, port, strerror(errno));
587 i = 60 * 5; /* complain again in 5 minutes */
589 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
590 Retrying ...\n", name, host, port, strerror(errno));
592 bmicrosleep(retry_interval, 0);
593 max_retry_time -= retry_interval;
594 if (max_retry_time <= 0) {
595 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
596 name, host, port, strerror(errno));
605 * Return the string for the error that occurred
606 * on the socket. Only the first error is retained.
608 char *bnet_strerror(BSOCK *bsock)
610 return strerror(bsock->b_errno);
614 * Format and send a message
615 * Returns: 0 on failure
619 bnet_fsend(BSOCK *bs, char *fmt, ...)
624 /* This probably won't work, but we vsnprintf, then if we
625 * get a negative length or a length greater than our buffer
626 * (depending on which library is used), the printf was truncated, so
627 * get a biger buffer and try again.
630 maxlen = sizeof_pool_memory(bs->msg) - 1;
631 va_start(arg_ptr, fmt);
632 bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
634 if (bs->msglen < 0 || bs->msglen >= maxlen) {
635 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
638 return bnet_send(bs) < 0 ? 0 : 1;
642 * Set the network buffer size, suggested size is in size.
643 * Actual size obtained is returned in bs->msglen
645 * Returns: 0 on failure
648 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
651 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
654 opt = IPTOS_THROUGHPUT;
655 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
659 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
660 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
663 if (rw & BNET_SETBUF_READ) {
664 while ((dbuf_size > TAPE_BSIZE) &&
665 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
666 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
667 dbuf_size -= TAPE_BSIZE;
669 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
670 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
671 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
672 if (dbuf_size % TAPE_BSIZE != 0) {
673 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
678 if (rw & BNET_SETBUF_WRITE) {
679 while ((dbuf_size > TAPE_BSIZE) &&
680 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
681 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
682 dbuf_size -= TAPE_BSIZE;
684 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
685 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
686 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
687 if (dbuf_size % TAPE_BSIZE != 0) {
688 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
693 bs->msglen = dbuf_size;
698 * Send a network "signal" to the other end
699 * This consists of sending a negative packet length
701 * Returns: 0 on failure
704 int bnet_sig(BSOCK *bs, int sig)
707 return bnet_send(bs);
711 * Convert a network "signal" code into
712 * human readable ASCII.
714 char *bnet_sig_to_ascii(BSOCK *bs)
717 switch (bs->msglen) {
719 return "BNET_EOD"; /* end of data stream */
721 return "BNET_EOD_POLL";
723 return "BNET_STATUS";
725 return "BNET_TERMINATE"; /* terminate connection */
729 return "BNET_HEARTBEAT";
730 case BNET_HB_RESPONSE:
731 return "BNET_HB_RESPONSE";
733 return "BNET_PROMPT";
735 sprintf(buf, "Unknown sig %d", bs->msglen);
741 /* Initialize internal socket structure.
742 * This probably should be done in net_open
745 init_bsock(JCR *jcr, int sockfd, char *who, char *host, int port)
747 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
748 memset(bsock, 0, sizeof(BSOCK));
751 bsock->msg = get_pool_memory(PM_MESSAGE);
752 bsock->errmsg = get_pool_memory(PM_MESSAGE);
753 bsock->who = bstrdup(who);
754 bsock->host = bstrdup(host);
757 * ****FIXME**** reduce this to a few hours once
758 * heartbeats are implemented
760 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
766 dup_bsock(BSOCK *osock)
768 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
769 memcpy(bsock, osock, sizeof(BSOCK));
770 bsock->msg = get_pool_memory(PM_MESSAGE);
771 bsock->errmsg = get_pool_memory(PM_MESSAGE);
773 bsock->who = bstrdup(osock->who);
776 bsock->host = bstrdup(osock->host);
782 /* Close the network connection */
784 bnet_close(BSOCK *bsock)
788 for ( ; bsock != NULL; bsock = next) {
799 term_bsock(BSOCK *bsock)
802 free_pool_memory(bsock->msg);
805 ASSERT(1==0); /* double close */
808 free_pool_memory(bsock->errmsg);
809 bsock->errmsg = NULL;