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