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