]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bnet.c
Rewrite spool error cod + level keyword for estimate
[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-2004 Kern Sibbald and John Walker
13
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.
18
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.
23
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,
27    MA 02111-1307, USA.
28
29  */
30
31
32 #include "bacula.h"
33 #include "jcr.h"
34 #include <netdb.h>
35
36 extern time_t watchdog_time;
37
38 #ifndef   INADDR_NONE
39 #define   INADDR_NONE    -1
40 #endif
41
42 #ifndef ENODATA                       /* not defined on BSD systems */
43 #define ENODATA EPIPE
44 #endif
45
46 #ifdef HAVE_WIN32
47 #define socketRead(fd, buf, len)  recv(fd, buf, len, 0)
48 #define socketWrite(fd, buf, len) send(fd, buf, len, 0)
49 #define socketClose(fd)           closesocket(fd)
50 #else
51 #define socketRead(fd, buf, len)  read(fd, buf, len)
52 #define socketWrite(fd, buf, len) write(fd, buf, len)
53 #define socketClose(fd)           close(fd)
54 #endif
55
56
57 /*
58  * Read a nbytes from the network.
59  * It is possible that the total bytes require in several
60  * read requests
61  */
62
63 static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
64 {
65    int32_t nleft, nread;
66       
67    nleft = nbytes;
68    while (nleft > 0) {
69       do {
70          errno = 0;
71          nread = socketRead(bsock->fd, ptr, nleft);      
72          if (bsock->timed_out || bsock->terminated) {
73             return nread;
74          }
75       } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
76       if (nread <= 0) {
77          return nread;               /* error, or EOF */
78       }
79       nleft -= nread;
80       ptr += nread;
81    }
82    return nbytes - nleft;            /* return >= 0 */
83 }
84
85 /*
86  * Write nbytes to the network.
87  * It may require several writes.
88  */
89
90 static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
91 {
92    int32_t nleft, nwritten;
93
94    if (bsock->spool) {
95       nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd);
96       if (nwritten != nbytes) {
97          Qmsg1(bsock->jcr, M_FATAL, 0, _("Attr spool write error. ERR=%s\n"), strerror(errno));
98          Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes);
99          return -1;
100       }
101       return nbytes;
102    }
103    nleft = nbytes;
104    while (nleft > 0) {
105       do {
106          errno = 0;
107          nwritten = socketWrite(bsock->fd, ptr, nleft);
108          if (bsock->timed_out || bsock->terminated) {
109             return nwritten;
110          }
111       } while (nwritten == -1 && errno == EINTR);
112       /*
113        * If connection is non-blocking, we will get EAGAIN, so
114        * use select() to keep from consuming all the CPU
115        * and try again.
116        */
117       if (nwritten == -1 && errno == EAGAIN) {
118          fd_set fdset;
119          struct timeval tv;
120
121          FD_ZERO(&fdset);
122          FD_SET((unsigned)bsock->fd, &fdset);
123          tv.tv_sec = 10;
124          tv.tv_usec = 0;
125          select(bsock->fd + 1, NULL, &fdset, NULL, &tv);
126          continue;
127       }
128       if (nwritten <= 0) {
129          return nwritten;            /* error */
130       }
131       nleft -= nwritten;
132       ptr += nwritten;
133    }
134    return nbytes-nleft;
135 }
136
137 /* 
138  * Receive a message from the other end. Each message consists of
139  * two packets. The first is a header that contains the size
140  * of the data that follows in the second packet.
141  * Returns number of bytes read (may return zero)
142  * Returns -1 on signal (BNET_SIGNAL) 
143  * Returns -2 on hard end of file (BNET_HARDEOF)
144  * Returns -3 on error  (BNET_ERROR)
145  *
146  *  Unfortunately, it is a bit complicated because we have these
147  *    four return types:
148  *    1. Normal data
149  *    2. Signal including end of data stream
150  *    3. Hard end of file                 
151  *    4. Error
152  *  Using is_bnet_stop() and is_bnet_error() you can figure this all out.
153  */
154 int32_t bnet_recv(BSOCK *bsock)
155 {
156    int32_t nbytes;
157    int32_t pktsiz;
158
159    ASSERT(bsock != NULL);
160    mp_chr(bsock->msg)[0] = 0;
161    if (bsock->errors || bsock->terminated) {
162       return BNET_HARDEOF;
163    }
164
165    bsock->read_seqno++;               /* bump sequence number */
166    bsock->timer_start = watchdog_time;  /* set start wait time */
167    bsock->timed_out = 0;
168    /* get data size -- in int32_t */
169    if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
170       bsock->timer_start = 0;         /* clear timer */
171       /* probably pipe broken because client died */
172       if (errno == 0) {
173          bsock->b_errno = ENODATA;
174       } else {
175          bsock->b_errno = errno;
176       }
177       bsock->errors++;
178       return BNET_HARDEOF;            /* assume hard EOF received */
179    }
180    bsock->timer_start = 0;            /* clear timer */
181    if (nbytes != sizeof(int32_t)) {
182       bsock->errors++;
183       bsock->b_errno = EIO;
184       Qmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), 
185             sizeof(int32_t), nbytes, bsock->who, bsock->host, bsock->port);
186       return BNET_ERROR;
187    }
188
189    pktsiz = ntohl(pktsiz);            /* decode no. of bytes that follow */
190
191    if (pktsiz == 0) {                 /* No data transferred */
192       bsock->timer_start = 0;         /* clear timer */
193       bsock->in_msg_no++;
194       bsock->msglen = 0;
195       return 0;                       /* zero bytes read */
196    }
197
198    /* If signal or packet size too big */
199    if (pktsiz < 0 || pktsiz > 1000000) {
200       if (pktsiz > 0) {               /* if packet too big */
201          Qmsg3(bsock->jcr, M_FATAL, 0, 
202             _("Packet size too big from \"%s:%s:%d. Terminating connection.\n"),
203             bsock->who, bsock->host, bsock->port);
204          pktsiz = BNET_TERMINATE;     /* hang up */
205       }
206       if (pktsiz == BNET_TERMINATE) {
207          bsock->terminated = 1;
208       }
209       bsock->timer_start = 0;         /* clear timer */
210       bsock->b_errno = ENODATA;
211       bsock->msglen = pktsiz;         /* signal code */
212       return BNET_SIGNAL;             /* signal */
213    }
214
215    /* Make sure the buffer is big enough + one byte for EOS */
216    if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
217       bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100);
218    }
219
220    bsock->timer_start = watchdog_time;  /* set start wait time */
221    bsock->timed_out = 0;
222    /* now read the actual data */
223    if ((nbytes = read_nbytes(bsock, mp_chr(bsock->msg), pktsiz)) <=  0) {
224       bsock->timer_start = 0;         /* clear timer */
225       if (errno == 0) {
226          bsock->b_errno = ENODATA;
227       } else {
228          bsock->b_errno = errno;
229       }
230       bsock->errors++;
231       Qmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"), 
232             bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
233       return BNET_ERROR;
234    }
235    bsock->timer_start = 0;            /* clear timer */
236    bsock->in_msg_no++;
237    bsock->msglen = nbytes;
238    if (nbytes != pktsiz) {
239       bsock->b_errno = EIO;
240       bsock->errors++;
241       Qmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes,
242             bsock->who, bsock->host, bsock->port);
243       return BNET_ERROR;
244    }
245    /* always add a zero by to properly terminate any
246     * string that was send to us. Note, we ensured above that the
247     * buffer is at least one byte longer than the message length.
248     */
249    mp_chr(bsock->msg)[nbytes] = 0;    /* terminate in case it is a string */
250    sm_check(__FILE__, __LINE__, false);
251    return nbytes;                     /* return actual length of message */
252 }
253
254
255 /*
256  * Return 1 if there are errors on this bsock or it is closed,  
257  *   i.e. stop communicating on this line.
258  */
259 int is_bnet_stop(BSOCK *bsock) 
260 {
261    return bsock->errors || bsock->terminated;
262 }
263
264 /*
265  * Return number of errors on socket 
266  */
267 int is_bnet_error(BSOCK *bsock)
268 {
269    return bsock->errors;
270 }
271
272 /*
273  * Call here after error during closing to suppress error
274  *  messages which are due to the other end shutting down too.
275  */
276 void
277 bnet_suppress_error_messages(BSOCK *bsock, bool flag)
278 {      
279    bsock->suppress_error_msgs = flag;
280 }
281
282
283 /*
284  * Transmit spooled data now to a BSOCK
285  */
286 int bnet_despool_to_bsock(BSOCK *bsock, void update_attr_spool_size(ssize_t size), ssize_t tsize)
287 {
288    int32_t pktsiz;
289    size_t nbytes;
290    ssize_t last = 0, size = 0;
291    int count = 0;
292
293    rewind(bsock->spool_fd);
294    while (fread((char *)&pktsiz, 1, sizeof(int32_t), bsock->spool_fd) == sizeof(int32_t)) {
295       size += sizeof(int32_t);
296       bsock->msglen = ntohl(pktsiz);
297       if (bsock->msglen > 0) {
298          if (bsock->msglen > (int32_t)sizeof_pool_memory(bsock->msg)) {
299             bsock->msg = realloc_pool_memory(bsock->msg, bsock->msglen + 1);
300          }
301          nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd);
302          if (nbytes != (size_t)bsock->msglen) {
303             Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen);
304             Qmsg1(bsock->jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"), strerror(errno));
305             update_attr_spool_size(tsize-last);
306             return 0;
307          }
308          size += nbytes;
309          if ((++count & 0x3F) == 0) {
310             update_attr_spool_size(size-last);
311             last = size;
312          }
313       }
314       bnet_send(bsock);
315    }
316    update_attr_spool_size(tsize-last);
317    if (ferror(bsock->spool_fd)) {
318       Qmsg1(bsock->jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"), strerror(errno));
319       return 0;
320    }
321    return 1;
322 }
323
324
325 /*
326  * Send a message over the network. The send consists of
327  * two network packets. The first is sends a 32 bit integer containing
328  * the length of the data packet which follows.
329  *
330  * Returns: 0 on failure
331  *          1 on success
332  */
333 int
334 bnet_send(BSOCK *bsock)
335 {
336    int32_t rc;
337    int32_t pktsiz;
338    int32_t msglen;
339
340    if (bsock->errors || bsock->terminated || bsock->msglen > 1000000) {
341       return 0;
342    }
343    msglen = bsock->msglen;
344    pktsiz = htonl((int32_t)bsock->msglen);
345    /* send int32_t containing size of data packet */
346    bsock->timer_start = watchdog_time; /* start timer */
347    bsock->timed_out = 0;               
348    rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
349    bsock->timer_start = 0;            /* clear timer */
350    if (rc != sizeof(int32_t)) {
351       if (bsock->msglen == BNET_TERMINATE) { /* if we were terminating */
352          bsock->terminated = 1;
353          return 0;                    /* ignore any errors */
354       }
355       bsock->errors++;
356       if (errno == 0) {
357          bsock->b_errno = EIO;
358       } else {
359          bsock->b_errno = errno;
360       }
361       if (rc < 0) {
362          if (!bsock->suppress_error_msgs && !bsock->timed_out) {
363             Qmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), 
364                   bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
365          }
366       } else {
367          Qmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), 
368                bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
369       }
370       return 0;
371    }
372
373    bsock->out_msg_no++;               /* increment message number */
374    if (bsock->msglen <= 0) {          /* length only? */
375       return 1;                       /* yes, no data */
376    }
377
378    /* send data packet */
379    bsock->timer_start = watchdog_time; /* start timer */
380    bsock->timed_out = 0;               
381    rc = write_nbytes(bsock, mp_chr(bsock->msg), bsock->msglen);
382    bsock->timer_start = 0;            /* clear timer */
383    if (rc != bsock->msglen) {
384       bsock->errors++;
385       if (errno == 0) {
386          bsock->b_errno = EIO;
387       } else {
388          bsock->b_errno = errno;
389       }
390       if (rc < 0) {
391          if (!bsock->suppress_error_msgs) {
392             Qmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), 
393                   bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
394          }
395       } else {
396          Qmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), 
397                bsock->msglen, bsock->who, bsock->host, bsock->port, rc);
398       }
399       return 0;
400    }
401    return 1;
402 }
403
404 /*
405  * Establish an SSL connection -- server side         
406  *  Codes that ssl_need and ssl_has can take
407  *    BNET_SSL_NONE      I cannot do ssl
408  *    BNET_SSL_OK        I can do ssl, but it is not required on my end
409  *    BNET_SSL_REQUIRED  ssl is required on my end
410  */
411 int     
412 bnet_ssl_server(BSOCK *bsock, char *password, int ssl_need, int ssl_has)
413 {
414    /* Check to see if what we need (ssl_need) corresponds to what he has (ssl_has) */
415    /* The other side expects a response from us */
416    return 1;
417 }
418
419 /*
420  * Establish an SSL connection -- client side   
421  */
422 int bnet_ssl_client(BSOCK *bsock, char *password, int ssl_need)
423 {
424    /* We are the client so we must wait for the server to notify us */
425    return 1;
426 }
427
428
429 /*
430  * Wait for a specified time for data to appear on
431  * the BSOCK connection.
432  *
433  *   Returns: 1 if data available
434  *            0 if timeout
435  *           -1 if error
436  */
437 int 
438 bnet_wait_data(BSOCK *bsock, int sec)          
439 {
440    fd_set fdset;
441    struct timeval tv;
442
443    FD_ZERO(&fdset);
444    FD_SET((unsigned)bsock->fd, &fdset);
445    tv.tv_sec = sec;
446    tv.tv_usec = 0;
447    for ( ;; ) {
448       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
449       case 0:                         /* timeout */
450          bsock->b_errno = 0;
451          return 0;
452       case -1:
453          bsock->b_errno = errno;
454          if (errno == EINTR || errno == EAGAIN) {
455             continue;
456          }
457          return -1;                  /* error return */
458       default:
459          bsock->b_errno = 0;
460          return 1;
461       }
462    }
463 }
464
465 /*
466  * As above, but returns on interrupt
467  */
468 int
469 bnet_wait_data_intr(BSOCK *bsock, int sec)          
470 {
471    fd_set fdset;
472    struct timeval tv;
473
474    FD_ZERO(&fdset);
475    FD_SET((unsigned)bsock->fd, &fdset);
476    tv.tv_sec = sec;
477    tv.tv_usec = 0;
478    for ( ;; ) {
479       switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
480       case 0:                         /* timeout */
481          bsock->b_errno = 0;
482          return 0;
483       case -1:
484          bsock->b_errno = errno;
485          return -1;                  /* error return */
486       default:
487          bsock->b_errno = 0;
488          return 1;
489       }
490    }
491 }
492
493 #ifndef NETDB_INTERNAL
494 #define NETDB_INTERNAL  -1      /* See errno. */
495 #endif
496 #ifndef NETDB_SUCCESS
497 #define NETDB_SUCCESS   0       /* No problem. */
498 #endif
499 #ifndef HOST_NOT_FOUND
500 #define HOST_NOT_FOUND  1       /* Authoritative Answer Host not found. */
501 #endif
502 #ifndef TRY_AGAIN
503 #define TRY_AGAIN       2       /* Non-Authoritative Host not found, or SERVERFAIL. */
504 #endif
505 #ifndef NO_RECOVERY
506 #define NO_RECOVERY     3       /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
507 #endif
508 #ifndef NO_DATA
509 #define NO_DATA         4       /* Valid name, no data record of requested type. */
510 #endif
511
512 /*
513  * Get human readable error for gethostbyname()
514  */
515 static const char *gethost_strerror() 
516 {
517    switch (h_errno) {
518    case NETDB_INTERNAL:
519       return strerror(errno);
520    case NETDB_SUCCESS:
521       return "No problem.";
522    case HOST_NOT_FOUND:
523       return "Authoritative answer Host not found.";
524    case TRY_AGAIN:
525       return "Non-authoritative Host not found, or ServerFail.";
526    case NO_RECOVERY:
527       return "Non-recoverable errors, FORMERR, REFUSED, or NOTIMP.";
528    case NO_DATA:
529       return "Valid name, no data record of resquested type.";
530    default:
531       return "Unknown error.";
532    }
533 }
534
535
536 static pthread_mutex_t ip_mutex = PTHREAD_MUTEX_INITIALIZER;
537
538 /*
539  * Convert a hostname or dotted IP address into   
540  * a s_addr.  We handle only IPv4.
541  */
542 static uint32_t *bget_host_ip(JCR *jcr, char *host)
543 {
544    struct in_addr inaddr;
545    uint32_t *addr_list;               /* this really should be struct in_addr */
546    struct hostent *hp;
547    char **p;
548    int i;
549
550    if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
551       addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
552       addr_list[0] = inaddr.s_addr;
553       addr_list[1] = (uint32_t) -1;
554    } else {
555       P(ip_mutex);
556       if ((hp = gethostbyname(host)) == NULL) {
557          Qmsg2(jcr, M_ERROR, 0, "gethostbyname() for host \"%s\" failed: ERR=%s\n", 
558                host, gethost_strerror());
559          V(ip_mutex);
560          return NULL;
561       }
562       if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
563          Qmsg2(jcr, M_ERROR, 0, _("gethostbyname() network address length error.\n\
564 Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length);
565          V(ip_mutex);
566          return NULL;
567       }
568       i = 0;
569       for (p = hp->h_addr_list; *p != 0; p++) {
570          i++;
571       }
572       i++;
573       addr_list = (uint32_t *)malloc(sizeof(uint32_t) * i);
574       i = 0;
575       for (p = hp->h_addr_list; *p != 0; p++) {
576          addr_list[i++] = (*(struct in_addr **)p)->s_addr;
577       }
578       addr_list[i] = (uint32_t) -1;
579       V(ip_mutex);
580    }
581    return addr_list;
582 }
583
584 /*     
585  * Open a TCP connection to the UPS network server
586  * Returns NULL
587  * Returns BSOCK * pointer on success
588  *
589  *  ***FIXME*** implement service from /etc/services
590  */
591 static BSOCK *
592 bnet_open(JCR *jcr, const char *name, char *host, char *service, int port, int *fatal)
593 {
594    int sockfd;
595    struct sockaddr_in tcp_serv_addr;     /* socket information */
596    uint32_t *addr_list;
597    int i, connected = 0;
598    int turnon = 1;
599
600    /* 
601     * Fill in the structure serv_addr with the address of
602     * the server that we want to connect with.
603     */
604    memset((char *)&tcp_serv_addr, 0,  sizeof(tcp_serv_addr));
605    tcp_serv_addr.sin_family = AF_INET;
606    tcp_serv_addr.sin_port = htons(port);
607
608    if ((addr_list=bget_host_ip(jcr, host)) == NULL) {
609      *fatal = 1;
610      return NULL;
611    }
612
613    /* Open a TCP socket */
614    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
615       free(addr_list);
616       *fatal = 1;
617       return NULL;
618    }
619
620    /*
621     * Receive notification when connection dies.
622     */
623    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
624       Qmsg1(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno));
625    }
626    
627    for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
628       /* connect to server */
629       tcp_serv_addr.sin_addr.s_addr = addr_list[i];
630       if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
631          continue;
632       }
633       connected = 1;
634       break;
635    }
636
637    free(addr_list);
638    if (!connected) {
639       socketClose(sockfd);
640       return NULL;
641    }
642    return init_bsock(jcr, sockfd, name, host, port, &tcp_serv_addr);
643 }
644
645 /*
646  * Try to connect to host for max_retry_time at retry_time intervals.
647  */
648 BSOCK *
649 bnet_connect(JCR *jcr, int retry_interval, int max_retry_time, const char *name,
650              char *host, char *service, int port, int verbose)
651 {
652    int i;
653    BSOCK *bsock;
654    int fatal = 0;
655
656    for (i=0; (bsock = bnet_open(jcr, name, host, service, port, &fatal)) == NULL; i -= retry_interval) {
657      if (fatal || (jcr && job_canceled(jcr))) {
658         return NULL;
659      }
660      Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
661               name, host, port, strerror(errno));
662       if (i < 0) {
663          i = 60 * 5;                  /* complain again in 5 minutes */
664          if (verbose)
665             Qmsg4(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
666 Retrying ...\n", name, host, port, strerror(errno));
667       }
668       bmicrosleep(retry_interval, 0);
669       max_retry_time -= retry_interval;
670       if (max_retry_time <= 0) {
671          Qmsg4(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
672               name, host, port, strerror(errno));
673          return NULL;
674       }
675    }
676    return bsock;
677 }
678
679
680 /*
681  * Return the string for the error that occurred
682  * on the socket. Only the first error is retained.
683  */
684 char *bnet_strerror(BSOCK *bsock)
685 {
686    return strerror(bsock->b_errno);
687 }
688
689 /*
690  * Format and send a message
691  *  Returns: 0 on failure
692  *           1 on success
693  */
694 int
695 bnet_fsend(BSOCK *bs, const char *fmt, ...)
696 {
697    va_list arg_ptr;
698    int maxlen;
699
700    if (bs->errors || bs->terminated) {
701       return 0;
702    }
703    /* This probably won't work, but we vsnprintf, then if we
704     * get a negative length or a length greater than our buffer
705     * (depending on which library is used), the printf was truncated, so
706     * get a biger buffer and try again.
707     */
708 again:
709    maxlen = sizeof_pool_memory(bs->msg) - 1;
710    va_start(arg_ptr, fmt);
711    bs->msglen = bvsnprintf(mp_chr(bs->msg), maxlen, fmt, arg_ptr);
712    va_end(arg_ptr);
713    if (bs->msglen < 0 || bs->msglen >= maxlen) {
714       bs->msg = realloc_pool_memory(bs->msg, maxlen + maxlen / 2);
715       goto again;
716    }
717    return bnet_send(bs);
718 }
719
720 /* 
721  * Set the network buffer size, suggested size is in size.
722  *  Actual size obtained is returned in bs->msglen
723  *
724  *  Returns: 0 on failure
725  *           1 on success
726  */
727 int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
728 {
729    uint32_t dbuf_size, start_size;
730 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
731    int opt;
732
733     opt = IPTOS_THROUGHPUT;
734     setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (sockopt_val_t)&opt, sizeof(opt));
735 #endif
736
737    if (size != 0) {
738       dbuf_size = size;
739    } else {
740       dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
741    }
742    start_size = dbuf_size;
743    if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
744       Qmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc BSOCK data buffer\n"));
745       return 0;
746    }
747    if (rw & BNET_SETBUF_READ) {
748       while ((dbuf_size > TAPE_BSIZE) &&
749          (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
750          Qmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
751          dbuf_size -= TAPE_BSIZE;
752       }
753       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
754       if (dbuf_size != start_size) {
755          Qmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
756       }
757       if (dbuf_size % TAPE_BSIZE != 0) {
758          Qmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
759               dbuf_size);
760       }
761    }
762    if (size != 0) {
763       dbuf_size = size;
764    } else {
765       dbuf_size = DEFAULT_NETWORK_BUFFER_SIZE;
766    }
767    start_size = dbuf_size;
768    if (rw & BNET_SETBUF_WRITE) {
769       while ((dbuf_size > TAPE_BSIZE) &&
770          (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (sockopt_val_t)&dbuf_size, sizeof(dbuf_size)) < 0)) {
771          Qmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno));
772          dbuf_size -= TAPE_BSIZE;
773       }
774       Dmsg1(200, "set network buffer size=%d\n", dbuf_size);
775       if (dbuf_size != start_size) {
776          Qmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size);
777       }
778       if (dbuf_size % TAPE_BSIZE != 0) {
779          Qmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"),
780               dbuf_size);
781       }
782    }
783
784    bs->msglen = dbuf_size;
785    return 1;
786 }
787
788 /*
789  * Send a network "signal" to the other end 
790  *  This consists of sending a negative packet length
791  *
792  *  Returns: 0 on failure
793  *           1 on success
794  */
795 int bnet_sig(BSOCK *bs, int sig)
796 {
797    bs->msglen = sig;
798    return bnet_send(bs);
799 }
800
801 /*
802  * Convert a network "signal" code into
803  * human readable ASCII.
804  */
805 const char *bnet_sig_to_ascii(BSOCK *bs)
806 {
807    static char buf[30];
808    switch (bs->msglen) {
809       case BNET_EOD:
810          return "BNET_EOD";           /* end of data stream */
811       case BNET_EOD_POLL:
812          return "BNET_EOD_POLL";
813       case BNET_STATUS:
814          return "BNET_STATUS";
815       case BNET_TERMINATE:
816          return "BNET_TERMINATE";     /* terminate connection */
817       case BNET_POLL:
818          return "BNET_POLL";
819       case BNET_HEARTBEAT:
820          return "BNET_HEARTBEAT";
821       case BNET_HB_RESPONSE:
822          return "BNET_HB_RESPONSE";
823       case BNET_PROMPT:
824          return "BNET_PROMPT";
825       default:
826          sprintf(buf, "Unknown sig %d", bs->msglen);
827          return buf;
828    }
829 }
830
831
832 /* Initialize internal socket structure.  
833  *  This probably should be done in net_open
834  */
835 BSOCK *
836 init_bsock(JCR *jcr, int sockfd, const char *who, const char *host, int port, 
837            struct sockaddr_in *client_addr) 
838 {
839    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
840    memset(bsock, 0, sizeof(BSOCK));
841    bsock->fd = sockfd;
842    bsock->errors = 0;
843    bsock->msg = get_pool_memory(PM_MESSAGE);
844    bsock->errmsg = get_pool_memory(PM_MESSAGE);
845    bsock->who = bstrdup(who);
846    bsock->host = bstrdup(host);
847    bsock->port = port;
848    memcpy(&bsock->client_addr, client_addr, sizeof(bsock->client_addr));
849    /*
850     * ****FIXME**** reduce this to a few hours once   
851     *   heartbeats are implemented
852     */
853    bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
854    bsock->jcr = jcr;
855    return bsock;
856 }
857
858 BSOCK *
859 dup_bsock(BSOCK *osock)
860 {
861    BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK));
862    memcpy(bsock, osock, sizeof(BSOCK));
863    bsock->msg = get_pool_memory(PM_MESSAGE);
864    bsock->errmsg = get_pool_memory(PM_MESSAGE);
865    if (osock->who) {
866       bsock->who = bstrdup(osock->who);
867    }
868    if (osock->host) {
869       bsock->host = bstrdup(osock->host);
870    }
871    bsock->duped = true;
872    return bsock;
873 }
874
875 /* Close the network connection */
876 void 
877 bnet_close(BSOCK *bsock)
878 {
879    BSOCK *next;
880
881    for ( ; bsock != NULL; bsock = next) {
882       next = bsock->next;
883       if (!bsock->duped) {
884          if (bsock->timed_out) {
885             shutdown(bsock->fd, 2);   /* discard any pending I/O */
886          }
887          socketClose(bsock->fd);      /* normal close */
888       }
889       term_bsock(bsock);
890    }
891    return;
892 }
893
894 void
895 term_bsock(BSOCK *bsock)
896 {
897    if (bsock->msg) {
898       free_pool_memory(bsock->msg);
899       bsock->msg = NULL;
900    } else {
901       ASSERT(1==0);                   /* double close */
902    }
903    if (bsock->errmsg) {
904       free_pool_memory(bsock->errmsg);
905       bsock->errmsg = NULL;
906    }
907    if (bsock->who) {
908       free(bsock->who);
909       bsock->who = NULL;
910    }
911    if (bsock->host) {
912       free(bsock->host);
913       bsock->host = NULL;
914    }
915    free(bsock);
916 }
917