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