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