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 program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of
17 the License, or (at your option) any later version.
19 This program 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 General Public License for more details.
24 You should have received a copy of the GNU General Public
25 License along with this program; 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)
119 if (bsock->errors || bsock->terminated) {
123 bsock->read_seqno++; /* bump sequence number */
124 bsock->timer_start = watchdog_time; /* set start wait time */
125 bsock->timed_out = 0;
126 /* get data size -- in int32_t */
127 if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
128 bsock->timer_start = 0; /* clear timer */
129 /* probably pipe broken because client died */
131 bsock->b_errno = ENODATA;
133 bsock->b_errno = errno;
136 return -1; /* assume hard EOF received */
138 bsock->timer_start = 0; /* clear timer */
139 if (nbytes != sizeof(int32_t)) {
141 bsock->b_errno = EIO;
142 Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t),
147 pktsiz = ntohl(pktsiz); /* decode no. of bytes that follow */
149 /* If signal or packet size too big */
150 if (pktsiz <= 0 || pktsiz > 10000000) {
151 if (pktsiz == BNET_TERMINATE) {
152 bsock->terminated = 1;
154 bsock->b_errno = ENODATA;
155 bsock->msglen = pktsiz; /* return size */
156 return 0; /* soft EOF */
159 /* Make sure the buffer is big enough + one byte for EOS */
160 if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
161 bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
164 bsock->timer_start = watchdog_time; /* set start wait time */
165 bsock->timed_out = 0;
166 /* now read the actual data */
167 if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <= 0) {
168 bsock->timer_start = 0; /* clear timer */
170 bsock->b_errno = ENODATA;
172 bsock->b_errno = errno;
175 Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
176 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
179 bsock->timer_start = 0; /* clear timer */
181 bsock->msglen = nbytes;
182 if (nbytes != pktsiz) {
183 bsock->b_errno = EIO;
185 Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
186 bsock->who, bsock->host, bsock->port);
189 /* always add a zero by to properly terminate any
190 * string that was send to us. Note, we ensured above that the
191 * buffer is at least one byte longer than the message length.
193 bsock->msg[nbytes] = 0; /* terminate in case it is a string */
194 sm_check(__FILE__, __LINE__, False);
195 return nbytes; /* return actual length of message */
198 int bnet_despool(BSOCK *bsock)
203 rewind(bsock->spool_fd);
204 while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
205 bsock->msglen = ntohl(pktsiz);
206 if (bsock->msglen > 0) {
207 if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
208 bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen);
210 nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
211 if (nbytes != (size_t)bsock->msglen) {
212 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
213 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
219 if (ferror(bsock->spool_fd)) {
220 Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno));
227 * Send a message over the network. The send consists of
228 * two network packets. The first is sends a 32 bit integer containing
229 * the length of the data packet which follows.
231 * Returns: 0 on failure
235 bnet_send(BSOCK *bsock)
240 if (bsock->errors || bsock->terminated) {
243 pktsiz = htonl((int32_t)bsock->msglen);
244 /* send int32_t containing size of data packet */
245 bsock->timer_start = watchdog_time; /* start timer */
246 bsock->timed_out = 0;
247 rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
248 bsock->timer_start = 0; /* clear timer */
249 if (rc != sizeof(int32_t)) {
252 bsock->b_errno = EIO;
254 bsock->b_errno = errno;
257 Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"),
258 bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
260 Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
261 bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
266 bsock->out_msg_no++; /* increment message number */
267 if (bsock->msglen <= 0) { /* length only? */
268 return 1; /* yes, no data */
271 /* send data packet */
272 bsock->timer_start = watchdog_time; /* start timer */
273 bsock->timed_out = 0;
274 rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
275 bsock->timer_start = 0; /* clear timer */
276 if (rc != bsock->msglen) {
279 bsock->b_errno = EIO;
281 bsock->b_errno = errno;
284 /************FIXME********* use Pmsg() **/
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 Pmsg2(0, "gethostbyname() for %s failed: ERR=%s\n", host, strerror(errno));
354 if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
355 Jmsg2(jcr, M_WARNING, 0, _("gethostbyname() network address length error.\n\
356 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
360 for (p = hp->h_addr_list; *p != 0; p++) {
364 addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
366 for (p = hp->h_addr_list; *p != 0; p++) {
367 addr_list[i++] = (*(struct in_addr **)p)->s_addr;
369 addr_list[i] = (uint32_t) -1;
375 * Open a TCP connection to the UPS network server
377 * Returns BSOCK * pointer on success
379 * ***FIXME*** implement service from /etc/services
382 bnet_open(void *jcr, char *name, char *host, char *service, int port)
385 struct sockaddr_in tcp_serv_addr; /* socket information */
387 int i, connected = 0;
391 * Fill in the structure serv_addr with the address of
392 * the server that we want to connect with.
394 memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr));
395 tcp_serv_addr.sin_family = AF_INET;
396 tcp_serv_addr.sin_port = htons(port);
398 if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
402 /* Open a TCP socket */
403 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
409 * Receive notification when connection dies.
411 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
412 Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
415 for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
416 /* connect to server */
417 tcp_serv_addr.sin_addr.s_addr = addr_list[i];
418 if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
430 return init_bsock(jcr, sockfd, name, host, port);
434 * Try to connect to host for max_retry_time at retry_time intervals.
437 bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
438 char *host, char *service, int port, int verbose)
443 for (i=0; (bsock = bnet_open(jcr, name, host, service, port)) == NULL; i -= retry_interval) {
444 Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
445 name, host, port, strerror(errno));
447 i = 60 * 5; /* complain again in 5 minutes */
449 Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
450 Retrying ...\n", name, host, port, strerror(errno));
452 sleep(retry_interval);
453 max_retry_time -= retry_interval;
454 if (max_retry_time <= 0) {
455 Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
456 name, host, port, strerror(errno));
465 * Return the string for the error that occurred
466 * on the socket. Only the first error is retained.
468 char *bnet_strerror(BSOCK *bsock)
470 /* ***FIXME*** not thread safe */
471 return strerror(bsock->b_errno);
475 * Format and send a message
476 * Returns: 0 on failure
480 bnet_fsend(BSOCK *bs, char *fmt, ...)
485 /* This probably won't work, but we vsnprintf, then if we
486 * get a negative length or a length greater than our buffer
487 * (depending on which library is used), the printf was truncated, so
488 * get a biger buffer and try again.
491 maxlen = sizeof_pool_memory(bs->msg) - 1;
492 va_start(arg_ptr, fmt);
493 bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
495 if (bs->msglen < 0 || bs->msglen >= maxlen) {
496 bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
499 return bnet_send(bs) < 0 ? 0 : 1;
503 * Set the network buffer size, suggested size is in size.
504 * Actual size obtained is returned in bs->msglen
506 * Returns: 0 on failure
509 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
512 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
515 opt = IPTOS_THROUGHPUT;
516 setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
520 if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
521 Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc 32K BSOCK data buffer\n"));
524 if (rw & BNET_SETBUF_READ) {
525 while ((dbuf_size > TAPE_BSIZE) &&
526 (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
527 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
528 dbuf_size -= TAPE_BSIZE;
530 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
531 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
532 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
533 if (dbuf_size % TAPE_BSIZE != 0) {
534 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
539 if (rw & BNET_SETBUF_WRITE) {
540 while ((dbuf_size > TAPE_BSIZE) &&
541 (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
542 Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
543 dbuf_size -= TAPE_BSIZE;
545 Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
546 if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
547 Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
548 if (dbuf_size % TAPE_BSIZE != 0) {
549 Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
554 bs->msglen = dbuf_size;
559 * Send a network "signal" to the other end
560 * This consists of sending a negative packet length
562 * Returns: 0 on failure
565 int bnet_sig(BSOCK *bs, int sig)
568 return bnet_send(bs);
572 * Convert a network "signal" code into
573 * human readable ASCII.
575 char *bnet_sig_to_ascii(BSOCK *bs)
578 switch (bs->msglen) {
579 case BNET_NONO: /* for compatibility */
581 return "BNET_EOD"; /* end of data stream */
583 return "BNET_EOD_POLL";
585 return "BNET_STATUS";
587 return "BNET_TERMINATE"; /* terminate connection */
591 return "BNET_HEARTBEAT";
592 case BNET_HB_RESPONSE:
593 return "BNET_HB_RESPONSE";
595 return "BNET_PROMPT";
597 sprintf(buf, "Unknown sig %d", bs->msglen);
603 /* Initialize internal socket structure.
604 * This probably should be done in net_open
607 init_bsock(void *jcr, int sockfd, char *who, char *host, int port)
609 BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
610 memset(bsock, 0, sizeof(BSOCK));
613 bsock->msg = get_pool_memory(PM_MESSAGE);
614 bsock->errmsg = get_pool_memory(PM_MESSAGE);
615 bsock->who = bstrdup(who);
616 bsock->host = bstrdup(host);
619 * ****FIXME**** reduce this to a few hours once
620 * heartbeats are implemented
622 bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
628 dup_bsock(BSOCK *osock)
630 BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
631 memcpy(bsock, osock, sizeof(BSOCK));
632 bsock->msg = get_pool_memory(PM_MESSAGE);
633 bsock->errmsg = get_pool_memory(PM_MESSAGE);
638 /* Close the network connection */
640 bnet_close(BSOCK *bsock)
644 for ( ; bsock != NULL; bsock = next) {
647 // shutdown(bsock->fd, SHUT_RDWR);
658 term_bsock(BSOCK *bsock)
661 free_pool_memory(bsock->msg);
664 ASSERT(1==0); /* double close */
667 free_pool_memory(bsock->errmsg);
668 bsock->errmsg = NULL;