debug level controls
[vlendec/samba-autobuild/.git] / ctdb / common / ctdb_control.c
1 /* 
2    ctdb_control protocol code
3
4    Copyright (C) Andrew Tridgell  2007
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 #include "includes.h"
21 #include "lib/events/events.h"
22 #include "lib/tdb/include/tdb.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
26 #include "../include/ctdb_private.h"
27 #include "lib/util/dlinklist.h"
28
29 struct ctdb_control_state {
30         struct ctdb_context *ctdb;
31         uint32_t reqid;
32         ctdb_control_callback_fn_t callback;
33         void *private_data;
34 };
35
36 #define CHECK_CONTROL_DATA_SIZE(size) do { \
37  if (indata.dsize != size) { \
38          DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected %u\n", \
39                   opcode, indata.dsize, size));                         \
40          return -1; \
41  } \
42  } while (0)
43
44 /*
45   process a control request
46  */
47 static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, 
48                                      uint32_t opcode, TDB_DATA indata,
49                                      TDB_DATA *outdata)
50 {
51         switch (opcode) {
52         case CTDB_CONTROL_PROCESS_EXISTS: {
53                 pid_t pid;
54                 CHECK_CONTROL_DATA_SIZE(sizeof(pid));
55                 pid = *(pid_t *)indata.dptr;
56                 return kill(pid, 0);
57         }
58
59         case CTDB_CONTROL_SET_DEBUG: {
60                 CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
61                 LogLevel = *(uint32_t *)indata.dptr;
62                 return 0;
63         }
64
65         case CTDB_CONTROL_GET_DEBUG: {
66                 CHECK_CONTROL_DATA_SIZE(0);
67                 outdata->dptr = (uint8_t *)&LogLevel;
68                 outdata->dsize = sizeof(LogLevel);
69                 return 0;
70         }
71
72         case CTDB_CONTROL_STATUS: {
73                 CHECK_CONTROL_DATA_SIZE(0);
74                 outdata->dptr = (uint8_t *)&ctdb->status;
75                 outdata->dsize = sizeof(ctdb->status);
76                 return 0;
77         }
78
79         case CTDB_CONTROL_GETVNNMAP: {
80                 uint32_t i, len;
81                 CHECK_CONTROL_DATA_SIZE(0);
82                 len = 2+ctdb->vnn_map->size;
83                 outdata->dsize = 4*len;
84                 outdata->dptr = (unsigned char *)talloc_array(outdata, uint32_t, len);
85                 
86                 ((uint32_t *)outdata->dptr)[0] = ctdb->vnn_map->generation;
87                 ((uint32_t *)outdata->dptr)[1] = ctdb->vnn_map->size;
88                 for (i=0;i<ctdb->vnn_map->size;i++) {
89                         ((uint32_t *)outdata->dptr)[i+2] = ctdb->vnn_map->map[i];
90                 }
91
92                 return 0;
93         }
94
95         case CTDB_CONTROL_SETVNNMAP: {
96                 uint32_t *ptr, i;
97                 
98                 ptr = (uint32_t *)(&indata.dptr[0]);
99                 ctdb->vnn_map->generation = ptr[0];
100                 ctdb->vnn_map->size = ptr[1];
101                 if (ctdb->vnn_map->map) {
102                         talloc_free(ctdb->vnn_map->map);
103                         ctdb->vnn_map->map = NULL;
104                 }
105                 ctdb->vnn_map->map = talloc_array(ctdb->vnn_map, uint32_t, ctdb->vnn_map->size);
106                 if (ctdb->vnn_map->map == NULL) {
107                         DEBUG(0,(__location__ " Unable to allocate vnn_map->map structure\n"));
108                         exit(1);
109                 }
110                 for (i=0;i<ctdb->vnn_map->size;i++) {
111                         ctdb->vnn_map->map[i] = ptr[i+2];
112                 }
113                 return 0;
114         }
115
116         case CTDB_CONTROL_CONFIG: {
117                 CHECK_CONTROL_DATA_SIZE(0);
118                 outdata->dptr = (uint8_t *)ctdb;
119                 outdata->dsize = sizeof(*ctdb);
120                 return 0;
121         }
122
123         case CTDB_CONTROL_PING:
124                 CHECK_CONTROL_DATA_SIZE(0);
125                 return 0;
126
127         case CTDB_CONTROL_GETDBPATH: {
128                 uint32_t db_id;
129                 struct ctdb_db_context *ctdb_db;
130
131                 CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
132                 db_id = *(uint32_t *)indata.dptr;
133                 ctdb_db = find_ctdb_db(ctdb, db_id);
134                 if (ctdb_db == NULL) return -1;
135                 outdata->dptr = discard_const(ctdb_db->db_path);
136                 outdata->dsize = strlen(ctdb_db->db_path)+1;
137                 return 0;
138         }
139
140         default:
141                 DEBUG(0,(__location__ " Unknown CTDB control opcode %u\n", opcode));
142                 return -1;
143         }
144 }
145
146 /*
147   called when a CTDB_REQ_CONTROL packet comes in
148 */
149 void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
150 {
151         struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
152         TDB_DATA data, *outdata;
153         struct ctdb_reply_control *r;
154         int32_t status;
155         size_t len;
156
157         data.dptr = &c->data[0];
158         data.dsize = c->datalen;
159
160         outdata = talloc_zero(c, TDB_DATA);
161         status = ctdb_control_dispatch(ctdb, c->opcode, data, outdata);
162
163         len = offsetof(struct ctdb_reply_control, data) + outdata->dsize;
164         r = ctdb->methods->allocate_pkt(ctdb, len);
165         CTDB_NO_MEMORY_VOID(ctdb, r);
166         talloc_set_name_const(r, "ctdb_reply_control packet");
167
168         r->hdr.length       = len;
169         r->hdr.ctdb_magic   = CTDB_MAGIC;
170         r->hdr.ctdb_version = CTDB_VERSION;
171         r->hdr.operation    = CTDB_REPLY_CONTROL;
172         r->hdr.destnode     = hdr->srcnode;
173         r->hdr.srcnode      = ctdb->vnn;
174         r->hdr.reqid        = hdr->reqid;
175         r->status           = status;
176         r->datalen          = outdata->dsize;
177         if (outdata->dsize) {
178                 memcpy(&r->data[0], outdata->dptr, outdata->dsize);
179         }
180         
181         ctdb_queue_packet(ctdb, &r->hdr);       
182
183         talloc_free(r);
184 }
185
186 /*
187   called when a CTDB_REPLY_CONTROL packet comes in
188 */
189 void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
190 {
191         struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
192         TDB_DATA data;
193         struct ctdb_control_state *state;
194
195         state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_control_state);
196         if (state == NULL) {
197                 return;
198         }
199
200         if (hdr->reqid != state->reqid) {
201                 /* we found a record  but it was the wrong one */
202                 DEBUG(0, ("Dropped orphaned control reply with reqid:%d\n", hdr->reqid));
203                 return;
204         }
205
206         data.dptr = &c->data[0];
207         data.dsize = c->datalen;
208
209         state->callback(ctdb, c->status, data, state->private_data);
210         talloc_free(state);
211 }
212
213 static int ctdb_control_destructor(struct ctdb_control_state *state)
214 {
215         ctdb_reqid_remove(state->ctdb, state->reqid);
216         return 0;
217 }
218
219 /*
220   send a control message to a node
221  */
222 int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
223                              uint32_t srvid, uint32_t opcode, TDB_DATA data,
224                              ctdb_control_callback_fn_t callback,
225                              void *private_data)
226 {
227         struct ctdb_req_control *c;
228         struct ctdb_control_state *state;
229         size_t len;
230
231         state = talloc(ctdb, struct ctdb_control_state);
232         CTDB_NO_MEMORY(ctdb, state);
233
234         state->reqid = ctdb_reqid_new(ctdb, state);
235         state->callback = callback;
236         state->private_data = private_data;
237         state->ctdb = ctdb;
238
239         talloc_set_destructor(state, ctdb_control_destructor);
240
241         len = offsetof(struct ctdb_req_control, data) + data.dsize;
242         c = ctdb->methods->allocate_pkt(state, len);
243         CTDB_NO_MEMORY(ctdb, c);
244         talloc_set_name_const(c, "ctdb_req_control packet");
245
246         c->hdr.length       = len;
247         c->hdr.ctdb_magic   = CTDB_MAGIC;
248         c->hdr.ctdb_version = CTDB_VERSION;
249         c->hdr.operation    = CTDB_REQ_CONTROL;
250         c->hdr.destnode     = destnode;
251         c->hdr.srcnode      = ctdb->vnn;
252         c->hdr.reqid        = state->reqid;
253         c->opcode           = opcode;
254         c->srvid            = srvid;
255         c->datalen          = data.dsize;
256         if (data.dsize) {
257                 memcpy(&c->data[0], data.dptr, data.dsize);
258         }
259         
260         ctdb_queue_packet(ctdb, &c->hdr);       
261
262 #if CTDB_REQ_TIMEOUT
263         event_add_timed(ctdb->ev, state, timeval_current_ofs(CTDB_REQ_TIMEOUT, 0), 
264                         ctdb_control_timeout, state);
265 #endif
266
267         talloc_free(c);
268         return 0;
269 }