]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet.c
First cut 1.23 -- kes07Jul02
[bacula/bacula] / bacula / src / lib / bnet.c
1 /*
2  * Network Utility Routines
3  *
4  *  by Kern Sibbald
5  *
6  * Adapted and enhanced for Bacula, originally written 
7  * for inclusion in the Apcupsd package
8  *
9  *   Version $Id$
10  */
11 /*
12    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
13
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.
18
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.
23
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,
27    MA 02111-1307, USA.
28
29  */
30
31
32 #include "bacula.h"
33
34 extern time_t watchdog_time;
35
36 #ifndef   INADDR_NONE
37 #define   INADDR_NONE    -1
38 #endif
39
40 #ifndef ENODATA                       /* not defined on BSD systems */
41 #define ENODATA EPIPE
42 #endif
43
44
45 /*
46  * Read a nbytes from the network.
47  * It is possible that the total bytes require in several
48  * read requests
49  */
50
51 static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
52 {
53    int32_t nleft, nread;
54       
55    nleft = nbytes;
56    while (nleft > 0) {
57       do {
58          errno = 0;
59          nread = read(bsock->fd, ptr, nleft);    
60       } while (!bsock->timed_out && nread == -1 && (errno == EINTR || errno == EAGAIN));
61       if (nread <= 0) {
62          return nread;               /* error, or EOF */
63       }
64       nleft -= nread;
65       ptr += nread;
66    }
67    return nbytes - nleft;            /* return >= 0 */
68 }
69
70 /*
71  * Write nbytes to the network.
72  * It may require several writes.
73  */
74
75 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
76 {
77    int32_t nleft, nwritten;
78
79    nleft = nbytes;
80    while (nleft > 0) {
81       do {
82          errno = 0;
83          nwritten = write(bsock->fd, ptr, nleft);
84       } while (!bsock->timed_out && nwritten == -1 && (errno == EINTR || errno == EAGAIN));
85       if (nwritten <= 0) {
86          return nwritten;            /* error */
87       }
88       nleft -= nwritten;
89       ptr += nwritten;
90    }
91    return nbytes-nleft;
92 }
93
94 /* 
95  * Receive a message from the other end. Each message consists of
96  * two packets. The first is a header that contains the size
97  * of the data that follows in the second packet.
98  * Returns number of bytes read
99  * Returns 0 on end of file
100  * Returns -1 on hard end of file (i.e. network connection close)
101  * Returns -2 on error
102  */
103 /* EXTPROTO */
104 int32_t 
105 bnet_recv(BSOCK *bsock)
106 {
107    int32_t nbytes;
108    int32_t pktsiz;
109
110    if (bsock->errors) {
111       return -2;
112    }
113
114    bsock->read_seqno++;               /* bump sequence number */
115    bsock->timer_start = watchdog_time;  /* set start wait time */
116    bsock->timed_out = 0;
117    /* get data size -- in int32_t */
118    if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
119       bsock->timer_start = 0;         /* clear timer */
120       /* probably pipe broken because client died */
121       if (errno == 0) {
122          bsock->b_errno = ENODATA;
123       } else {
124          bsock->b_errno = errno;
125       }
126       bsock->errors++;
127       return -1;                      /* assume hard EOF received */
128    }
129    bsock->timer_start = 0;            /* clear timer */
130    if (nbytes != sizeof(int32_t)) {
131       bsock->errors++;
132       bsock->b_errno = EIO;
133       Emsg3(M_ERROR, 0, "Read %d expected %d from %s\n", nbytes, sizeof(int32_t),
134             bsock->who);
135       return -2;
136    }
137
138    pktsiz = ntohl(pktsiz);            /* decode no. of bytes that follow */
139
140    if (pktsiz <= 0) {
141       bsock->b_errno = ENODATA;
142       bsock->msglen = pktsiz;         /* return size */
143       return 0;                       /* soft EOF */
144    }
145    /* For big packet size, something went wrong */
146    if (pktsiz > 10000000) {
147       bsock->b_errno = ENODATA;
148       bsock->msglen = pktsiz;         /* return size */
149       return 0;                       /* soft EOF */
150    }
151
152    /* Make sure the buffer is big enough + one byte for EOS */
153    if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
154       bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
155    }
156
157    bsock->timer_start = watchdog_time;  /* set start wait time */
158    bsock->timed_out = 0;
159    /* now read the actual data */
160    if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <=  0) {
161       bsock->timer_start = 0;         /* clear timer */
162       if (errno == 0) {
163          bsock->b_errno = ENODATA;
164       } else {
165          bsock->b_errno = errno;
166       }
167       bsock->errors++;
168       Emsg4(M_ERROR, 0, "Read error from %s:%s:%d: ERR=%s\n", 
169             bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
170       return -2;
171    }
172    bsock->timer_start = 0;            /* clear timer */
173    bsock->in_msg_no++;
174    bsock->msglen = nbytes;
175    if (nbytes != pktsiz) {
176       bsock->b_errno = EIO;
177       bsock->errors++;
178       Emsg5(M_ERROR, 0, "Read expected %d got %d from %s:%s:%d\n", pktsiz, nbytes,
179             bsock->who, bsock->host, bsock->port);
180       return -2;
181    }
182    /* always add a zero by to properly terminate any
183     * string that was send to us. Note, we ensured above that the
184     * buffer is at least one byte longer than the message length.
185     */
186    bsock->msg[nbytes] = 0;            /* terminate in case it is a string */
187    sm_check(__FILE__, __LINE__, False);
188    return nbytes;                     /* return actual length of message */
189 }
190
191 /*
192  * Send a message over the network. The send consists of
193  * two network packets. The first is sends a 32 bit integer containing
194  * the length of the data packet which follows.
195  *
196  * Returns: 0 on failure
197  *          1 on success
198  */
199 int
200 bnet_send(BSOCK *bsock)
201 {
202    int32_t rc;
203    int32_t pktsiz;
204
205    if (bsock->errors) {
206       return 0;
207    }
208    pktsiz = htonl((int32_t)bsock->msglen);
209    /* send int32_t containing size of data packet */
210    bsock->timer_start = watchdog_time; /* start timer */
211    bsock->timed_out = 0;               
212    rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
213    bsock->timer_start = 0;            /* clear timer */
214    if (rc != sizeof(int32_t)) {
215       bsock->errors++;
216       if (errno == 0) {
217          bsock->b_errno = EIO;
218       } else {
219          bsock->b_errno = errno;
220       }
221       if (rc < 0) {
222          /****FIXME***** use Mmsg */
223          Emsg4(M_ERROR, 0, "Write error sending to %s:%s:%d: ERR=%s\n", 
224                bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
225       } else {
226          Emsg5(M_ERROR, 0, "Wrote %d bytes to %s:%s:%d, but only %d accepted.\n", 
227                bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
228       }
229       return 0;
230    }
231
232    bsock->out_msg_no++;               /* increment message number */
233    if (bsock->msglen <= 0) {          /* length only? */
234       return 1;                       /* yes, no data */
235    }
236
237    /* send data packet */
238    bsock->timer_start = watchdog_time; /* start timer */
239    bsock->timed_out = 0;               
240    rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
241    bsock->timer_start = 0;            /* clear timer */
242    if (rc != bsock->msglen) {
243       bsock->errors++;
244       if (errno == 0) {
245          bsock->b_errno = EIO;
246       } else {
247          bsock->b_errno = errno;
248       }
249       if (rc < 0) {
250          /************FIXME********* use Pmsg() **/
251          Emsg4(M_ERROR, 0, "Write error sending to %s:%s:%d: ERR=%s\n", 
252                bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
253       } else {
254          Emsg5(M_ERROR, 0, "Wrote %d bytes to %s:%s:%d, but only %d accepted.\n", 
255                bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
256       }
257       return 0;
258    }
259    return 1;
260 }
261
262 /*
263  * Wait for a specified time for data to appear on
264  * the BSOCK connection.
265  *
266  *   Returns: 1 if data available
267  *            0 if timeout
268  *           -1 if error
269  */
270 int 
271 bnet_wait_data(BSOCK *bsock, int sec)
272 {
273    fd_set fdset;
274    struct timeval tv;
275
276    FD_ZERO(&fdset);
277    FD_SET(bsock->fd, &fdset);
278    tv.tv_sec = sec;
279    tv.tv_usec = 0;
280    for ( ;; ) {
281       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
282          case 0:                         /* timeout */
283             bsock->b_errno = 0;
284             return 0;
285          case -1:
286             bsock->b_errno = errno;
287             if (errno == EINTR || errno == EAGAIN) {
288                continue;
289             }
290             return -1;                  /* error return */
291          default:
292             bsock->b_errno = 0;
293             return 1;
294       }
295    }
296 }
297
298 /*
299  * Convert a hostname or dotted IP address into   
300  * a s_addr.  We handle only IPv4.
301  */
302 static uint32_t *bget_host_ip(char *host)
303 {
304    struct in_addr inaddr;
305    uint32_t *addr_list;               /* this really should be struct in_addr */
306    struct hostent *hp;
307    char **p;
308    int i;
309
310    if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
311       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
312       addr_list[0] = inaddr.s_addr;
313       addr_list[1] = (uint32_t) -1;
314    } else {
315       /******FIXME***** use gethostbyname_r or mutex ****/
316       if ((hp = gethostbyname(host)) == NULL) {
317          Dmsg2(0, "gethostbyname() for %s failed: ERR=%s\n", host, strerror(errno));
318          return NULL;
319       }
320       if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
321           Emsg2(M_WARNING, 0, "gethostbyname() network address length error.\n\
322 Wanted %d got %d bytes for s_addr.\n", sizeof(inaddr.s_addr), hp->h_length);
323           return NULL;
324       }
325       i = 0;
326       for (p = hp->h_addr_list; *p != 0; p++) {
327          i++;
328       }
329       i++;
330       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
331       i = 0;
332       for (p = hp->h_addr_list; *p != 0; p++) {
333          addr_list[i++] = (*(struct in_addr **)p)->s_addr;
334       }
335       addr_list[i] = (uint32_t) -1;
336    }
337    return addr_list;
338 }
339
340 /*     
341  * Open a TCP connection to the UPS network server
342  * Returns NULL
343  * Returns BSOCK * pointer on success
344  *
345  *  ***FIXME*** implement service from /etc/services
346  */
347 static BSOCK *
348 bnet_open(char *name, char *host, char *service, int port)
349 {
350    int sockfd;
351    struct sockaddr_in tcp_serv_addr;     /* socket information */
352    uint32_t *addr_list;
353    int i, connected = 0;
354    int turnon = 1;
355
356    /* 
357     * Fill in the structure serv_addr with the address of
358     * the server that we want to connect with.
359     */
360    memset((char *)&tcp_serv_addr, 0,  sizeof(tcp_serv_addr));
361    tcp_serv_addr.sin_family = AF_INET;
362    tcp_serv_addr.sin_port = htons(port);
363
364    if ((addr_list=bget_host_ip(host)) == NULL) {
365      return NULL;
366    }
367
368    /* Open a TCP socket */
369    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
370       free(addr_list);
371       return NULL;
372    }
373
374    /*
375     * Receive notification when connection dies.
376     */
377    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
378       Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
379    }
380    
381    for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
382       /* connect to server */
383       tcp_serv_addr.sin_addr.s_addr = addr_list[i];
384       if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
385          continue;
386       }
387       connected = 1;
388       break;
389    }
390
391    free(addr_list);
392    if (!connected) {
393       close(sockfd);
394       return NULL;
395    }
396    return init_bsock(sockfd, name, host, port);
397 }
398
399 /*
400  * Try to connect to host for max_retry_time at retry_time intervals.
401  */
402 BSOCK *
403 bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
404              char *host, char *service, int port, int verbose)
405 {
406    int i;
407    BSOCK *bsock;
408
409    for (i=0; (bsock = bnet_open(name, host, service, port)) == NULL; i -= retry_interval) {
410      Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
411               name, host, port, strerror(errno));
412       if (i <= 0) {
413          i = 60 * 5;                  /* complain again in 5 minutes */
414          if (verbose)
415             Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
416 Retrying ...\n", name, host, port, strerror(errno));
417       }
418       sleep(retry_interval);
419       max_retry_time -= retry_interval;
420       if (max_retry_time <= 0) {
421          Jmsg(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
422               name, host, port, strerror(errno));
423          return NULL;
424       }
425    }
426    return bsock;
427 }
428
429
430 /*
431  * Return the string for the error that occurred
432  * on the socket. Only the first error is retained.
433  */
434 char *bnet_strerror(BSOCK *bsock)
435 {
436    /*  ***FIXME*** not thread safe */
437    return strerror(bsock->b_errno);
438 }
439
440 /*
441  * Format and send a message
442  *  Returns: 0 on failure
443  *           1 on success
444  */
445 int
446 bnet_fsend(BSOCK *bs, char *fmt, ...)
447 {
448    va_list arg_ptr;
449    int maxlen;
450
451    /* This probably won't work, but we vsnprintf, then if we
452     * get a negative length or a length greater than our buffer
453     * (depending on which library is used), the printf was truncated, so
454     * get a biger buffer and try again.
455     */
456 again:
457    maxlen = sizeof_pool_memory(bs->msg) - 1;
458    va_start(arg_ptr, fmt);
459    bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
460    va_end(arg_ptr);
461    if (bs->msglen < 0 || bs->msglen >= maxlen) {
462       bs->msg = realloc_pool_memory(bs->msg, maxlen + 200);
463       goto again;
464    }
465    return bnet_send(bs) < 0 ? 0 : 1;
466 }
467
468 /* 
469  * Set the network buffer size, suggested size is in size.
470  *  Actual size obtained is returned in bs->msglen
471  *
472  *  Returns: 0 on failure
473  *           1 on success
474  */
475 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
476 {
477    uint32_t dbuf_size;
478 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
479    int opt;
480
481     opt = IPTOS_THROUGHPUT;
482     setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
483 #endif
484
485    dbuf_size = size;
486    if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
487       Emsg0(M_FATAL, 0, "Could not malloc 32K BSOCK data buffer\n");
488       return 0;
489    }
490    if (rw & BNET_SETBUF_READ) {
491       while ((dbuf_size > TAPE_BSIZE) &&
492          (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
493          Emsg1(M_ERROR, 0, "sockopt error: %s\n", strerror(errno));
494          dbuf_size -= TAPE_BSIZE;
495       }
496       Dmsg1(20, "set network buffer size=%d\n", dbuf_size);
497       if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
498          Emsg1(M_WARNING, 0, "Warning network buffer = %d bytes not max size.\n", dbuf_size);
499       if (dbuf_size % TAPE_BSIZE != 0) {
500          Emsg1(M_ABORT, 0, "Network buffer size %d not multiple of tape block size.\n",
501               dbuf_size);
502       }
503    }
504    dbuf_size = size;
505    if (rw & BNET_SETBUF_WRITE) {
506       while ((dbuf_size > TAPE_BSIZE) &&
507          (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
508          Emsg1(M_ERROR, 0, "sockopt error: %s\n", strerror(errno));
509          dbuf_size -= TAPE_BSIZE;
510       }
511       Dmsg1(20, "set network buffer size=%d\n", dbuf_size);
512       if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
513          Emsg1(M_WARNING, 0, "Warning network buffer = %d bytes not max size.\n", dbuf_size);
514       if (dbuf_size % TAPE_BSIZE != 0) {
515          Emsg1(M_ABORT, 0, "Network buffer size %d not multiple of tape block size.\n",
516               dbuf_size);
517       }
518    }
519
520    bs->msglen = dbuf_size;
521    return 1;
522 }
523
524 /*
525  * Send a network "signal" to the other end 
526  *  This consists of sending a negative packet length
527  *
528  *  Returns: 0 on failure
529  *           1 on success
530  */
531 int bnet_sig(BSOCK *bs, int sig)
532 {
533    bs->msglen = sig;
534    return bnet_send(bs);
535 }
536
537 /*
538  * Convert a network "signal" code into
539  * human readable ASCII.
540  */
541 char *bnet_sig_to_ascii(BSOCK *bs)
542 {
543    static char buf[30];
544    switch (bs->msglen) {
545       case BNET_EOF:
546          return "BNET_EOF";
547       case BNET_EOD:
548          return "BNET_EOD";
549       case BNET_EOD_POLL:
550          return "BNET_EOD_POLL";
551       case BNET_STATUS:
552          return "BNET_STATUS";
553       case BNET_TERMINATE:
554          return "BNET_TERMINATE";
555       case BNET_POLL:
556          return "BNET_POLL";
557       case BNET_HEARTBEAT:
558          return "BNET_HEARTBEAT";
559       case BNET_HB_RESPONSE:
560          return "BNET_HB_RESPONSE";
561       case BNET_PROMPT:
562          return "BNET_PROMPT";
563       default:
564          sprintf(buf, "Unknown sig %d", bs->msglen);
565          return buf;
566    }
567 }
568
569
570 /* Initialize internal socket structure.  
571  *  This probably should be done in net_open
572  */
573 BSOCK *
574 init_bsock(int sockfd, char *who, char *host, int port) 
575 {
576    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
577    if (bsock == NULL) {
578       Emsg0(M_ABORT, 0, "Out of memory in init_bsock.\n");
579    }
580    memset(bsock, 0, sizeof(BSOCK));
581    bsock->fd = sockfd;
582    bsock->errors = 0;
583    bsock->msg = get_pool_memory(PM_MESSAGE);
584    bsock->errmsg = get_pool_memory(PM_MESSAGE);
585    bsock->who = bstrdup(who);
586    bsock->host = bstrdup(host);
587    bsock->port = port;
588    /*
589     * ****FIXME**** reduce this to a few hours once   
590     *   heartbeats are implemented
591     */
592    bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
593    return bsock;
594 }
595
596 BSOCK *
597 dup_bsock(BSOCK *osock)
598 {
599    BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
600    if (bsock == NULL) {
601       Emsg0(M_ABORT, 0, "Out of memory in dup_bsock.\n");
602    }
603    memcpy(bsock, osock, sizeof(BSOCK));
604    bsock->msg = get_pool_memory(PM_MESSAGE);
605    bsock->errmsg = get_pool_memory(PM_MESSAGE);
606    bsock->duped = TRUE;
607    return bsock;
608 }
609
610 /* Close the network connection */
611 void 
612 bnet_close(BSOCK *bsock)
613 {
614    BSOCK *next;
615
616    for ( ; bsock != NULL; bsock = next) {
617       next = bsock->next;
618       if (!bsock->duped) {
619          shutdown(bsock->fd, SHUT_RDWR);
620          close(bsock->fd);
621          term_bsock(bsock);
622       } else {
623          free(bsock);
624       }
625    }
626    return;
627 }
628
629 void
630 term_bsock(BSOCK *bsock)
631 {
632    free_pool_memory(bsock->msg);
633    free_pool_memory(bsock->errmsg);
634    free(bsock->who);
635    free(bsock->host);
636    free(bsock);
637 }
638