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 */
49 * Read a nbytes from the network.
50 * It is possible that the total bytes require in several
54 static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
62 nread = read(bsock->fd, ptr, nleft);
63 if (bsock->timed_out || bsock->terminated) {
66 } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
68 return nread; /* error, or EOF */
73 return nbytes - nleft; /* return >= 0 */
77 * Write nbytes to the network.
78 * It may require several writes.
81 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
83 int32_t nleft, nwritten;
86 nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
87 if (nwritten != nbytes) {
88 Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno));
89 Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
98 nwritten = write(bsock->fd, ptr, nleft);
99 if (bsock->timed_out || bsock->terminated) {
102 } while (nwritten == -1 && errno == EINTR);
104 * If connection is non-blocking, we will get EAGAIN, so
105 * use select() to keep from consuming all the CPU
108 if (nwritten == -1 && errno == EAGAIN) {
113 FD_SET(bsock->fd, &fdset);
116 select(bsock->fd + 1, NULL, &fdset, NULL, &tv);
120 return nwritten; /* error */
129 * Receive a message from the other end. Each message consists of
130 * two packets. The first is a header that contains the size
131 * of the data that follows in the second packet.
132 * Returns number of bytes read (may return zero)
133 * Returns -1 on signal (BNET_SIGNAL)
134 * Returns -2 on hard end of file (BNET_HARDEOF)
135 * Returns -3 on error (BNET_ERROR)
137 * Unfortunately, it is a bit complicated because we have these
140 * 2. Signal including end of data stream
141 * 3. Hard end of file
143 * Using is_bnet_stop() and is_bnet_error() you can figure this all out.
145 int32_t bnet_recv(BSOCK *bsock)
150 mp_chr(bsock->msg)[0] = 0;
151 if (bsock->errors || bsock->terminated) {
155 bsock->read_seqno++; /* bump sequence number */
156 bsock->timer_start = watchdog_time; /* set start wait time */
157 bsock->timed_out = 0;
158 /* get data size -- in int32_t */
159 if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
160 bsock->timer_start = 0; /* clear timer */
161 /* probably pipe broken because client died */
163 bsock->b_errno = ENODATA;
165 bsock->b_errno = errno;
168 return BNET_HARDEOF; /* assume hard EOF received */
170 bsock->timer_start = 0; /* clear timer */
171 if (nbytes != sizeof(int32_t)) {
173 bsock->b_errno = EIO;
174 Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
179 pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
181 if (pktsiz == 0) { /* No data transferred */
182 bsock->timer_start = 0; /* clear timer */
185 return 0; /* zero bytes read */
188 /* If signal or packet size too big */
189 if (pktsiz < 0 || pktsiz > 1000000) {
190 if (pktsiz > 0) { /* if packet too big */
191 pktsiz = BNET_TERMINATE; /* hang up */
193 if (pktsiz == BNET_TERMINATE) {
194 bsock->terminated = 1;
196 bsock->timer_start = 0; /* clear timer */
197 bsock->b_errno = ENODATA;
198 bsock->msglen = pktsiz; /* signal code */
199 return BNET_SIGNAL; /* signal */
202 /* Make sure the buffer is big enough + one byte for EOS */
203 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
204 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
207 bsock->timer_start = watchdog_time; /* set start wait time */
208 bsock->timed_out = 0;
209 /* now read the actual data */
210 if ((nbytes = read_nbytes(bsock, mp_chr(bsock->msg), pktsiz)) <= 0) {
211 bsock->timer_start = 0; /* clear timer */
213 bsock->b_errno = ENODATA;
215 bsock->b_errno = errno;
218 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
219 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
222 bsock->timer_start = 0; /* clear timer */
224 bsock->msglen = nbytes;
225 if (nbytes != pktsiz) {
226 bsock->b_errno = EIO;
228 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
229 bsock->who, bsock->host, bsock->port);
232 /* always add a zero by to properly terminate any
233 * string that was send to us. Note, we ensured above that the
234 * buffer is at least one byte longer than the message length.
236 mp_chr(bsock->msg)[nbytes] = 0; /* terminate in case it is a string */
237 sm_check(__FILE__, __LINE__, False);
238 return nbytes; /* return actual length of message */
243 * Return 1 if there are errors on this bsock or it is closed,
244 * i.e. stop communicating on this line.
246 int is_bnet_stop(BSOCK *bsock)
248 return bsock->errors || bsock->terminated;
252 * Return number of errors on socket
254 int is_bnet_error(BSOCK *bsock)
256 return bsock->errors;
260 * Call here after error during closing to suppress error
261 * messages which are due to the other end shutting down too.
264 bnet_suppress_error_messages(BSOCK *bsock, int flag)
266 bsock->suppress_error_msgs = flag;
271 * Transmit spooled data now
273 int bnet_despool(BSOCK *bsock)
278 rewind(bsock->spool_fd);
279 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
280 bsock->msglen = ntohl(pktsiz);
281 if (bsock->msglen > 0) {
282 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
283 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
285 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
286 if (nbytes != (size_t)bsock->msglen) {
287 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
288 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
294 if (ferror(bsock->spool_fd)) {
295 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
303 * Send a message over the network. The send consists of
304 * two network packets. The first is sends a 32 bit integer containing
305 * the length of the data packet which follows.
307 * Returns: 0 on failure
311 bnet_send(BSOCK *bsock)
316 if (bsock->errors || bsock->terminated) {
319 pktsiz = htonl((int32_t)bsock->msglen);
320 /* send int32_t containing size of data packet */
321 bsock->timer_start = watchdog_time; /* start timer */
322 bsock->timed_out = 0;
323 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
324 bsock->timer_start = 0; /* clear timer */
325 if (rc != sizeof(int32_t)) {
326 if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
327 bsock->terminated = 1;
328 return 0; /* ignore any errors */
332 bsock->b_errno = EIO;
334 bsock->b_errno = errno;
337 if (!bsock->suppress_error_msgs && !bsock->timed_out) {
338 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
339 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
342 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
343 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
348 bsock->out_msg_no++; /* increment message number */
349 if (bsock->msglen <= 0) { /* length only? */
350 return 1; /* yes, no data */
353 /* send data packet */
354 bsock->timer_start = watchdog_time; /* start timer */
355 bsock->timed_out = 0;
356 rc = write_nbytes(bsock, mp_chr(bsock->msg), bsock->msglen);
357 bsock->timer_start = 0; /* clear timer */
358 if (rc != bsock->msglen) {
361 bsock->b_errno = EIO;
363 bsock->b_errno = errno;
366 if (!bsock->suppress_error_msgs) {
367 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
368 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
371 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
372 bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
380 * Establish an SSL connection -- server side
381 * Codes that ssl_need and ssl_has can take
382 * BNET_SSL_NONE I cannot do ssl
383 * BNET_SSL_OK I can do ssl, but it is not required on my end
384 * BNET_SSL_REQUIRED ssl is required on my end
387 bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
389 /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
390 /* The other side expects a response from us */
395 * Establish an SSL connection -- client side
397 int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
399 /* We are the client so we must wait for the server to notify us */
405 * Wait for a specified time for data to appear on
406 * the BSOCK connection.
408 * Returns: 1 if data available
413 bnet_wait_data(BSOCK *bsock, int sec)
419 FD_SET(bsock->fd, &fdset);
423 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
424 case 0: /* timeout */
428 bsock->b_errno = errno;
429 if (errno == EINTR || errno == EAGAIN) {
432 return -1; /* error return */
441 * As above, but returns on interrupt
444 bnet_wait_data_intr(BSOCK *bsock, int sec)
450 FD_SET(bsock->fd, &fdset);
454 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
455 case 0: /* timeout */
459 bsock->b_errno = errno;
460 return -1; /* error return */
469 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
472 * Convert a hostname or dotted IP address into
473 * a s_addr. We handle only IPv4.
475 static uint32_t *bget_host_ip(JCR *jcr, char *host)
477 struct in_addr inaddr;
478 uint32_t *addr_list; /* this really should be struct in_addr */
483 if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
484 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
485 addr_list[0] = inaddr.s_addr;
486 addr_list[1] = (uint32_t) -1;
489 if ((hp = gethostbyname(host)) == NULL) {
490 Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n",
491 host, strerror(errno));
495 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
496 Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
497 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
502 for (p = hp->h_addr_list; *p != 0; p++) {
506 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
508 for (p = hp->h_addr_list; *p != 0; p++) {
509 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
511 addr_list[i] = (uint32_t) -1;
518 * Open a TCP connection to the UPS network server
520 * Returns BSOCK * pointer on success
522 * ***FIXME*** implement service from /etc/services
525 bnet_open(JCR *jcr, char *name, char *host, char *service, int port, int *fatal)
528 struct sockaddr_in tcp_serv_addr; /* socket information */
530 int i, connected = 0;
534 * Fill in the structure serv_addr with the address of
535 * the server that we want to connect with.
537 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
538 tcp_serv_addr.sin_family = AF_INET;
539 tcp_serv_addr.sin_port = htons(port);
541 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
546 /* Open a TCP socket */
547 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
554 * Receive notification when connection dies.
556 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
557 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
560 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
561 /* connect to server */
562 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
563 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
575 return init_bsock(jcr, sockfd, name, host, port);
579 * Try to connect to host for max_retry_time at retry_time intervals.
582 bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, char *name,
583 char *host, char *service, int port, int verbose)
589 for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
590 if (fatal || (jcr && job_canceled(jcr))) {
593 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
594 name, host, port, strerror(errno));
596 i = 60 * 5; /* complain again in 5 minutes */
598 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
599 Retrying ...\n", name, host, port, strerror(errno));
601 bmicrosleep(retry_interval, 0);
602 max_retry_time -= retry_interval;
603 if (max_retry_time <= 0) {
604 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
605 name, host, port, strerror(errno));
614 * Return the string for the error that occurred
615 * on the socket. Only the first error is retained.
617 char *bnet_strerror(BSOCK *bsock)
619 return strerror(bsock->b_errno);
623 * Format and send a message
624 * Returns: 0 on failure
628 bnet_fsend(BSOCK *bs, char *fmt, ...)
633 /* This probably won't work, but we vsnprintf, then if we
634 * get a negative length or a length greater than our buffer
635 * (depending on which library is used), the printf was truncated, so
636 * get a biger buffer and try again.
639 maxlen = sizeof_pool_memory(bs->msg) - 1;
640 va_start(arg_ptr, fmt);
641 bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
643 if (bs->msglen < 0 || bs->msglen >= maxlen) {
644 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
647 return bnet_send(bs) < 0 ? 0 : 1;
651 * Set the network buffer size, suggested size is in size.
652 * Actual size obtained is returned in bs->msglen
654 * Returns: 0 on failure
657 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
660 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
663 opt = IPTOS_THROUGHPUT;
664 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
668 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
669 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
672 if (rw & BNET_SETBUF_READ) {
673 while ((dbuf_size > TAPE_BSIZE) &&
674 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
675 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
676 dbuf_size -= TAPE_BSIZE;
678 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
679 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
680 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
681 if (dbuf_size % TAPE_BSIZE != 0) {
682 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
687 if (rw & BNET_SETBUF_WRITE) {
688 while ((dbuf_size > TAPE_BSIZE) &&
689 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
690 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
691 dbuf_size -= TAPE_BSIZE;
693 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
694 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
695 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
696 if (dbuf_size % TAPE_BSIZE != 0) {
697 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
702 bs->msglen = dbuf_size;
707 * Send a network "signal" to the other end
708 * This consists of sending a negative packet length
710 * Returns: 0 on failure
713 int bnet_sig(BSOCK *bs, int sig)
716 return bnet_send(bs);
720 * Convert a network "signal" code into
721 * human readable ASCII.
723 char *bnet_sig_to_ascii(BSOCK *bs)
726 switch (bs->msglen) {
728 return "BNET_EOD"; /* end of data stream */
730 return "BNET_EOD_POLL";
732 return "BNET_STATUS";
734 return "BNET_TERMINATE"; /* terminate connection */
738 return "BNET_HEARTBEAT";
739 case BNET_HB_RESPONSE:
740 return "BNET_HB_RESPONSE";
742 return "BNET_PROMPT";
744 sprintf(buf, "Unknown sig %d", bs->msglen);
750 /* Initialize internal socket structure.
751 * This probably should be done in net_open
754 init_bsock(JCR *jcr, int sockfd, char *who, char *host, int port)
756 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
757 memset(bsock, 0, sizeof(BSOCK));
760 bsock->msg = get_pool_memory(PM_MESSAGE);
761 bsock->errmsg = get_pool_memory(PM_MESSAGE);
762 bsock->who = bstrdup(who);
763 bsock->host = bstrdup(host);
766 * ****FIXME**** reduce this to a few hours once
767 * heartbeats are implemented
769 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
775 dup_bsock(BSOCK *osock)
777 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
778 memcpy(bsock, osock, sizeof(BSOCK));
779 bsock->msg = get_pool_memory(PM_MESSAGE);
780 bsock->errmsg = get_pool_memory(PM_MESSAGE);
782 bsock->who = bstrdup(osock->who);
785 bsock->host = bstrdup(osock->host);
791 /* Close the network connection */
793 bnet_close(BSOCK *bsock)
797 for ( ; bsock != NULL; bsock = next) {
800 if (bsock->timed_out) {
801 shutdown(bsock->fd, 2); /* discard any pending I/O */
803 close(bsock->fd); /* normal close */
811 term_bsock(BSOCK *bsock)
814 free_pool_memory(bsock->msg);
817 ASSERT(1==0); /* double close */
820 free_pool_memory(bsock->errmsg);
821 bsock->errmsg = NULL;