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