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
108 * Returns 0 on end of file
109 * Returns -1 on hard end of file (i.e. network connection close)
110 * Returns -2 on error
114 bnet_recv(BSOCK *bsock)
120 if (bsock->errors || bsock->terminated) {
124 bsock->read_seqno++; /* bump sequence number */
125 bsock->timer_start = watchdog_time; /* set start wait time */
126 bsock->timed_out = 0;
127 /* get data size -- in int32_t */
128 if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
129 bsock->timer_start = 0; /* clear timer */
130 /* probably pipe broken because client died */
132 bsock->b_errno = ENODATA;
134 bsock->b_errno = errno;
137 return -1; /* assume hard EOF received */
139 bsock->timer_start = 0; /* clear timer */
140 if (nbytes != sizeof(int32_t)) {
142 bsock->b_errno = EIO;
143 Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
148 pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
150 /* If signal or packet size too big */
151 if (pktsiz <= 0 || pktsiz > 10000000) {
152 if (pktsiz == BNET_TERMINATE) {
153 bsock->terminated = 1;
155 bsock->b_errno = ENODATA;
156 bsock->msglen = pktsiz; /* return size */
157 return 0; /* soft EOF */
160 /* Make sure the buffer is big enough + one byte for EOS */
161 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
162 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
165 bsock->timer_start = watchdog_time; /* set start wait time */
166 bsock->timed_out = 0;
167 /* now read the actual data */
168 if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <= 0) {
169 bsock->timer_start = 0; /* clear timer */
171 bsock->b_errno = ENODATA;
173 bsock->b_errno = errno;
176 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
177 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
180 bsock->timer_start = 0; /* clear timer */
182 bsock->msglen = nbytes;
183 if (nbytes != pktsiz) {
184 bsock->b_errno = EIO;
186 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
187 bsock->who, bsock->host, bsock->port);
190 /* always add a zero by to properly terminate any
191 * string that was send to us. Note, we ensured above that the
192 * buffer is at least one byte longer than the message length.
194 bsock->msg[nbytes] = 0; /* terminate in case it is a string */
195 sm_check(__FILE__, __LINE__, False);
196 return nbytes; /* return actual length of message */
199 int bnet_despool(BSOCK *bsock)
204 rewind(bsock->spool_fd);
205 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
206 bsock->msglen = ntohl(pktsiz);
207 if (bsock->msglen > 0) {
208 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
209 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
211 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
212 if (nbytes != (size_t)bsock->msglen) {
213 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
214 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
220 if (ferror(bsock->spool_fd)) {
221 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
228 * Send a message over the network. The send consists of
229 * two network packets. The first is sends a 32 bit integer containing
230 * the length of the data packet which follows.
232 * Returns: 0 on failure
236 bnet_send(BSOCK *bsock)
241 if (bsock->errors || bsock->terminated) {
244 pktsiz = htonl((int32_t)bsock->msglen);
245 /* send int32_t containing size of data packet */
246 bsock->timer_start = watchdog_time; /* start timer */
247 bsock->timed_out = 0;
248 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
249 bsock->timer_start = 0; /* clear timer */
250 if (rc != sizeof(int32_t)) {
253 bsock->b_errno = EIO;
255 bsock->b_errno = errno;
258 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
259 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
261 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
262 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
267 bsock->out_msg_no++; /* increment message number */
268 if (bsock->msglen <= 0) { /* length only? */
269 return 1; /* yes, no data */
272 /* send data packet */
273 bsock->timer_start = watchdog_time; /* start timer */
274 bsock->timed_out = 0;
275 rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
276 bsock->timer_start = 0; /* clear timer */
277 if (rc != bsock->msglen) {
280 bsock->b_errno = EIO;
282 bsock->b_errno = errno;
285 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
286 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
288 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
289 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
297 * Wait for a specified time for data to appear on
298 * the BSOCK connection.
300 * Returns: 1 if data available
305 bnet_wait_data(BSOCK *bsock, int sec)
311 FD_SET(bsock->fd, &fdset);
315 switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
316 case 0: /* timeout */
320 bsock->b_errno = errno;
321 if (errno == EINTR || errno == EAGAIN) {
324 return -1; /* error return */
333 * Convert a hostname or dotted IP address into
334 * a s_addr. We handle only IPv4.
336 static uint32_t *bget_host_ip(void *jcr, char *host)
338 struct in_addr inaddr;
339 uint32_t *addr_list; /* this really should be struct in_addr */
344 if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
345 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
346 addr_list[0] = inaddr.s_addr;
347 addr_list[1] = (uint32_t) -1;
349 /******FIXME***** use gethostbyname_r or mutex ****/
350 if ((hp = gethostbyname(host)) == NULL) {
351 Jmsg2(jcr, M_ERROR, 0, "gethostbyname() for %s failed: ERR=%s\n",
352 host, strerror(errno));
355 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
356 Jmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
357 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
361 for (p = hp->h_addr_list; *p != 0; p++) {
365 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
367 for (p = hp->h_addr_list; *p != 0; p++) {
368 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
370 addr_list[i] = (uint32_t) -1;
376 * Open a TCP connection to the UPS network server
378 * Returns BSOCK * pointer on success
380 * ***FIXME*** implement service from /etc/services
383 bnet_open(void *jcr, char *name, char *host, char *service, int port)
386 struct sockaddr_in tcp_serv_addr; /* socket information */
388 int i, connected = 0;
392 * Fill in the structure serv_addr with the address of
393 * the server that we want to connect with.
395 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
396 tcp_serv_addr.sin_family = AF_INET;
397 tcp_serv_addr.sin_port = htons(port);
399 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
403 /* Open a TCP socket */
404 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
410 * Receive notification when connection dies.
412 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
413 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
416 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
417 /* connect to server */
418 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
419 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
431 return init_bsock(jcr, sockfd, name, host, port);
435 * Try to connect to host for max_retry_time at retry_time intervals.
438 bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
439 char *host, char *service, int port, int verbose)
444 for (i=0; (bsock = bnet_open(jcr, name, host, service, port)) == NULL; i -= retry_interval) {
445 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
446 name, host, port, strerror(errno));
448 i = 60 * 5; /* complain again in 5 minutes */
450 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
451 Retrying ...\n", name, host, port, strerror(errno));
453 sleep(retry_interval);
454 max_retry_time -= retry_interval;
455 if (max_retry_time <= 0) {
456 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
457 name, host, port, strerror(errno));
466 * Return the string for the error that occurred
467 * on the socket. Only the first error is retained.
469 char *bnet_strerror(BSOCK *bsock)
471 /* ***FIXME*** not thread safe */
472 return strerror(bsock->b_errno);
476 * Format and send a message
477 * Returns: 0 on failure
481 bnet_fsend(BSOCK *bs, char *fmt, ...)
486 /* This probably won't work, but we vsnprintf, then if we
487 * get a negative length or a length greater than our buffer
488 * (depending on which library is used), the printf was truncated, so
489 * get a biger buffer and try again.
492 maxlen = sizeof_pool_memory(bs->msg) - 1;
493 va_start(arg_ptr, fmt);
494 bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
496 if (bs->msglen < 0 || bs->msglen >= maxlen) {
497 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
500 return bnet_send(bs) < 0 ? 0 : 1;
504 * Set the network buffer size, suggested size is in size.
505 * Actual size obtained is returned in bs->msglen
507 * Returns: 0 on failure
510 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
513 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
516 opt = IPTOS_THROUGHPUT;
517 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
521 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
522 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc 32K BSOCK data buffer\n"));
525 if (rw & BNET_SETBUF_READ) {
526 while ((dbuf_size > TAPE_BSIZE) &&
527 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
528 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
529 dbuf_size -= TAPE_BSIZE;
531 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
532 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
533 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
534 if (dbuf_size % TAPE_BSIZE != 0) {
535 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
540 if (rw & BNET_SETBUF_WRITE) {
541 while ((dbuf_size > TAPE_BSIZE) &&
542 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
543 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
544 dbuf_size -= TAPE_BSIZE;
546 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
547 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
548 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
549 if (dbuf_size % TAPE_BSIZE != 0) {
550 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
555 bs->msglen = dbuf_size;
560 * Send a network "signal" to the other end
561 * This consists of sending a negative packet length
563 * Returns: 0 on failure
566 int bnet_sig(BSOCK *bs, int sig)
569 return bnet_send(bs);
573 * Convert a network "signal" code into
574 * human readable ASCII.
576 char *bnet_sig_to_ascii(BSOCK *bs)
579 switch (bs->msglen) {
580 case BNET_NONO: /* for compatibility */
582 return "BNET_EOD"; /* end of data stream */
584 return "BNET_EOD_POLL";
586 return "BNET_STATUS";
588 return "BNET_TERMINATE"; /* terminate connection */
592 return "BNET_HEARTBEAT";
593 case BNET_HB_RESPONSE:
594 return "BNET_HB_RESPONSE";
596 return "BNET_PROMPT";
598 sprintf(buf, "Unknown sig %d", bs->msglen);
604 /* Initialize internal socket structure.
605 * This probably should be done in net_open
608 init_bsock(void *jcr, int sockfd, char *who, char *host, int port)
610 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
611 memset(bsock, 0, sizeof(BSOCK));
614 bsock->msg = get_pool_memory(PM_MESSAGE);
615 bsock->errmsg = get_pool_memory(PM_MESSAGE);
616 bsock->who = bstrdup(who);
617 bsock->host = bstrdup(host);
620 * ****FIXME**** reduce this to a few hours once
621 * heartbeats are implemented
623 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
629 dup_bsock(BSOCK *osock)
631 BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
632 memcpy(bsock, osock, sizeof(BSOCK));
633 bsock->msg = get_pool_memory(PM_MESSAGE);
634 bsock->errmsg = get_pool_memory(PM_MESSAGE);
639 /* Close the network connection */
641 bnet_close(BSOCK *bsock)
645 for ( ; bsock != NULL; bsock = next) {
648 // shutdown(bsock->fd, SHUT_RDWR);
659 term_bsock(BSOCK *bsock)
662 free_pool_memory(bsock->msg);
665 ASSERT(1==0); /* double close */
668 free_pool_memory(bsock->errmsg);
669 bsock->errmsg = NULL;