3 Subroutines for dealing with message objects. */
6 * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
25 * https://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
37 #include <omapip/omapip_p.h>
39 OMAPI_OBJECT_ALLOC (omapi_message,
40 omapi_message_object_t, omapi_type_message)
42 omapi_message_object_t *omapi_registered_messages;
44 isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
46 omapi_message_object_t *m;
50 m = (omapi_message_object_t *)0;
51 status = omapi_message_allocate (&m, file, line);
52 if (status != ISC_R_SUCCESS)
55 g = (omapi_object_t *)0;
56 status = omapi_generic_new (&g, file, line);
57 if (status != ISC_R_SUCCESS) {
58 dfree (m, file, line);
61 status = omapi_object_reference (&m -> inner, g, file, line);
62 if (status != ISC_R_SUCCESS) {
63 omapi_object_dereference ((omapi_object_t **)&m, file, line);
64 omapi_object_dereference (&g, file, line);
67 status = omapi_object_reference (&g -> outer,
68 (omapi_object_t *)m, file, line);
70 if (status != ISC_R_SUCCESS) {
71 omapi_object_dereference ((omapi_object_t **)&m, file, line);
72 omapi_object_dereference (&g, file, line);
76 status = omapi_object_reference (o, (omapi_object_t *)m, file, line);
77 omapi_message_dereference (&m, file, line);
78 omapi_object_dereference (&g, file, line);
79 if (status != ISC_R_SUCCESS)
85 isc_result_t omapi_message_set_value (omapi_object_t *h,
87 omapi_data_string_t *name,
88 omapi_typed_data_t *value)
90 omapi_message_object_t *m;
93 if (h -> type != omapi_type_message)
94 return DHCP_R_INVALIDARG;
95 m = (omapi_message_object_t *)h;
97 /* Can't set authlen. */
99 /* Can set authenticator, but the value must be typed data. */
100 if (!omapi_ds_strcmp (name, "authenticator")) {
101 if (m -> authenticator)
102 omapi_typed_data_dereference (&m -> authenticator,
104 omapi_typed_data_reference (&m -> authenticator, value, MDL);
105 return ISC_R_SUCCESS;
107 } else if (!omapi_ds_strcmp (name, "object")) {
108 if (value -> type != omapi_datatype_object)
109 return DHCP_R_INVALIDARG;
111 omapi_object_dereference (&m -> object, MDL);
112 omapi_object_reference (&m -> object, value -> u.object, MDL);
113 return ISC_R_SUCCESS;
115 } else if (!omapi_ds_strcmp (name, "notify-object")) {
116 if (value -> type != omapi_datatype_object)
117 return DHCP_R_INVALIDARG;
118 if (m -> notify_object)
119 omapi_object_dereference (&m -> notify_object, MDL);
120 omapi_object_reference (&m -> notify_object,
121 value -> u.object, MDL);
122 return ISC_R_SUCCESS;
124 /* Can set authid, but it has to be an integer. */
125 } else if (!omapi_ds_strcmp (name, "authid")) {
126 if (value -> type != omapi_datatype_int)
127 return DHCP_R_INVALIDARG;
128 m -> authid = value -> u.integer;
129 return ISC_R_SUCCESS;
131 /* Can set op, but it has to be an integer. */
132 } else if (!omapi_ds_strcmp (name, "op")) {
133 if (value -> type != omapi_datatype_int)
134 return DHCP_R_INVALIDARG;
135 m -> op = value -> u.integer;
136 return ISC_R_SUCCESS;
138 /* Handle also has to be an integer. */
139 } else if (!omapi_ds_strcmp (name, "handle")) {
140 if (value -> type != omapi_datatype_int)
141 return DHCP_R_INVALIDARG;
142 m -> h = value -> u.integer;
143 return ISC_R_SUCCESS;
145 /* Transaction ID has to be an integer. */
146 } else if (!omapi_ds_strcmp (name, "id")) {
147 if (value -> type != omapi_datatype_int)
148 return DHCP_R_INVALIDARG;
149 m -> id = value -> u.integer;
150 return ISC_R_SUCCESS;
152 /* Remote transaction ID has to be an integer. */
153 } else if (!omapi_ds_strcmp (name, "rid")) {
154 if (value -> type != omapi_datatype_int)
155 return DHCP_R_INVALIDARG;
156 m -> rid = value -> u.integer;
157 return ISC_R_SUCCESS;
160 /* Try to find some inner object that can take the value. */
161 if (h -> inner && h -> inner -> type -> set_value) {
162 status = ((*(h -> inner -> type -> set_value))
163 (h -> inner, id, name, value));
164 if (status == ISC_R_SUCCESS)
168 return ISC_R_NOTFOUND;
171 isc_result_t omapi_message_get_value (omapi_object_t *h,
173 omapi_data_string_t *name,
174 omapi_value_t **value)
176 omapi_message_object_t *m;
177 if (h -> type != omapi_type_message)
178 return DHCP_R_INVALIDARG;
179 m = (omapi_message_object_t *)h;
181 /* Look for values that are in the message data structure. */
182 if (!omapi_ds_strcmp (name, "authlen"))
183 return omapi_make_int_value (value, name, (int)m -> authlen,
185 else if (!omapi_ds_strcmp (name, "authenticator")) {
186 if (m -> authenticator)
187 return omapi_make_value (value, name,
188 m -> authenticator, MDL);
190 return ISC_R_NOTFOUND;
191 } else if (!omapi_ds_strcmp (name, "authid")) {
192 return omapi_make_int_value (value,
193 name, (int)m -> authid, MDL);
194 } else if (!omapi_ds_strcmp (name, "op")) {
195 return omapi_make_int_value (value, name, (int)m -> op, MDL);
196 } else if (!omapi_ds_strcmp (name, "handle")) {
197 return omapi_make_int_value (value, name, (int)m -> h, MDL);
198 } else if (!omapi_ds_strcmp (name, "id")) {
199 return omapi_make_int_value (value, name, (int)m -> id, MDL);
200 } else if (!omapi_ds_strcmp (name, "rid")) {
201 return omapi_make_int_value (value, name, (int)m -> rid, MDL);
204 /* See if there's an inner object that has the value. */
205 if (h -> inner && h -> inner -> type -> get_value)
206 return (*(h -> inner -> type -> get_value))
207 (h -> inner, id, name, value);
208 return ISC_R_NOTFOUND;
211 isc_result_t omapi_message_destroy (omapi_object_t *h,
212 const char *file, int line)
214 omapi_message_object_t *m;
215 if (h -> type != omapi_type_message)
216 return DHCP_R_INVALIDARG;
217 m = (omapi_message_object_t *)h;
218 if (m -> authenticator) {
219 omapi_typed_data_dereference (&m -> authenticator, file, line);
221 if (!m -> prev && omapi_registered_messages != m)
222 omapi_message_unregister (h);
224 omapi_object_dereference (&m -> id_object, file, line);
226 omapi_object_dereference (&m -> object, file, line);
227 if (m -> notify_object)
228 omapi_object_dereference (&m -> notify_object, file, line);
229 if (m -> protocol_object)
230 omapi_protocol_dereference (&m -> protocol_object, file, line);
231 return ISC_R_SUCCESS;
234 isc_result_t omapi_message_signal_handler (omapi_object_t *h,
235 const char *name, va_list ap)
237 omapi_message_object_t *m;
238 if (h -> type != omapi_type_message)
239 return DHCP_R_INVALIDARG;
240 m = (omapi_message_object_t *)h;
242 if (!strcmp (name, "status")) {
243 if (m -> notify_object &&
244 m -> notify_object -> type -> signal_handler)
245 return ((m -> notify_object -> type -> signal_handler))
246 (m -> notify_object, name, ap);
247 else if (m -> object && m -> object -> type -> signal_handler)
248 return ((m -> object -> type -> signal_handler))
249 (m -> object, name, ap);
251 if (h -> inner && h -> inner -> type -> signal_handler)
252 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
254 return ISC_R_NOTFOUND;
257 /* Write all the published values associated with the object through the
258 specified connection. */
260 isc_result_t omapi_message_stuff_values (omapi_object_t *c,
264 if (m -> type != omapi_type_message)
265 return DHCP_R_INVALIDARG;
267 if (m -> inner && m -> inner -> type -> stuff_values)
268 return (*(m -> inner -> type -> stuff_values)) (c, id,
270 return ISC_R_SUCCESS;
273 isc_result_t omapi_message_register (omapi_object_t *mo)
275 omapi_message_object_t *m;
277 if (mo -> type != omapi_type_message)
278 return DHCP_R_INVALIDARG;
279 m = (omapi_message_object_t *)mo;
281 /* Already registered? */
282 if (m -> prev || m -> next || omapi_registered_messages == m)
283 return DHCP_R_INVALIDARG;
285 if (omapi_registered_messages) {
286 omapi_object_reference
287 ((omapi_object_t **)&m -> next,
288 (omapi_object_t *)omapi_registered_messages, MDL);
289 omapi_object_reference
290 ((omapi_object_t **)&omapi_registered_messages -> prev,
291 (omapi_object_t *)m, MDL);
292 omapi_object_dereference
293 ((omapi_object_t **)&omapi_registered_messages, MDL);
295 omapi_object_reference
296 ((omapi_object_t **)&omapi_registered_messages,
297 (omapi_object_t *)m, MDL);
298 return ISC_R_SUCCESS;;
301 isc_result_t omapi_message_unregister (omapi_object_t *mo)
303 omapi_message_object_t *m;
304 omapi_message_object_t *n;
306 if (mo -> type != omapi_type_message)
307 return DHCP_R_INVALIDARG;
308 m = (omapi_message_object_t *)mo;
310 /* Not registered? */
311 if (!m -> prev && omapi_registered_messages != m)
312 return DHCP_R_INVALIDARG;
314 n = (omapi_message_object_t *)0;
316 omapi_object_reference ((omapi_object_t **)&n,
317 (omapi_object_t *)m -> next, MDL);
318 omapi_object_dereference ((omapi_object_t **)&m -> next, MDL);
319 omapi_object_dereference ((omapi_object_t **)&n -> prev, MDL);
322 omapi_message_object_t *tmp = (omapi_message_object_t *)0;
323 omapi_object_reference ((omapi_object_t **)&tmp,
324 (omapi_object_t *)m -> prev, MDL);
325 omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL);
327 omapi_object_dereference
328 ((omapi_object_t **)&tmp -> next, MDL);
330 omapi_object_reference
331 ((omapi_object_t **)&tmp -> next,
332 (omapi_object_t *)n, MDL);
333 omapi_object_dereference ((omapi_object_t **)&tmp, MDL);
335 omapi_object_dereference
336 ((omapi_object_t **)&omapi_registered_messages, MDL);
338 omapi_object_reference
339 ((omapi_object_t **)&omapi_registered_messages,
340 (omapi_object_t *)n, MDL);
343 omapi_object_dereference ((omapi_object_t **)&n, MDL);
344 return ISC_R_SUCCESS;
347 #ifdef DEBUG_PROTOCOL
348 static const char *omapi_message_op_name(int op) {
350 case OMAPI_OP_OPEN: return "OMAPI_OP_OPEN";
351 case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH";
352 case OMAPI_OP_UPDATE: return "OMAPI_OP_UPDATE";
353 case OMAPI_OP_STATUS: return "OMAPI_OP_STATUS";
354 case OMAPI_OP_DELETE: return "OMAPI_OP_DELETE";
355 case OMAPI_OP_NOTIFY: return "OMAPI_OP_NOTIFY";
356 default: return "(unknown op)";
362 omapi_message_process_internal (omapi_object_t *, omapi_object_t *);
364 isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po)
367 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
368 unsigned long previous_outstanding = dmalloc_outstanding;
371 status = omapi_message_process_internal (mo, po);
373 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
374 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
376 dmalloc_outstanding - previous_outstanding,
377 dmalloc_outstanding, dmalloc_longterm);
379 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
380 dmalloc_dump_outstanding ();
382 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0
390 omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po)
392 omapi_message_object_t *message, *m;
393 omapi_object_t *object = (omapi_object_t *)0;
394 omapi_value_t *tv = (omapi_value_t *)0;
395 unsigned long create, update, exclusive;
397 isc_result_t status, waitstatus;
398 omapi_object_type_t *type;
400 if (mo -> type != omapi_type_message)
401 return DHCP_R_INVALIDARG;
402 message = (omapi_message_object_t *)mo;
404 #ifdef DEBUG_PROTOCOL
405 log_debug ("omapi_message_process(): "
406 "op=%s handle=%#x id=%#x rid=%#x",
407 omapi_message_op_name (message -> op),
408 message -> h, message -> id, message -> rid);
411 if (message -> rid) {
412 for (m = omapi_registered_messages; m; m = m -> next)
413 if (m -> id == message -> rid)
415 /* If we don't have a real message corresponding to
416 the message ID to which this message claims it is a
417 response, something's fishy. */
419 return ISC_R_NOTFOUND;
420 /* The authenticator on responses must match the initial
422 if (message -> authid != m -> authid)
423 return ISC_R_NOTFOUND;
425 m = (omapi_message_object_t *)0;
427 /* All messages must have an authenticator, with the exception
428 of messages that are opening a new authenticator. */
429 if (omapi_protocol_authenticated(po) &&
430 !message->id_object &&
431 message->op != OMAPI_OP_OPEN) {
432 return omapi_protocol_send_status
433 (po, message->id_object, DHCP_R_NOKEYS,
434 message->id, "No authenticator on message");
438 switch (message -> op) {
441 return omapi_protocol_send_status
442 (po, message->id_object, DHCP_R_INVALIDARG,
443 message->id, "OPEN can't be a response");
446 /* Get the type of the requested object, if one was
448 status = omapi_get_value_str (mo, message -> id_object,
450 if (status == ISC_R_SUCCESS &&
451 (tv -> value -> type == omapi_datatype_data ||
452 tv -> value -> type == omapi_datatype_string)) {
453 for (type = omapi_object_types;
454 type; type = type -> next)
455 if (!omapi_td_strcmp (tv -> value,
459 type = (omapi_object_type_t *)0;
461 omapi_value_dereference (&tv, MDL);
463 /* If this object had no authenticator, the requested object
464 must be an authenticator object. */
465 if (omapi_protocol_authenticated(po) &&
466 !message->id_object &&
467 type != omapi_type_auth_key) {
468 return omapi_protocol_send_status
469 (po, message->id_object, DHCP_R_NOKEYS,
470 message->id, "No authenticator on message");
473 /* Get the create flag. */
474 status = omapi_get_value_str (mo, message -> id_object,
476 if (status == ISC_R_SUCCESS) {
477 status = omapi_get_int_value (&create, tv -> value);
478 omapi_value_dereference (&tv, MDL);
479 if (status != ISC_R_SUCCESS) {
480 return omapi_protocol_send_status
481 (po, message -> id_object,
482 status, message -> id,
483 "invalid create flag value");
488 /* Get the update flag. */
489 status = omapi_get_value_str (mo, message -> id_object,
491 if (status == ISC_R_SUCCESS) {
492 status = omapi_get_int_value (&update, tv -> value);
493 omapi_value_dereference (&tv, MDL);
494 if (status != ISC_R_SUCCESS) {
495 return omapi_protocol_send_status
496 (po, message -> id_object,
497 status, message -> id,
498 "invalid update flag value");
503 /* Get the exclusive flag. */
504 status = omapi_get_value_str (mo, message -> id_object,
506 if (status == ISC_R_SUCCESS) {
507 status = omapi_get_int_value (&exclusive, tv -> value);
508 omapi_value_dereference (&tv, MDL);
509 if (status != ISC_R_SUCCESS) {
510 return omapi_protocol_send_status
511 (po, message -> id_object,
512 status, message -> id,
513 "invalid exclusive flag value");
518 /* If we weren't given a type, look the object up with
522 return omapi_protocol_send_status
523 (po, message->id_object,
526 "type required on create");
531 /* If the type doesn't provide a lookup method, we can't
532 look up the object. */
533 if (!type -> lookup) {
534 return omapi_protocol_send_status
535 (po, message -> id_object,
536 ISC_R_NOTIMPLEMENTED, message -> id,
537 "unsearchable object type");
540 status = (*(type -> lookup)) (&object, message -> id_object,
543 if (status != ISC_R_SUCCESS &&
544 status != ISC_R_NOTFOUND &&
545 status != DHCP_R_NOKEYS) {
546 return omapi_protocol_send_status
547 (po, message -> id_object,
548 status, message -> id,
549 "object lookup failed");
552 /* If we didn't find the object and we aren't supposed to
553 create it, return an error. */
554 if (status == ISC_R_NOTFOUND && !create) {
555 return omapi_protocol_send_status
556 (po, message -> id_object,
557 ISC_R_NOTFOUND, message -> id,
558 "no object matches specification");
561 /* If we found an object, we're supposed to be creating an
562 object, and we're not supposed to have found an object,
564 if (status == ISC_R_SUCCESS && create && exclusive) {
565 omapi_object_dereference (&object, MDL);
566 return omapi_protocol_send_status
567 (po, message -> id_object,
568 ISC_R_EXISTS, message -> id,
569 "specified object already exists");
572 /* If we're creating the object, do it now. */
574 status = omapi_object_create (&object,
575 message -> id_object,
577 if (status != ISC_R_SUCCESS) {
578 return omapi_protocol_send_status
579 (po, message -> id_object,
580 status, message -> id,
581 "can't create new object");
585 /* If we're updating it, do so now. */
586 if (create || update) {
587 /* This check does not belong here. */
588 if (object -> type == omapi_type_auth_key) {
589 omapi_object_dereference (&object, MDL);
590 return omapi_protocol_send_status
591 (po, message -> id_object,
592 status, message -> id,
593 "can't update object");
596 status = omapi_object_update (object,
597 message -> id_object,
600 if (status != ISC_R_SUCCESS) {
601 omapi_object_dereference (&object, MDL);
602 return omapi_protocol_send_status
603 (po, message -> id_object,
604 status, message -> id,
605 "can't update object");
609 /* If this is an authenticator object, add it to the active
610 set for the connection. */
611 if (object -> type == omapi_type_auth_key) {
612 omapi_handle_t handle;
613 status = omapi_object_handle (&handle, object);
614 if (status != ISC_R_SUCCESS) {
615 omapi_object_dereference (&object, MDL);
616 return omapi_protocol_send_status
617 (po, message -> id_object,
618 status, message -> id,
619 "can't select authenticator");
622 status = omapi_protocol_add_auth (po, object, handle);
623 if (status != ISC_R_SUCCESS) {
624 omapi_object_dereference (&object, MDL);
625 return omapi_protocol_send_status
626 (po, message -> id_object,
627 status, message -> id,
628 "can't select authenticator");
632 /* Now send the new contents of the object back in
636 case OMAPI_OP_REFRESH:
638 status = omapi_handle_lookup (&object, message -> h);
639 if (status != ISC_R_SUCCESS) {
640 return omapi_protocol_send_status
641 (po, message -> id_object,
642 status, message -> id,
643 "no matching handle");
646 status = omapi_protocol_send_update (po, message -> id_object,
647 message -> id, object);
648 omapi_object_dereference (&object, MDL);
651 case OMAPI_OP_UPDATE:
652 if (m && m -> object) {
653 status = omapi_object_reference (&object, m -> object,
656 status = omapi_handle_lookup (&object, message -> h);
657 if (status != ISC_R_SUCCESS) {
658 return omapi_protocol_send_status
659 (po, message -> id_object,
660 status, message -> id,
661 "no matching handle");
665 if (object -> type == omapi_type_auth_key ||
667 object -> inner -> type == omapi_type_auth_key)) {
669 omapi_object_dereference (&object, MDL);
670 return omapi_protocol_send_status
671 (po, message -> id_object,
672 status, message -> id,
673 "cannot update authenticator");
676 status = omapi_protocol_add_auth (po, object,
679 status = omapi_object_update (object,
680 message -> id_object,
684 if (status != ISC_R_SUCCESS) {
685 omapi_object_dereference (&object, MDL);
687 return omapi_protocol_send_status
688 (po, message -> id_object,
689 status, message -> id,
690 "can't update object");
692 omapi_signal ((omapi_object_t *)m,
694 (omapi_typed_data_t *)0);
695 return ISC_R_SUCCESS;
698 status = omapi_protocol_send_status
699 (po, message -> id_object, ISC_R_SUCCESS,
700 message -> id, (char *)0);
702 omapi_signal ((omapi_object_t *)m,
703 "status", ISC_R_SUCCESS,
704 (omapi_typed_data_t *)0);
705 omapi_message_unregister ((omapi_object_t *)m);
708 omapi_object_dereference (&object, MDL);
712 case OMAPI_OP_NOTIFY:
713 return omapi_protocol_send_status
714 (po, message -> id_object, ISC_R_NOTIMPLEMENTED,
715 message -> id, "notify not implemented yet");
717 case OMAPI_OP_STATUS:
718 /* The return status of a request. */
720 return ISC_R_UNEXPECTED;
722 /* Get the wait status. */
723 status = omapi_get_value_str (mo, message -> id_object,
725 if (status == ISC_R_SUCCESS) {
726 status = omapi_get_int_value (&wsi, tv -> value);
728 omapi_value_dereference (&tv, MDL);
729 if (status != ISC_R_SUCCESS)
730 waitstatus = ISC_R_UNEXPECTED;
732 waitstatus = ISC_R_UNEXPECTED;
734 status = omapi_get_value_str (mo, message -> id_object,
736 omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv);
737 if (status == ISC_R_SUCCESS)
738 omapi_value_dereference (&tv, MDL);
740 omapi_message_unregister((omapi_object_t *)m);
742 return ISC_R_SUCCESS;
744 case OMAPI_OP_DELETE:
745 status = omapi_handle_lookup (&object, message -> h);
746 if (status != ISC_R_SUCCESS) {
747 return omapi_protocol_send_status
748 (po, message -> id_object,
749 status, message -> id,
750 "no matching handle");
753 if (!object -> type -> remove)
754 return omapi_protocol_send_status
755 (po, message -> id_object,
756 ISC_R_NOTIMPLEMENTED, message -> id,
757 "no remove method for object");
759 status = (*(object -> type -> remove)) (object,
760 message -> id_object);
761 omapi_object_dereference (&object, MDL);
763 return omapi_protocol_send_status (po, message -> id_object,
764 status, message -> id,
767 return ISC_R_NOTIMPLEMENTED;