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 Jmsg0(bsock->jcr, M_FATAL, 0, _("Received packet too big. Terminating.\n"));
192 pktsiz = BNET_TERMINATE; /* hang up */
194 if (pktsiz == BNET_TERMINATE) {
195 bsock->terminated = 1;
197 bsock->timer_start = 0; /* clear timer */
198 bsock->b_errno = ENODATA;
199 bsock->msglen = pktsiz; /* signal code */
200 return BNET_SIGNAL; /* signal */
203 /* Make sure the buffer is big enough + one byte for EOS */
204 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
205 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
208 bsock->timer_start = watchdog_time; /* set start wait time */
209 bsock->timed_out = 0;
210 /* now read the actual data */
211 if ((nbytes = read_nbytes(bsock, mp_chr(bsock->msg), pktsiz)) <= 0) {
212 bsock->timer_start = 0; /* clear timer */
214 bsock->b_errno = ENODATA;
216 bsock->b_errno = errno;
219 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
220 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
223 bsock->timer_start = 0; /* clear timer */
225 bsock->msglen = nbytes;
226 if (nbytes != pktsiz) {
227 bsock->b_errno = EIO;
229 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
230 bsock->who, bsock->host, bsock->port);
233 /* always add a zero by to properly terminate any
234 * string that was send to us. Note, we ensured above that the
235 * buffer is at least one byte longer than the message length.
237 mp_chr(bsock->msg)[nbytes] = 0; /* terminate in case it is a string */
238 sm_check(__FILE__, __LINE__, False);
239 return nbytes; /* return actual length of message */
244 * Return 1 if there are errors on this bsock or it is closed,
245 * i.e. stop communicating on this line.
247 int is_bnet_stop(BSOCK *bsock)
249 return bsock->errors || bsock->terminated;
253 * Return number of errors on socket
255 int is_bnet_error(BSOCK *bsock)
257 return bsock->errors;
261 * Call here after error during closing to suppress error
262 * messages which are due to the other end shutting down too.
265 bnet_suppress_error_messages(BSOCK *bsock, int flag)
267 bsock->suppress_error_msgs = flag;
272 * Transmit spooled data now
274 int bnet_despool(BSOCK *bsock)
279 rewind(bsock->spool_fd);
280 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
281 bsock->msglen = ntohl(pktsiz);
282 if (bsock->msglen > 0) {
283 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
284 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
286 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
287 if (nbytes != (size_t)bsock->msglen) {
288 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
289 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
295 if (ferror(bsock->spool_fd)) {
296 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
304 * Send a message over the network. The send consists of
305 * two network packets. The first is sends a 32 bit integer containing
306 * the length of the data packet which follows.
308 * Returns: 0 on failure
312 bnet_send(BSOCK *bsock)
317 if (bsock->errors || bsock->terminated) {
320 pktsiz = htonl((int32_t)bsock->msglen);
321 /* send int32_t containing size of data packet */
322 bsock->timer_start = watchdog_time; /* start timer */
323 bsock->timed_out = 0;
324 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
325 bsock->timer_start = 0; /* clear timer */
326 if (rc != sizeof(int32_t)) {
327 if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
328 bsock->terminated = 1;
329 return 0; /* ignore any errors */
333 bsock->b_errno = EIO;
335 bsock->b_errno = errno;
338 if (!bsock->suppress_error_msgs && !bsock->timed_out) {
339 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
340 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
343 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
344 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
349 bsock->out_msg_no++; /* increment message number */
350 if (bsock->msglen <= 0) { /* length only? */
351 return 1; /* yes, no data */
354 /* send data packet */
355 bsock->timer_start = watchdog_time; /* start timer */
356 bsock->timed_out = 0;
357 rc = write_nbytes(bsock, mp_chr(bsock->msg), bsock->msglen);
358 bsock->timer_start = 0; /* clear timer */
359 if (rc != bsock->msglen) {
362 bsock->b_errno = EIO;
364 bsock->b_errno = errno;
367 if (!bsock->suppress_error_msgs) {
368 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
369 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
372 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
373 bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
381 * Establish an SSL connection -- server side
382 * Codes that ssl_need and ssl_has can take
383 * BNET_SSL_NONE I cannot do ssl
384 * BNET_SSL_OK I can do ssl, but it is not required on my end
385 * BNET_SSL_REQUIRED ssl is required on my end
388 bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
390 /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
391 /* The other side expects a response from us */
396 * Establish an SSL connection -- client side
398 int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
400 /* We are the client so we must wait for the server to notify us */
406 * Wait for a specified time for data to appear on
407 * the BSOCK connection.
409 * Returns: 1 if data available
414 bnet_wait_data(BSOCK *bsock, int sec)
420 FD_SET(bsock->fd, &fdset);
424 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
425 case 0: /* timeout */
429 bsock->b_errno = errno;
430 if (errno == EINTR || errno == EAGAIN) {
433 return -1; /* error return */
442 * As above, but returns on interrupt
445 bnet_wait_data_intr(BSOCK *bsock, int sec)
451 FD_SET(bsock->fd, &fdset);
455 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
456 case 0: /* timeout */
460 bsock->b_errno = errno;
461 return -1; /* error return */
470 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
473 * Convert a hostname or dotted IP address into
474 * a s_addr. We handle only IPv4.
476 static uint32_t *bget_host_ip(JCR *jcr, char *host)
478 struct in_addr inaddr;
479 uint32_t *addr_list; /* this really should be struct in_addr */
484 if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
485 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
486 addr_list[0] = inaddr.s_addr;
487 addr_list[1] = (uint32_t) -1;
490 if ((hp = gethostbyname(host)) == NULL) {
491 Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n",
492 host, strerror(errno));
496 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
497 Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
498 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
503 for (p = hp->h_addr_list; *p != 0; p++) {
507 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
509 for (p = hp->h_addr_list; *p != 0; p++) {
510 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
512 addr_list[i] = (uint32_t) -1;
519 * Open a TCP connection to the UPS network server
521 * Returns BSOCK * pointer on success
523 * ***FIXME*** implement service from /etc/services
526 bnet_open(JCR *jcr, char *name, char *host, char *service, int port, int *fatal)
529 struct sockaddr_in tcp_serv_addr; /* socket information */
531 int i, connected = 0;
535 * Fill in the structure serv_addr with the address of
536 * the server that we want to connect with.
538 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
539 tcp_serv_addr.sin_family = AF_INET;
540 tcp_serv_addr.sin_port = htons(port);
542 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
547 /* Open a TCP socket */
548 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
555 * Receive notification when connection dies.
557 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
558 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
561 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
562 /* connect to server */
563 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
564 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
576 return init_bsock(jcr, sockfd, name, host, port);
580 * Try to connect to host for max_retry_time at retry_time intervals.
583 bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, char *name,
584 char *host, char *service, int port, int verbose)
590 for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
591 if (fatal || (jcr && job_canceled(jcr))) {
594 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
595 name, host, port, strerror(errno));
597 i = 60 * 5; /* complain again in 5 minutes */
599 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
600 Retrying ...\n", name, host, port, strerror(errno));
602 bmicrosleep(retry_interval, 0);
603 max_retry_time -= retry_interval;
604 if (max_retry_time <= 0) {
605 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
606 name, host, port, strerror(errno));
615 * Return the string for the error that occurred
616 * on the socket. Only the first error is retained.
618 char *bnet_strerror(BSOCK *bsock)
620 return strerror(bsock->b_errno);
624 * Format and send a message
625 * Returns: 0 on failure
629 bnet_fsend(BSOCK *bs, char *fmt, ...)
634 /* This probably won't work, but we vsnprintf, then if we
635 * get a negative length or a length greater than our buffer
636 * (depending on which library is used), the printf was truncated, so
637 * get a biger buffer and try again.
640 maxlen = sizeof_pool_memory(bs->msg) - 1;
641 va_start(arg_ptr, fmt);
642 bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
644 if (bs->msglen < 0 || bs->msglen >= maxlen) {
645 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
648 return bnet_send(bs) < 0 ? 0 : 1;
652 * Set the network buffer size, suggested size is in size.
653 * Actual size obtained is returned in bs->msglen
655 * Returns: 0 on failure
658 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
661 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
664 opt = IPTOS_THROUGHPUT;
665 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
669 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
670 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
673 if (rw & BNET_SETBUF_READ) {
674 while ((dbuf_size > TAPE_BSIZE) &&
675 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
676 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
677 dbuf_size -= TAPE_BSIZE;
679 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
680 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
681 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
682 if (dbuf_size % TAPE_BSIZE != 0) {
683 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
688 if (rw & BNET_SETBUF_WRITE) {
689 while ((dbuf_size > TAPE_BSIZE) &&
690 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
691 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
692 dbuf_size -= TAPE_BSIZE;
694 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
695 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
696 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
697 if (dbuf_size % TAPE_BSIZE != 0) {
698 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
703 bs->msglen = dbuf_size;
708 * Send a network "signal" to the other end
709 * This consists of sending a negative packet length
711 * Returns: 0 on failure
714 int bnet_sig(BSOCK *bs, int sig)
717 return bnet_send(bs);
721 * Convert a network "signal" code into
722 * human readable ASCII.
724 char *bnet_sig_to_ascii(BSOCK *bs)
727 switch (bs->msglen) {
729 return "BNET_EOD"; /* end of data stream */
731 return "BNET_EOD_POLL";
733 return "BNET_STATUS";
735 return "BNET_TERMINATE"; /* terminate connection */
739 return "BNET_HEARTBEAT";
740 case BNET_HB_RESPONSE:
741 return "BNET_HB_RESPONSE";
743 return "BNET_PROMPT";
745 sprintf(buf, "Unknown sig %d", bs->msglen);
751 /* Initialize internal socket structure.
752 * This probably should be done in net_open
755 init_bsock(JCR *jcr, int sockfd, char *who, char *host, int port)
757 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
758 memset(bsock, 0, sizeof(BSOCK));
761 bsock->msg = get_pool_memory(PM_MESSAGE);
762 bsock->errmsg = get_pool_memory(PM_MESSAGE);
763 bsock->who = bstrdup(who);
764 bsock->host = bstrdup(host);
767 * ****FIXME**** reduce this to a few hours once
768 * heartbeats are implemented
770 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
776 dup_bsock(BSOCK *osock)
778 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
779 memcpy(bsock, osock, sizeof(BSOCK));
780 bsock->msg = get_pool_memory(PM_MESSAGE);
781 bsock->errmsg = get_pool_memory(PM_MESSAGE);
783 bsock->who = bstrdup(osock->who);
786 bsock->host = bstrdup(osock->host);
792 /* Close the network connection */
794 bnet_close(BSOCK *bsock)
798 for ( ; bsock != NULL; bsock = next) {
801 if (bsock->timed_out) {
802 shutdown(bsock->fd, 2); /* discard any pending I/O */
804 close(bsock->fd); /* normal close */
812 term_bsock(BSOCK *bsock)
815 free_pool_memory(bsock->msg);
818 ASSERT(1==0); /* double close */
821 free_pool_memory(bsock->errmsg);
822 bsock->errmsg = NULL;