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,
34 extern time_t watchdog_time;
37 #define INADDR_NONE -1
40 #ifndef ENODATA /* not defined on BSD systems */
46 * Read a nbytes from the network.
47 * It is possible that the total bytes require in several
51 static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
59 nread = read(bsock->fd, ptr, nleft);
60 } while (!bsock->timed_out && nread == -1 && (errno == EINTR || errno == EAGAIN));
62 return nread; /* error, or EOF */
67 return nbytes - nleft; /* return >= 0 */
71 * Write nbytes to the network.
72 * It may require several writes.
75 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
77 int32_t nleft, nwritten;
80 nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
81 if (nwritten != nbytes) {
82 Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno));
83 Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
92 nwritten = write(bsock->fd, ptr, nleft);
93 } while (!bsock->timed_out && nwritten == -1 && (errno == EINTR || errno == EAGAIN));
95 return nwritten; /* error */
104 * Receive a message from the other end. Each message consists of
105 * two packets. The first is a header that contains the size
106 * of the data that follows in the second packet.
107 * Returns number of bytes read (may return zero)
108 * Returns -1 on signal (BNET_SIGNAL)
109 * Returns -2 on hard end of file (BNET_HARDEOF)
110 * Returns -3 on error (BNET_ERROR)
112 * Unfortunately, it is a bit complicated because we have these
115 * 2. Signal including end of data stream
116 * 3. Hard end of file
118 * Using is_bnet_stop() and is_bnet_error() you can figure this all out.
120 int32_t bnet_recv(BSOCK *bsock)
126 if (bsock->errors || bsock->terminated) {
130 bsock->read_seqno++; /* bump sequence number */
131 bsock->timer_start = watchdog_time; /* set start wait time */
132 bsock->timed_out = 0;
133 /* get data size -- in int32_t */
134 if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
135 bsock->timer_start = 0; /* clear timer */
136 /* probably pipe broken because client died */
138 bsock->b_errno = ENODATA;
140 bsock->b_errno = errno;
143 return BNET_HARDEOF; /* assume hard EOF received */
145 bsock->timer_start = 0; /* clear timer */
146 if (nbytes != sizeof(int32_t)) {
148 bsock->b_errno = EIO;
149 Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
154 pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
156 if (pktsiz == 0) { /* No data transferred */
157 bsock->timer_start = 0; /* clear timer */
160 return 0; /* zero bytes read */
163 /* If signal or packet size too big */
164 if (pktsiz < 0 || pktsiz > 10000000) {
165 if (pktsiz == BNET_TERMINATE) {
166 bsock->terminated = 1;
168 bsock->timer_start = 0; /* clear timer */
169 bsock->b_errno = ENODATA;
170 bsock->msglen = pktsiz; /* signal code */
171 return BNET_SIGNAL; /* signal */
174 /* Make sure the buffer is big enough + one byte for EOS */
175 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
176 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
179 bsock->timer_start = watchdog_time; /* set start wait time */
180 bsock->timed_out = 0;
181 /* now read the actual data */
182 if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <= 0) {
183 bsock->timer_start = 0; /* clear timer */
185 bsock->b_errno = ENODATA;
187 bsock->b_errno = errno;
190 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
191 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
194 bsock->timer_start = 0; /* clear timer */
196 bsock->msglen = nbytes;
197 if (nbytes != pktsiz) {
198 bsock->b_errno = EIO;
200 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
201 bsock->who, bsock->host, bsock->port);
204 /* always add a zero by to properly terminate any
205 * string that was send to us. Note, we ensured above that the
206 * buffer is at least one byte longer than the message length.
208 bsock->msg[nbytes] = 0; /* terminate in case it is a string */
209 sm_check(__FILE__, __LINE__, False);
210 return nbytes; /* return actual length of message */
215 * Return 1 if there are errors on this bsock or it is closed,
216 * i.e. stop communicating on this line.
218 int is_bnet_stop(BSOCK *bsock)
220 return bsock->errors || bsock->terminated;
224 * Return number of errors on socket
226 int is_bnet_error(BSOCK *bsock)
228 return bsock->errors;
231 int bnet_despool(BSOCK *bsock)
236 rewind(bsock->spool_fd);
237 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
238 bsock->msglen = ntohl(pktsiz);
239 if (bsock->msglen > 0) {
240 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
241 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
243 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
244 if (nbytes != (size_t)bsock->msglen) {
245 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
246 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
252 if (ferror(bsock->spool_fd)) {
253 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
261 * Send a message over the network. The send consists of
262 * two network packets. The first is sends a 32 bit integer containing
263 * the length of the data packet which follows.
265 * Returns: 0 on failure
269 bnet_send(BSOCK *bsock)
274 if (bsock->errors || bsock->terminated) {
277 pktsiz = htonl((int32_t)bsock->msglen);
278 /* send int32_t containing size of data packet */
279 bsock->timer_start = watchdog_time; /* start timer */
280 bsock->timed_out = 0;
281 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
282 bsock->timer_start = 0; /* clear timer */
283 if (rc != sizeof(int32_t)) {
286 bsock->b_errno = EIO;
288 bsock->b_errno = errno;
291 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
292 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
294 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
295 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
300 bsock->out_msg_no++; /* increment message number */
301 if (bsock->msglen <= 0) { /* length only? */
302 return 1; /* yes, no data */
305 /* send data packet */
306 bsock->timer_start = watchdog_time; /* start timer */
307 bsock->timed_out = 0;
308 rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
309 bsock->timer_start = 0; /* clear timer */
310 if (rc != bsock->msglen) {
313 bsock->b_errno = EIO;
315 bsock->b_errno = errno;
318 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
319 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
321 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
322 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
330 * Wait for a specified time for data to appear on
331 * the BSOCK connection.
333 * Returns: 1 if data available
338 bnet_wait_data(BSOCK *bsock, int sec)
344 FD_SET(bsock->fd, &fdset);
348 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
349 case 0: /* timeout */
353 bsock->b_errno = errno;
354 if (errno == EINTR || errno == EAGAIN) {
357 return -1; /* error return */
365 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
368 * Convert a hostname or dotted IP address into
369 * a s_addr. We handle only IPv4.
371 static uint32_t *bget_host_ip(void *jcr, char *host)
373 struct in_addr inaddr;
374 uint32_t *addr_list; /* this really should be struct in_addr */
379 if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
380 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
381 addr_list[0] = inaddr.s_addr;
382 addr_list[1] = (uint32_t) -1;
385 if ((hp = gethostbyname(host)) == NULL) {
386 Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n",
387 host, strerror(errno));
391 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
392 Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
393 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
398 for (p = hp->h_addr_list; *p != 0; p++) {
402 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
404 for (p = hp->h_addr_list; *p != 0; p++) {
405 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
407 addr_list[i] = (uint32_t) -1;
414 * Open a TCP connection to the UPS network server
416 * Returns BSOCK * pointer on success
418 * ***FIXME*** implement service from /etc/services
421 bnet_open(void *jcr, char *name, char *host, char *service, int port)
424 struct sockaddr_in tcp_serv_addr; /* socket information */
426 int i, connected = 0;
430 * Fill in the structure serv_addr with the address of
431 * the server that we want to connect with.
433 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
434 tcp_serv_addr.sin_family = AF_INET;
435 tcp_serv_addr.sin_port = htons(port);
437 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
441 /* Open a TCP socket */
442 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
448 * Receive notification when connection dies.
450 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
451 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
454 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
455 /* connect to server */
456 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
457 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
469 return init_bsock(jcr, sockfd, name, host, port);
473 * Try to connect to host for max_retry_time at retry_time intervals.
476 bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
477 char *host, char *service, int port, int verbose)
482 for (i=0; (bsock = bnet_open(jcr, name, host, service, port)) == NULL; i -= retry_interval) {
483 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
484 name, host, port, strerror(errno));
486 i = 60 * 5; /* complain again in 5 minutes */
488 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
489 Retrying ...\n", name, host, port, strerror(errno));
491 sleep(retry_interval);
492 max_retry_time -= retry_interval;
493 if (max_retry_time <= 0) {
494 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
495 name, host, port, strerror(errno));
504 * Return the string for the error that occurred
505 * on the socket. Only the first error is retained.
507 char *bnet_strerror(BSOCK *bsock)
509 return strerror(bsock->b_errno);
513 * Format and send a message
514 * Returns: 0 on failure
518 bnet_fsend(BSOCK *bs, char *fmt, ...)
523 /* This probably won't work, but we vsnprintf, then if we
524 * get a negative length or a length greater than our buffer
525 * (depending on which library is used), the printf was truncated, so
526 * get a biger buffer and try again.
529 maxlen = sizeof_pool_memory(bs->msg) - 1;
530 va_start(arg_ptr, fmt);
531 bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
533 if (bs->msglen < 0 || bs->msglen >= maxlen) {
534 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
537 return bnet_send(bs) < 0 ? 0 : 1;
541 * Set the network buffer size, suggested size is in size.
542 * Actual size obtained is returned in bs->msglen
544 * Returns: 0 on failure
547 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
550 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
553 opt = IPTOS_THROUGHPUT;
554 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
558 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
559 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
562 if (rw & BNET_SETBUF_READ) {
563 while ((dbuf_size > TAPE_BSIZE) &&
564 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
565 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
566 dbuf_size -= TAPE_BSIZE;
568 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
569 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
570 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
571 if (dbuf_size % TAPE_BSIZE != 0) {
572 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
577 if (rw & BNET_SETBUF_WRITE) {
578 while ((dbuf_size > TAPE_BSIZE) &&
579 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
580 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
581 dbuf_size -= TAPE_BSIZE;
583 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
584 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
585 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
586 if (dbuf_size % TAPE_BSIZE != 0) {
587 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
592 bs->msglen = dbuf_size;
597 * Send a network "signal" to the other end
598 * This consists of sending a negative packet length
600 * Returns: 0 on failure
603 int bnet_sig(BSOCK *bs, int sig)
606 return bnet_send(bs);
610 * Convert a network "signal" code into
611 * human readable ASCII.
613 char *bnet_sig_to_ascii(BSOCK *bs)
616 switch (bs->msglen) {
618 return "BNET_EOD"; /* end of data stream */
620 return "BNET_EOD_POLL";
622 return "BNET_STATUS";
624 return "BNET_TERMINATE"; /* terminate connection */
628 return "BNET_HEARTBEAT";
629 case BNET_HB_RESPONSE:
630 return "BNET_HB_RESPONSE";
632 return "BNET_PROMPT";
634 sprintf(buf, "Unknown sig %d", bs->msglen);
640 /* Initialize internal socket structure.
641 * This probably should be done in net_open
644 init_bsock(void *jcr, int sockfd, char *who, char *host, int port)
646 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
647 memset(bsock, 0, sizeof(BSOCK));
650 bsock->msg = get_pool_memory(PM_MESSAGE);
651 bsock->errmsg = get_pool_memory(PM_MESSAGE);
652 bsock->who = bstrdup(who);
653 bsock->host = bstrdup(host);
656 * ****FIXME**** reduce this to a few hours once
657 * heartbeats are implemented
659 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
665 dup_bsock(BSOCK *osock)
667 BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
668 memcpy(bsock, osock, sizeof(BSOCK));
669 bsock->msg = get_pool_memory(PM_MESSAGE);
670 bsock->errmsg = get_pool_memory(PM_MESSAGE);
675 /* Close the network connection */
677 bnet_close(BSOCK *bsock)
681 for ( ; bsock != NULL; bsock = next) {
684 // shutdown(bsock->fd, SHUT_RDWR);
695 term_bsock(BSOCK *bsock)
698 free_pool_memory(bsock->msg);
701 ASSERT(1==0); /* double close */
704 free_pool_memory(bsock->errmsg);
705 bsock->errmsg = NULL;