]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/getmsg.c
Initial revision
[bacula/bacula] / bacula / src / dird / getmsg.c
1 /*
2  *
3  *   Bacula Director -- routines to receive network data and
4  *    handle network signals. These routines handle the connections
5  *    to the Storage daemon and the File daemon.
6  *
7  *     Kern Sibbald, August MM
8  *
9  *    This routine runs as a thread and must be thread reentrant.
10  *
11  *  Basic tasks done here:
12  *    Handle  network signals (signals).  
13  *       Signals always have return status 0 from bnet_recv() and
14  *       a zero or negative message length.
15  *    Pass appropriate messages back to the caller (responses).  
16  *       Responses always have a digit as the first character.
17  *    Handle requests for message and catalog services (requests).  
18  *       Requests are any message that does not begin with a digit.
19  *       In affect, they are commands.
20  *
21  */
22 /*
23    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
24
25    This program is free software; you can redistribute it and/or
26    modify it under the terms of the GNU General Public License as
27    published by the Free Software Foundation; either version 2 of
28    the License, or (at your option) any later version.
29
30    This program is distributed in the hope that it will be useful,
31    but WITHOUT ANY WARRANTY; without even the implied warranty of
32    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33    General Public License for more details.
34
35    You should have received a copy of the GNU General Public
36    License along with this program; if not, write to the Free
37    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
38    MA 02111-1307, USA.
39
40  */
41
42 #include "bacula.h"
43 #include "dird.h"
44
45 /* Forward referenced functions */
46 static char *find_msg_start(char *msg);
47
48 static char OK_msg[] = "1000 OK\n";
49
50 /*
51  * Get a message
52  *  Call appropriate processing routine
53  *  If it is not a Jmsg or a ReqCat message,
54  *   return it to the caller.
55  *
56  *  This routine is called to get the next message from
57  *  another daemon. If the message is in canonical message
58  *  format and the type is known, it will be dispatched
59  *  to the appropriate handler.  If the message is
60  *  in any other format, it will be returned. 
61  *
62  */
63 int32_t bget_msg(BSOCK *bs, int rtn)
64 {
65    int32_t n;
66    char Job[MAX_NAME_LENGTH];
67    char MsgType[20];
68    int type, level;
69    JCR *jcr;
70    char *msg;
71
72    for (;;) {
73       n = bnet_recv(bs);
74       Dmsg2(120, "bget_msg %d: %s\n", n, bs->msg);
75
76       if (n < 0) {
77          return n;                    /* error return */
78       }
79       if (n == 0) {                   /* handle signal */
80          /* 0 return from bnet_recv() => network signal */
81          switch (bs->msglen) {
82             case BNET_EOF:               /* deprecated */
83             case BNET_EOD:               /* end of data */
84                return 0;
85             case BNET_EOD_POLL:
86                bnet_fsend(bs, OK_msg);   /* send response */
87                return 0;                 /* end of data */
88             case BNET_TERMINATE:
89                bs->terminated = 1;
90                return 0;
91             case BNET_POLL:
92                bnet_fsend(bs, OK_msg);   /* send response */
93                break;
94             case BNET_HEARTBEAT:
95                bnet_sig(bs, BNET_HB_RESPONSE);
96                break;
97             case BNET_STATUS:
98                /* *****FIXME***** Implement */
99                bnet_fsend(bs, "Status OK\n");
100                bnet_sig(bs, BNET_EOD);
101                break;
102             default:
103                Emsg1(M_WARNING, 0, _("bget_msg: unknown signal %d\n"), bs->msglen);
104                return 0;
105          }
106          continue;
107       }
108      
109       /* Handle normal data */
110
111       if (ISDIGIT(bs->msg[0])) {      /* response? */
112          return n;                    /* yes, return it */
113       }
114         
115       /*
116        * If we get here, it must be a request.  Either
117        *  a message to dispatch, or a catalog request.
118        *  Try to fulfill it.
119        */
120       if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
121          Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
122          continue;
123       }
124       if (!(jcr=get_jcr_by_full_name(Job))) {
125          Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
126          continue;
127       }
128
129       /* Skip past "Jmsg Job=nnn" */
130       if (!(msg=find_msg_start(bs->msg))) {
131          Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
132          free_jcr(jcr);
133          continue;
134       }
135
136       /* 
137        * Here we are expecting a message of the following format:
138        *   Jmsg Job=nnn type=nnn level=nnn Message-string
139        */
140       if (bs->msg[0] == 'J') {           /* Job message */
141          if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d", 
142                     Job, &type, &level) != 3) {
143             Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
144             free_jcr(jcr);
145             continue;
146          }
147          Dmsg1(120, "Got msg: %s\n", bs->msg);
148          skip_spaces(&msg);
149          skip_nonspaces(&msg);        /* skip type=nnn */
150          skip_spaces(&msg);
151          skip_nonspaces(&msg);        /* skip level=nnn */
152          if (*msg == ' ') {
153             msg++;                    /* skip leading space */
154          }
155          Dmsg1(120, "Dispatch msg: %s", msg);
156          dispatch_message(jcr, type, level, msg);
157          free_jcr(jcr);
158          continue;
159       }
160       /* 
161        * Here we expact a CatReq message
162        *   CatReq Job=nn Catalog-Request-Message
163        */
164       if (bs->msg[0] == 'C') {        /* Catalog request */
165          Dmsg1(120, "Catalog req: %s", bs->msg);
166          catalog_request(jcr, bs, msg);
167          free_jcr(jcr);
168          continue;
169       }
170       if (bs->msg[0] == 'U') {        /* Catalog update */
171          catalog_update(jcr, bs, msg);
172          free_jcr(jcr);
173          continue;
174       }
175       if (bs->msg[0] == 'M') {        /* Mount request */
176          Dmsg1(120, "Mount req: %s", bs->msg);
177          mount_request(jcr, bs, msg);
178          free_jcr(jcr);
179          continue;
180       }
181       return n;
182    }
183 }
184
185 static char *find_msg_start(char *msg)
186 {
187    char *p = msg;
188
189    skip_nonspaces(&p);                /* skip message type */
190    skip_spaces(&p);
191    skip_nonspaces(&p);                /* skip Job */
192    skip_spaces(&p);                   /* after spaces come the message */
193    return p;
194 }
195
196 /*
197  * Get response from File daemon to a command we
198  * sent. Check that the response agrees with what we expect.
199  *
200  *  Returns: 0 on failure
201  *           1 on success
202  */
203 int response(BSOCK *fd, char *resp, char *cmd)
204 {
205    int n;
206
207    if (fd->errors) {
208       return 0;
209    }
210    if ((n = bget_msg(fd, 0)) > 0) {
211       Dmsg0(10, fd->msg);
212       if (strcmp(fd->msg, resp) == 0) {
213          return 1;
214       }
215       Emsg3(M_FATAL, 0, _("<filed: bad response to %s command: wanted %s got: %s\n"),
216          cmd, resp, fd->msg);
217       return 0;
218    } 
219    Emsg2(M_FATAL, 0, _("<filed: Socket error from Filed on %s command: ERR=%s\n"),
220          cmd, bnet_strerror(fd));
221    return 0;
222 }