ia64/xen-unstable

view tools/xenstore/xenstored_watch.c @ 6538:84ee014ebd41

Merge xen-vtx-unstable.hg
author adsharma@los-vmm.sc.intel.com
date Wed Aug 17 12:34:38 2005 -0800 (2005-08-17)
parents 23979fb12c49 f294acb25858
children 99914b54f7bf
line source
1 /*
2 Watch code for Xen Store Daemon.
3 Copyright (C) 2005 Rusty Russell IBM Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <sys/time.h>
25 #include <time.h>
26 #include <assert.h>
27 #include "talloc.h"
28 #include "list.h"
29 #include "xenstored_watch.h"
30 #include "xs_lib.h"
31 #include "utils.h"
32 #include "xenstored_test.h"
33 #include "xenstored_domain.h"
35 /* FIXME: time out unacked watches. */
36 struct watch_event
37 {
38 /* The events on this watch. */
39 struct list_head list;
41 /* Data to send (node\0token\0). */
42 unsigned int len;
43 char *data;
44 };
46 struct watch
47 {
48 /* Watches on this connection */
49 struct list_head list;
51 /* Current outstanding events applying to this watch. */
52 struct list_head events;
54 /* Is this relative to connnection's implicit path? */
55 const char *relative_path;
57 char *token;
58 char *node;
59 };
61 /* Look through our watches: if any of them have an event, queue it. */
62 void queue_next_event(struct connection *conn)
63 {
64 struct watch_event *event;
65 struct watch *watch;
67 /* We had a reply queued already? Send it: other end will
68 * discard watch. */
69 if (conn->waiting_reply) {
70 conn->out = conn->waiting_reply;
71 conn->waiting_reply = NULL;
72 conn->waiting_for_ack = NULL;
73 return;
74 }
76 /* If we're already waiting for ack, don't queue more. */
77 if (conn->waiting_for_ack)
78 return;
80 list_for_each_entry(watch, &conn->watches, list) {
81 event = list_top(&watch->events, struct watch_event, list);
82 if (event) {
83 conn->waiting_for_ack = watch;
84 send_reply(conn,XS_WATCH_EVENT,event->data,event->len);
85 break;
86 }
87 }
88 }
90 static int destroy_watch_event(void *_event)
91 {
92 struct watch_event *event = _event;
94 trace_destroy(event, "watch_event");
95 return 0;
96 }
98 static void add_event(struct connection *conn,
99 struct watch *watch, const char *node)
100 {
101 struct watch_event *event;
103 /* Check read permission: no permission, no watch event.
104 * If it doesn't exist, we need permission to read parent.
105 */
106 if (!check_node_perms(conn, node, XS_PERM_READ|XS_PERM_ENOENT_OK)) {
107 fprintf(stderr, "No permission for %s\n", node);
108 return;
109 }
111 if (watch->relative_path) {
112 node += strlen(watch->relative_path);
113 if (*node == '/') /* Could be "" */
114 node++;
115 }
117 event = talloc(watch, struct watch_event);
118 event->len = strlen(node) + 1 + strlen(watch->token) + 1;
119 event->data = talloc_array(event, char, event->len);
120 strcpy(event->data, node);
121 strcpy(event->data + strlen(node) + 1, watch->token);
122 talloc_set_destructor(event, destroy_watch_event);
123 list_add_tail(&event->list, &watch->events);
124 trace_create(event, "watch_event");
125 }
127 /* FIXME: we fail to fire on out of memory. Should drop connections. */
128 void fire_watches(struct connection *conn, const char *node, bool recurse)
129 {
130 struct connection *i;
131 struct watch *watch;
133 /* During transactions, don't fire watches. */
134 if (conn->transaction)
135 return;
137 /* Create an event for each watch. Don't send to self. */
138 list_for_each_entry(i, &connections, list) {
139 if (i == conn)
140 continue;
142 list_for_each_entry(watch, &i->watches, list) {
143 if (is_child(node, watch->node))
144 add_event(i, watch, node);
145 else if (recurse && is_child(watch->node, node))
146 add_event(i, watch, watch->node);
147 else
148 continue;
149 /* If connection not doing anything, queue this. */
150 if (!i->out)
151 queue_next_event(i);
152 }
153 }
154 }
156 static int destroy_watch(void *_watch)
157 {
158 trace_destroy(_watch, "watch");
159 return 0;
160 }
162 void shortest_watch_ack_timeout(struct timeval *tv)
163 {
164 (void)tv;
165 #if 0 /* FIXME */
166 struct watch *watch;
168 list_for_each_entry(watch, &watches, list) {
169 struct watch_event *i;
170 list_for_each_entry(i, &watch->events, list) {
171 if (!timerisset(&i->timeout))
172 continue;
173 if (!timerisset(tv) || timercmp(&i->timeout, tv, <))
174 *tv = i->timeout;
175 }
176 }
177 #endif
178 }
180 void check_watch_ack_timeout(void)
181 {
182 #if 0
183 struct watch *watch;
184 struct timeval now;
186 gettimeofday(&now, NULL);
187 list_for_each_entry(watch, &watches, list) {
188 struct watch_event *i, *tmp;
189 list_for_each_entry_safe(i, tmp, &watch->events, list) {
190 if (!timerisset(&i->timeout))
191 continue;
192 if (timercmp(&i->timeout, &now, <)) {
193 xprintf("Warning: timeout on watch event %s"
194 " token %s\n",
195 i->node, watch->token);
196 trace_watch_timeout(watch->conn, i->node,
197 watch->token);
198 timerclear(&i->timeout);
199 }
200 }
201 }
202 #endif
203 }
205 void do_watch(struct connection *conn, struct buffered_data *in)
206 {
207 struct watch *watch;
208 char *vec[2];
209 bool relative;
211 if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
212 send_error(conn, EINVAL);
213 return;
214 }
216 relative = !strstarts(vec[0], "/");
217 vec[0] = canonicalize(conn, vec[0]);
218 if (!is_valid_nodename(vec[0])) {
219 send_error(conn, errno);
220 return;
221 }
223 watch = talloc(conn, struct watch);
224 watch->node = talloc_strdup(watch, vec[0]);
225 watch->token = talloc_strdup(watch, vec[1]);
226 if (relative)
227 watch->relative_path = get_implicit_path(conn);
228 else
229 watch->relative_path = NULL;
231 INIT_LIST_HEAD(&watch->events);
233 list_add_tail(&watch->list, &conn->watches);
234 trace_create(watch, "watch");
235 talloc_set_destructor(watch, destroy_watch);
236 send_ack(conn, XS_WATCH);
237 }
239 void do_watch_ack(struct connection *conn, const char *token)
240 {
241 struct watch_event *event;
243 if (!token) {
244 send_error(conn, EINVAL);
245 return;
246 }
248 if (!conn->waiting_for_ack) {
249 send_error(conn, ENOENT);
250 return;
251 }
253 if (!streq(conn->waiting_for_ack->token, token)) {
254 /* They're confused: this will cause us to send event again */
255 conn->waiting_for_ack = NULL;
256 send_error(conn, EINVAL);
257 return;
258 }
260 /* Remove event: after ack sent, core will call queue_next_event */
261 event = list_top(&conn->waiting_for_ack->events, struct watch_event,
262 list);
263 list_del(&event->list);
264 talloc_free(event);
266 conn->waiting_for_ack = NULL;
267 send_ack(conn, XS_WATCH_ACK);
268 }
270 void do_unwatch(struct connection *conn, struct buffered_data *in)
271 {
272 struct watch *watch;
273 char *node, *vec[2];
275 if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
276 send_error(conn, EINVAL);
277 return;
278 }
280 /* We don't need to worry if we're waiting for an ack for the
281 * watch we're deleting: conn->waiting_for_ack was reset by
282 * this command in consider_message anyway. */
283 node = canonicalize(conn, vec[0]);
284 list_for_each_entry(watch, &conn->watches, list) {
285 if (streq(watch->node, node) && streq(watch->token, vec[1])) {
286 list_del(&watch->list);
287 talloc_free(watch);
288 send_ack(conn, XS_UNWATCH);
289 return;
290 }
291 }
292 send_error(conn, ENOENT);
293 }
295 #ifdef TESTING
296 void dump_watches(struct connection *conn)
297 {
298 struct watch *watch;
299 struct watch_event *event;
301 if (conn->waiting_for_ack)
302 printf(" waiting_for_ack for watch on %s token %s\n",
303 conn->waiting_for_ack->node,
304 conn->waiting_for_ack->token);
306 list_for_each_entry(watch, &conn->watches, list) {
307 printf(" watch on %s token %s\n",
308 watch->node, watch->token);
309 list_for_each_entry(event, &watch->events, list)
310 printf(" event: %s\n", event->data);
311 }
312 }
313 #endif