]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsock.c
kes Implement posix_fadvise in FD, and for reading spool files in SD.
[bacula/bacula] / bacula / src / lib / bsock.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Network Utility Routines
30  *
31  *  by Kern Sibbald
32  *
33  *   Version $Id: bnet.c 3670 2006-11-21 16:13:58Z kerns $
34  */
35
36
37 #include "bacula.h"
38 #include "jcr.h"
39 #include <netdb.h>
40
41 #ifndef ENODATA                    /* not defined on BSD systems */
42 #define ENODATA EPIPE
43 #endif
44
45 #ifdef HAVE_WIN32
46 #define socketRead(fd, buf, len)  ::recv(fd, buf, len, 0)
47 #define socketWrite(fd, buf, len) ::send(fd, buf, len, 0)
48 #define socketClose(fd)           ::closesocket(fd)
49 #else
50 #define socketRead(fd, buf, len)  ::read(fd, buf, len)
51 #define socketWrite(fd, buf, len) ::write(fd, buf, len)
52 #define socketClose(fd)           ::close(fd)
53 #endif
54
55 /*
56  * Send a message over the network. The send consists of
57  * two network packets. The first is sends a 32 bit integer containing
58  * the length of the data packet which follows.
59  *
60  * Returns: false on failure
61  *          true  on success
62  */
63 bool BSOCK::send()
64 {
65    int32_t rc;
66    int32_t pktsiz;
67    int32_t *hdr;
68
69    if (errors || terminated || msglen > 1000000) {
70       return false;
71    }
72    /* Compute total packet length */
73    if (msglen <= 0) {
74       pktsiz = sizeof(pktsiz);               /* signal, no data */
75    } else {
76       pktsiz = msglen + sizeof(pktsiz);      /* data */
77    }
78    /* Store packet length at head of message -- note, we
79     *  have reserved an int32_t just before msg, so we can
80     *  store there 
81     */
82    hdr = (int32_t *)(msg - (int)sizeof(pktsiz));
83    *hdr = htonl(msglen);                     /* store signal/length */
84
85    out_msg_no++;            /* increment message number */
86
87    /* send data packet */
88    timer_start = watchdog_time;  /* start timer */
89    timed_out = 0;
90    /* Full I/O done in one write */
91    rc = write_nbytes(this, (char *)hdr, pktsiz);
92    timer_start = 0;         /* clear timer */
93    if (rc != pktsiz) {
94       errors++;
95       if (errno == 0) {
96          b_errno = EIO;
97       } else {
98          b_errno = errno;
99       }
100       if (rc < 0) {
101          if (!suppress_error_msgs) {
102             Qmsg5(m_jcr, M_ERROR, 0,
103                   _("Write error sending %d bytes to %s:%s:%d: ERR=%s\n"), 
104                   msglen, m_who,
105                   m_host, m_port, bnet_strerror(this));
106          }
107       } else {
108          Qmsg5(m_jcr, M_ERROR, 0,
109                _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
110                msglen, m_who, m_host, m_port, rc);
111       }
112       return false;
113    }
114    return true;
115 }
116
117 /*
118  * Format and send a message
119  *  Returns: false on error
120  *           true  on success
121  */
122 bool BSOCK::fsend(const char *fmt, ...)
123 {
124    va_list arg_ptr;
125    int maxlen;
126
127    if (errors || terminated) {
128       return false;
129    }
130    /* This probably won't work, but we vsnprintf, then if we
131     * get a negative length or a length greater than our buffer
132     * (depending on which library is used), the printf was truncated, so
133     * get a bigger buffer and try again.
134     */
135    for (;;) {
136       maxlen = sizeof_pool_memory(msg) - 1;
137       va_start(arg_ptr, fmt);
138       msglen = bvsnprintf(msg, maxlen, fmt, arg_ptr);
139       va_end(arg_ptr);
140       if (msglen > 0 && msglen < (maxlen - 5)) {
141          break;
142       }
143       msg = realloc_pool_memory(msg, maxlen + maxlen / 2);
144    }
145    return send();
146 }
147
148 /*
149  * Receive a message from the other end. Each message consists of
150  * two packets. The first is a header that contains the size
151  * of the data that follows in the second packet.
152  * Returns number of bytes read (may return zero)
153  * Returns -1 on signal (BNET_SIGNAL)
154  * Returns -2 on hard end of file (BNET_HARDEOF)
155  * Returns -3 on error  (BNET_ERROR)
156  *
157  *  Unfortunately, it is a bit complicated because we have these
158  *    four return types:
159  *    1. Normal data
160  *    2. Signal including end of data stream
161  *    3. Hard end of file
162  *    4. Error
163  *  Using is_bnet_stop() and is_bnet_error() you can figure this all out.
164  */
165 int32_t BSOCK::recv()
166 {
167    int32_t nbytes;
168    int32_t pktsiz;
169
170    msg[0] = 0;
171    msglen = 0;
172    if (errors || terminated) {
173       return BNET_HARDEOF;
174    }
175
176    read_seqno++;            /* bump sequence number */
177    timer_start = watchdog_time;  /* set start wait time */
178    timed_out = 0;
179    /* get data size -- in int32_t */
180    if ((nbytes = read_nbytes(this, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
181       timer_start = 0;      /* clear timer */
182       /* probably pipe broken because client died */
183       if (errno == 0) {
184          b_errno = ENODATA;
185       } else {
186          b_errno = errno;
187       }
188       errors++;
189       return BNET_HARDEOF;         /* assume hard EOF received */
190    }
191    timer_start = 0;         /* clear timer */
192    if (nbytes != sizeof(int32_t)) {
193       errors++;
194       b_errno = EIO;
195       Qmsg5(m_jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"),
196             sizeof(int32_t), nbytes, m_who, m_host, m_port);
197       return BNET_ERROR;
198    }
199
200    pktsiz = ntohl(pktsiz);         /* decode no. of bytes that follow */
201
202    if (pktsiz == 0) {              /* No data transferred */
203       timer_start = 0;      /* clear timer */
204       in_msg_no++;
205       msglen = 0;
206       return 0;                    /* zero bytes read */
207    }
208
209    /* If signal or packet size too big */
210    if (pktsiz < 0 || pktsiz > 1000000) {
211       if (pktsiz > 0) {            /* if packet too big */
212          Qmsg3(m_jcr, M_FATAL, 0,
213                _("Packet size too big from \"%s:%s:%d. Terminating connection.\n"),
214                m_who, m_host, m_port);
215          pktsiz = BNET_TERMINATE;  /* hang up */
216       }
217       if (pktsiz == BNET_TERMINATE) {
218          terminated = 1;
219       }
220       timer_start = 0;      /* clear timer */
221       b_errno = ENODATA;
222       msglen = pktsiz;      /* signal code */
223       return BNET_SIGNAL;          /* signal */
224    }
225
226    /* Make sure the buffer is big enough + one byte for EOS */
227    if (pktsiz >= (int32_t) sizeof_pool_memory(msg)) {
228       msg = realloc_pool_memory(msg, pktsiz + 100);
229    }
230
231    timer_start = watchdog_time;  /* set start wait time */
232    timed_out = 0;
233    /* now read the actual data */
234    if ((nbytes = read_nbytes(this, msg, pktsiz)) <= 0) {
235       timer_start = 0;      /* clear timer */
236       if (errno == 0) {
237          b_errno = ENODATA;
238       } else {
239          b_errno = errno;
240       }
241       errors++;
242       Qmsg4(m_jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
243             m_who, m_host, m_port, bnet_strerror(this));
244       return BNET_ERROR;
245    }
246    timer_start = 0;         /* clear timer */
247    in_msg_no++;
248    msglen = nbytes;
249    if (nbytes != pktsiz) {
250       b_errno = EIO;
251       errors++;
252       Qmsg5(m_jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"),
253             pktsiz, nbytes, m_who, m_host, m_port);
254       return BNET_ERROR;
255    }
256    /* always add a zero by to properly terminate any
257     * string that was send to us. Note, we ensured above that the
258     * buffer is at least one byte longer than the message length.
259     */
260    msg[nbytes] = 0; /* terminate in case it is a string */
261    sm_check(__FILE__, __LINE__, false);
262    return nbytes;                  /* return actual length of message */
263 }
264
265
266 /*
267  * Send a signal
268  */
269 bool BSOCK::signal(int signal)
270 {
271    msglen = signal;
272    if (signal == BNET_TERMINATE) {
273       suppress_error_msgs = true;
274    }
275    return send();
276 }
277
278 /* 
279  * Despool spooled attributes
280  */
281 bool BSOCK::despool(void update_attr_spool_size(ssize_t size), ssize_t tsize)
282 {
283    int32_t pktsiz;
284    size_t nbytes;
285    ssize_t last = 0, size = 0;
286    int count = 0;
287
288    rewind(spool_fd);
289
290 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
291    posix_fadvise(fileno(spool_fd), 0, 0, POSIX_FADV_WILLNEED);
292 #endif
293
294    while (fread((char *)&pktsiz, 1, sizeof(int32_t), spool_fd) ==
295           sizeof(int32_t)) {
296       size += sizeof(int32_t);
297       msglen = ntohl(pktsiz);
298       if (msglen > 0) {
299          if (msglen > (int32_t) sizeof_pool_memory(msg)) {
300             msg = realloc_pool_memory(msg, msglen + 1);
301          }
302          nbytes = fread(msg, 1, msglen, spool_fd);
303          if (nbytes != (size_t) msglen) {
304             berrno be;
305             Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, msglen);
306             Qmsg1(jcr(), M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
307                   be.strerror());
308             update_attr_spool_size(tsize - last);
309             return false;
310          }
311          size += nbytes;
312          if ((++count & 0x3F) == 0) {
313             update_attr_spool_size(size - last);
314             last = size;
315          }
316       }
317       send();
318    }
319    update_attr_spool_size(tsize - last);
320    if (ferror(spool_fd)) {
321       berrno be;
322       Qmsg1(jcr(), M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
323             be.strerror());
324       return false;
325    }
326    return true;
327 }
328
329
330 void BSOCK::close()
331 {
332    BSOCK *bsock = this;
333    BSOCK *next;
334
335    for (; bsock; bsock = next) {
336       next = bsock->m_next;           /* get possible pointer to next before destoryed */
337       if (!bsock->duped) {
338 #ifdef HAVE_TLS
339          /* Shutdown tls cleanly. */
340          if (bsock->tls) {
341             tls_bsock_shutdown(bsock);
342             free_tls_connection(bsock->tls);
343             bsock->tls = NULL;
344          }
345 #endif /* HAVE_TLS */
346          if (bsock->timed_out) {
347             shutdown(bsock->fd, 2);   /* discard any pending I/O */
348          }
349          socketClose(bsock->fd);      /* normal close */
350       }
351       destroy();                      /* free the packet */
352    }
353    return;
354 }
355
356 void BSOCK::destroy()
357 {
358    if (msg) {
359       free_pool_memory(msg);
360       msg = NULL;
361    } else {
362       ASSERT(1 == 0);              /* double close */
363    }
364    if (errmsg) {
365       free_pool_memory(errmsg);
366       errmsg = NULL;
367    }
368    if (m_who) {
369       free(m_who);
370       m_who = NULL;
371    }
372    if (m_host) {
373       free(m_host);
374       m_host = NULL;
375    }
376    free(this);
377 }