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 } while (!bsock->timed_out && nread == -1 && (errno == EINTR || errno == EAGAIN));
63 return nread; /* error, or EOF */
68 return nbytes - nleft; /* return >= 0 */
72 * Write nbytes to the network.
73 * It may require several writes.
76 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
78 int32_t nleft, nwritten;
81 nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
82 if (nwritten != nbytes) {
83 Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno));
84 Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
93 nwritten = write(bsock->fd, ptr, nleft);
94 } while (!bsock->timed_out && nwritten == -1 && (errno == EINTR || errno == EAGAIN));
96 return nwritten; /* error */
105 * Receive a message from the other end. Each message consists of
106 * two packets. The first is a header that contains the size
107 * of the data that follows in the second packet.
108 * Returns number of bytes read (may return zero)
109 * Returns -1 on signal (BNET_SIGNAL)
110 * Returns -2 on hard end of file (BNET_HARDEOF)
111 * Returns -3 on error (BNET_ERROR)
113 * Unfortunately, it is a bit complicated because we have these
116 * 2. Signal including end of data stream
117 * 3. Hard end of file
119 * Using is_bnet_stop() and is_bnet_error() you can figure this all out.
121 int32_t bnet_recv(BSOCK *bsock)
127 if (bsock->errors || bsock->terminated) {
131 bsock->read_seqno++; /* bump sequence number */
132 bsock->timer_start = watchdog_time; /* set start wait time */
133 bsock->timed_out = 0;
134 /* get data size -- in int32_t */
135 if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
136 bsock->timer_start = 0; /* clear timer */
137 /* probably pipe broken because client died */
139 bsock->b_errno = ENODATA;
141 bsock->b_errno = errno;
144 return BNET_HARDEOF; /* assume hard EOF received */
146 bsock->timer_start = 0; /* clear timer */
147 if (nbytes != sizeof(int32_t)) {
149 bsock->b_errno = EIO;
150 Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
155 pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
157 if (pktsiz == 0) { /* No data transferred */
158 bsock->timer_start = 0; /* clear timer */
161 return 0; /* zero bytes read */
164 /* If signal or packet size too big */
165 if (pktsiz < 0 || pktsiz > 1000000) {
166 if (pktsiz > 0) { /* if packet too big */
167 pktsiz = BNET_TERMINATE; /* hang up */
169 if (pktsiz == BNET_TERMINATE) {
170 bsock->terminated = 1;
172 bsock->timer_start = 0; /* clear timer */
173 bsock->b_errno = ENODATA;
174 bsock->msglen = pktsiz; /* signal code */
175 return BNET_SIGNAL; /* signal */
178 /* Make sure the buffer is big enough + one byte for EOS */
179 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
180 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
183 bsock->timer_start = watchdog_time; /* set start wait time */
184 bsock->timed_out = 0;
185 /* now read the actual data */
186 if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <= 0) {
187 bsock->timer_start = 0; /* clear timer */
189 bsock->b_errno = ENODATA;
191 bsock->b_errno = errno;
194 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
195 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
198 bsock->timer_start = 0; /* clear timer */
200 bsock->msglen = nbytes;
201 if (nbytes != pktsiz) {
202 bsock->b_errno = EIO;
204 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
205 bsock->who, bsock->host, bsock->port);
208 /* always add a zero by to properly terminate any
209 * string that was send to us. Note, we ensured above that the
210 * buffer is at least one byte longer than the message length.
212 bsock->msg[nbytes] = 0; /* terminate in case it is a string */
213 sm_check(__FILE__, __LINE__, False);
214 return nbytes; /* return actual length of message */
219 * Return 1 if there are errors on this bsock or it is closed,
220 * i.e. stop communicating on this line.
222 int is_bnet_stop(BSOCK *bsock)
224 return bsock->errors || bsock->terminated;
228 * Return number of errors on socket
230 int is_bnet_error(BSOCK *bsock)
232 return bsock->errors;
236 * Call here after error during closing to suppress error
237 * messages which are due to the other end shutting down too.
240 bnet_suppress_error_messages(BSOCK *bsock, int flag)
242 bsock->suppress_error_msgs = flag;
247 * Transmit spooled data now
249 int bnet_despool(BSOCK *bsock)
254 rewind(bsock->spool_fd);
255 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
256 bsock->msglen = ntohl(pktsiz);
257 if (bsock->msglen > 0) {
258 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
259 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
261 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
262 if (nbytes != (size_t)bsock->msglen) {
263 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
264 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
270 if (ferror(bsock->spool_fd)) {
271 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
279 * Send a message over the network. The send consists of
280 * two network packets. The first is sends a 32 bit integer containing
281 * the length of the data packet which follows.
283 * Returns: 0 on failure
287 bnet_send(BSOCK *bsock)
292 if (bsock->errors || bsock->terminated) {
295 pktsiz = htonl((int32_t)bsock->msglen);
296 /* send int32_t containing size of data packet */
297 bsock->timer_start = watchdog_time; /* start timer */
298 bsock->timed_out = 0;
299 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
300 bsock->timer_start = 0; /* clear timer */
301 if (rc != sizeof(int32_t)) {
304 bsock->b_errno = EIO;
306 bsock->b_errno = errno;
309 if (!bsock->suppress_error_msgs) {
310 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
311 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
314 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
315 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
320 bsock->out_msg_no++; /* increment message number */
321 if (bsock->msglen <= 0) { /* length only? */
322 return 1; /* yes, no data */
325 /* send data packet */
326 bsock->timer_start = watchdog_time; /* start timer */
327 bsock->timed_out = 0;
328 rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
329 bsock->timer_start = 0; /* clear timer */
330 if (rc != bsock->msglen) {
333 bsock->b_errno = EIO;
335 bsock->b_errno = errno;
338 if (!bsock->suppress_error_msgs) {
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);
352 * Wait for a specified time for data to appear on
353 * the BSOCK connection.
355 * Returns: 1 if data available
360 bnet_wait_data(BSOCK *bsock, int sec)
366 FD_SET(bsock->fd, &fdset);
370 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
371 case 0: /* timeout */
375 bsock->b_errno = errno;
376 if (errno == EINTR || errno == EAGAIN) {
379 return -1; /* error return */
387 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
390 * Convert a hostname or dotted IP address into
391 * a s_addr. We handle only IPv4.
393 static uint32_t *bget_host_ip(void *jcr, char *host)
395 struct in_addr inaddr;
396 uint32_t *addr_list; /* this really should be struct in_addr */
401 if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
402 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
403 addr_list[0] = inaddr.s_addr;
404 addr_list[1] = (uint32_t) -1;
407 if ((hp = gethostbyname(host)) == NULL) {
408 Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n",
409 host, strerror(errno));
413 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
414 Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
415 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
420 for (p = hp->h_addr_list; *p != 0; p++) {
424 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
426 for (p = hp->h_addr_list; *p != 0; p++) {
427 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
429 addr_list[i] = (uint32_t) -1;
436 * Open a TCP connection to the UPS network server
438 * Returns BSOCK * pointer on success
440 * ***FIXME*** implement service from /etc/services
443 bnet_open(void *jcr, char *name, char *host, char *service, int port, int *fatal)
446 struct sockaddr_in tcp_serv_addr; /* socket information */
448 int i, connected = 0;
452 * Fill in the structure serv_addr with the address of
453 * the server that we want to connect with.
455 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
456 tcp_serv_addr.sin_family = AF_INET;
457 tcp_serv_addr.sin_port = htons(port);
459 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
464 /* Open a TCP socket */
465 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
472 * Receive notification when connection dies.
474 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
475 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
478 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
479 /* connect to server */
480 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
481 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
493 return init_bsock(jcr, sockfd, name, host, port);
497 * Try to connect to host for max_retry_time at retry_time intervals.
500 bnet_connect(void *vjcr, int retry_interval, int max_retry_time, char *name,
501 char *host, char *service, int port, int verbose)
505 JCR *jcr = (JCR *)vjcr;
508 for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
509 if (fatal || (jcr && job_canceled(jcr))) {
512 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
513 name, host, port, strerror(errno));
515 i = 60 * 5; /* complain again in 5 minutes */
517 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
518 Retrying ...\n", name, host, port, strerror(errno));
520 sleep(retry_interval);
521 max_retry_time -= retry_interval;
522 if (max_retry_time <= 0) {
523 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
524 name, host, port, strerror(errno));
533 * Return the string for the error that occurred
534 * on the socket. Only the first error is retained.
536 char *bnet_strerror(BSOCK *bsock)
538 return strerror(bsock->b_errno);
542 * Format and send a message
543 * Returns: 0 on failure
547 bnet_fsend(BSOCK *bs, char *fmt, ...)
552 /* This probably won't work, but we vsnprintf, then if we
553 * get a negative length or a length greater than our buffer
554 * (depending on which library is used), the printf was truncated, so
555 * get a biger buffer and try again.
558 maxlen = sizeof_pool_memory(bs->msg) - 1;
559 va_start(arg_ptr, fmt);
560 bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
562 if (bs->msglen < 0 || bs->msglen >= maxlen) {
563 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
566 return bnet_send(bs) < 0 ? 0 : 1;
570 * Set the network buffer size, suggested size is in size.
571 * Actual size obtained is returned in bs->msglen
573 * Returns: 0 on failure
576 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
579 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
582 opt = IPTOS_THROUGHPUT;
583 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
587 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
588 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
591 if (rw & BNET_SETBUF_READ) {
592 while ((dbuf_size > TAPE_BSIZE) &&
593 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
594 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
595 dbuf_size -= TAPE_BSIZE;
597 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
598 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
599 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
600 if (dbuf_size % TAPE_BSIZE != 0) {
601 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
606 if (rw & BNET_SETBUF_WRITE) {
607 while ((dbuf_size > TAPE_BSIZE) &&
608 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
609 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
610 dbuf_size -= TAPE_BSIZE;
612 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
613 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
614 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
615 if (dbuf_size % TAPE_BSIZE != 0) {
616 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
621 bs->msglen = dbuf_size;
626 * Send a network "signal" to the other end
627 * This consists of sending a negative packet length
629 * Returns: 0 on failure
632 int bnet_sig(BSOCK *bs, int sig)
635 return bnet_send(bs);
639 * Convert a network "signal" code into
640 * human readable ASCII.
642 char *bnet_sig_to_ascii(BSOCK *bs)
645 switch (bs->msglen) {
647 return "BNET_EOD"; /* end of data stream */
649 return "BNET_EOD_POLL";
651 return "BNET_STATUS";
653 return "BNET_TERMINATE"; /* terminate connection */
657 return "BNET_HEARTBEAT";
658 case BNET_HB_RESPONSE:
659 return "BNET_HB_RESPONSE";
661 return "BNET_PROMPT";
663 sprintf(buf, "Unknown sig %d", bs->msglen);
669 /* Initialize internal socket structure.
670 * This probably should be done in net_open
673 init_bsock(void *jcr, int sockfd, char *who, char *host, int port)
675 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
676 memset(bsock, 0, sizeof(BSOCK));
679 bsock->msg = get_pool_memory(PM_MESSAGE);
680 bsock->errmsg = get_pool_memory(PM_MESSAGE);
681 bsock->who = bstrdup(who);
682 bsock->host = bstrdup(host);
685 * ****FIXME**** reduce this to a few hours once
686 * heartbeats are implemented
688 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
694 dup_bsock(BSOCK *osock)
696 BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
697 memcpy(bsock, osock, sizeof(BSOCK));
698 bsock->msg = get_pool_memory(PM_MESSAGE);
699 bsock->errmsg = get_pool_memory(PM_MESSAGE);
704 /* Close the network connection */
706 bnet_close(BSOCK *bsock)
710 for ( ; bsock != NULL; bsock = next) {
713 // shutdown(bsock->fd, SHUT_RDWR);
724 term_bsock(BSOCK *bsock)
727 free_pool_memory(bsock->msg);
730 ASSERT(1==0); /* double close */
733 free_pool_memory(bsock->errmsg);
734 bsock->errmsg = NULL;