]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsock.c
Move putz test program to a test program directory under qt-console.
[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 #ifdef HAVE_WIN32
42 #define socketRead(fd, buf, len)  ::recv(fd, buf, len, 0)
43 #define socketWrite(fd, buf, len) ::send(fd, buf, len, 0)
44 #define socketClose(fd)           ::closesocket(fd)
45 #else
46 #define socketRead(fd, buf, len)  ::read(fd, buf, len)
47 #define socketWrite(fd, buf, len) ::write(fd, buf, len)
48 #define socketClose(fd)           ::close(fd)
49 #endif
50
51 /*
52  * Send a message over the network. The send consists of
53  * two network packets. The first is sends a 32 bit integer containing
54  * the length of the data packet which follows.
55  *
56  * Returns: false on failure
57  *          true  on success
58  */
59 bool BSOCK::send()
60 {
61    int32_t rc;
62    int32_t pktsiz;
63    int32_t *hdr;
64
65    if (errors || terminated || msglen > 1000000) {
66       return false;
67    }
68    /* Compute total packet length */
69    if (msglen <= 0) {
70       pktsiz = sizeof(pktsiz);               /* signal, no data */
71    } else {
72       pktsiz = msglen + sizeof(pktsiz);      /* data */
73    }
74    /* Store packet length at head of message -- note, we
75     *  have reserved an int32_t just before msg, so we can
76     *  store there 
77     */
78    hdr = (int32_t *)(msg - (int)sizeof(pktsiz));
79    *hdr = htonl(msglen);                     /* store signal/length */
80
81    out_msg_no++;            /* increment message number */
82
83    /* send data packet */
84    timer_start = watchdog_time;  /* start timer */
85    timed_out = 0;
86    /* Full I/O done in one write */
87    rc = write_nbytes(this, (char *)hdr, pktsiz);
88    timer_start = 0;         /* clear timer */
89    if (rc != pktsiz) {
90       errors++;
91       if (errno == 0) {
92          b_errno = EIO;
93       } else {
94          b_errno = errno;
95       }
96       if (rc < 0) {
97          if (!suppress_error_msgs) {
98             Qmsg5(m_jcr, M_ERROR, 0,
99                   _("Write error sending %d bytes to %s:%s:%d: ERR=%s\n"), 
100                   msglen, m_who,
101                   m_host, m_port, bnet_strerror(this));
102          }
103       } else {
104          Qmsg5(m_jcr, M_ERROR, 0,
105                _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
106                msglen, m_who, m_host, m_port, rc);
107       }
108       return false;
109    }
110    return true;
111 }
112
113 /*
114  * Format and send a message
115  *  Returns: false on error
116  *           true  on success
117  */
118 bool BSOCK::fsend(const char *fmt, ...)
119 {
120    va_list arg_ptr;
121    int maxlen;
122
123    if (errors || terminated) {
124       return false;
125    }
126    /* This probably won't work, but we vsnprintf, then if we
127     * get a negative length or a length greater than our buffer
128     * (depending on which library is used), the printf was truncated, so
129     * get a bigger buffer and try again.
130     */
131    for (;;) {
132       maxlen = sizeof_pool_memory(msg) - 1;
133       va_start(arg_ptr, fmt);
134       msglen = bvsnprintf(msg, maxlen, fmt, arg_ptr);
135       va_end(arg_ptr);
136       if (msglen > 0 && msglen < (maxlen - 5)) {
137          break;
138       }
139       msg = realloc_pool_memory(msg, maxlen + maxlen / 2);
140    }
141    return send();
142 }
143
144 /*
145  * Receive a message from the other end. Each message consists of
146  * two packets. The first is a header that contains the size
147  * of the data that follows in the second packet.
148  * Returns number of bytes read (may return zero)
149  * Returns -1 on signal (BNET_SIGNAL)
150  * Returns -2 on hard end of file (BNET_HARDEOF)
151  * Returns -3 on error  (BNET_ERROR)
152  *
153  *  Unfortunately, it is a bit complicated because we have these
154  *    four return types:
155  *    1. Normal data
156  *    2. Signal including end of data stream
157  *    3. Hard end of file
158  *    4. Error
159  *  Using is_bnet_stop() and is_bnet_error() you can figure this all out.
160  */
161 int32_t BSOCK::recv()
162 {
163    int32_t nbytes;
164    int32_t pktsiz;
165
166    msg[0] = 0;
167    msglen = 0;
168    if (errors || terminated) {
169       return BNET_HARDEOF;
170    }
171
172    read_seqno++;            /* bump sequence number */
173    timer_start = watchdog_time;  /* set start wait time */
174    timed_out = 0;
175    /* get data size -- in int32_t */
176    if ((nbytes = read_nbytes(this, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
177       timer_start = 0;      /* clear timer */
178       /* probably pipe broken because client died */
179       if (errno == 0) {
180          b_errno = ENODATA;
181       } else {
182          b_errno = errno;
183       }
184       errors++;
185       return BNET_HARDEOF;         /* assume hard EOF received */
186    }
187    timer_start = 0;         /* clear timer */
188    if (nbytes != sizeof(int32_t)) {
189       errors++;
190       b_errno = EIO;
191       Qmsg5(m_jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"),
192             sizeof(int32_t), nbytes, m_who, m_host, m_port);
193       return BNET_ERROR;
194    }
195
196    pktsiz = ntohl(pktsiz);         /* decode no. of bytes that follow */
197
198    if (pktsiz == 0) {              /* No data transferred */
199       timer_start = 0;      /* clear timer */
200       in_msg_no++;
201       msglen = 0;
202       return 0;                    /* zero bytes read */
203    }
204
205    /* If signal or packet size too big */
206    if (pktsiz < 0 || pktsiz > 1000000) {
207       if (pktsiz > 0) {            /* if packet too big */
208          Qmsg3(m_jcr, M_FATAL, 0,
209                _("Packet size too big from \"%s:%s:%d. Terminating connection.\n"),
210                m_who, m_host, m_port);
211          pktsiz = BNET_TERMINATE;  /* hang up */
212       }
213       if (pktsiz == BNET_TERMINATE) {
214          terminated = 1;
215       }
216       timer_start = 0;      /* clear timer */
217       b_errno = ENODATA;
218       msglen = pktsiz;      /* signal code */
219       return BNET_SIGNAL;          /* signal */
220    }
221
222    /* Make sure the buffer is big enough + one byte for EOS */
223    if (pktsiz >= (int32_t) sizeof_pool_memory(msg)) {
224       msg = realloc_pool_memory(msg, pktsiz + 100);
225    }
226
227    timer_start = watchdog_time;  /* set start wait time */
228    timed_out = 0;
229    /* now read the actual data */
230    if ((nbytes = read_nbytes(this, msg, pktsiz)) <= 0) {
231       timer_start = 0;      /* clear timer */
232       if (errno == 0) {
233          b_errno = ENODATA;
234       } else {
235          b_errno = errno;
236       }
237       errors++;
238       Qmsg4(m_jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"),
239             m_who, m_host, m_port, bnet_strerror(this));
240       return BNET_ERROR;
241    }
242    timer_start = 0;         /* clear timer */
243    in_msg_no++;
244    msglen = nbytes;
245    if (nbytes != pktsiz) {
246       b_errno = EIO;
247       errors++;
248       Qmsg5(m_jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"),
249             pktsiz, nbytes, m_who, m_host, m_port);
250       return BNET_ERROR;
251    }
252    /* always add a zero by to properly terminate any
253     * string that was send to us. Note, we ensured above that the
254     * buffer is at least one byte longer than the message length.
255     */
256    msg[nbytes] = 0; /* terminate in case it is a string */
257    sm_check(__FILE__, __LINE__, false);
258    return nbytes;                  /* return actual length of message */
259 }
260
261
262 /*
263  * Send a signal
264  */
265 bool BSOCK::signal(int signal)
266 {
267    msglen = signal;
268    if (signal == BNET_TERMINATE) {
269       suppress_error_msgs = true;
270    }
271    return send();
272 }
273
274 void BSOCK::close()
275 {
276    BSOCK *bsock = this;
277    BSOCK *next;
278
279    for (; bsock; bsock = next) {
280       next = bsock->m_next;           /* get possible pointer to next before destoryed */
281       if (!bsock->duped) {
282 #ifdef HAVE_TLS
283          /* Shutdown tls cleanly. */
284          if (bsock->tls) {
285             tls_bsock_shutdown(bsock);
286             free_tls_connection(bsock->tls);
287             bsock->tls = NULL;
288          }
289 #endif /* HAVE_TLS */
290          if (bsock->timed_out) {
291             shutdown(bsock->fd, 2);   /* discard any pending I/O */
292          }
293          socketClose(bsock->fd);      /* normal close */
294       }
295       destroy();                      /* free the packet */
296    }
297    return;
298 }
299
300 void BSOCK::destroy()
301 {
302    if (msg) {
303       free_pool_memory(msg);
304       msg = NULL;
305    } else {
306       ASSERT(1 == 0);              /* double close */
307    }
308    if (errmsg) {
309       free_pool_memory(errmsg);
310       errmsg = NULL;
311    }
312    if (m_who) {
313       free(m_who);
314       m_who = NULL;
315    }
316    if (m_host) {
317       free(m_host);
318       m_host = NULL;
319    }
320    free(this);
321 }