6 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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 * Newmarket, NH 03857 USA
25 * https://www.isc.org/
31 #include <omapip/omapip_p.h>
34 static omapi_io_object_t omapi_io_states
;
35 struct timeval cur_tv
;
37 struct eventqueue
*rw_queue_empty
;
39 OMAPI_OBJECT_ALLOC (omapi_io
,
40 omapi_io_object_t
, omapi_type_io_object
)
41 OMAPI_OBJECT_ALLOC (omapi_waiter
,
42 omapi_waiter_object_t
, omapi_type_waiter
)
45 register_eventhandler(struct eventqueue
**queue
, void (*handler
)(void *))
47 struct eventqueue
*t
, *q
;
49 /* traverse to end of list */
51 for (q
= *queue
; q
; q
= q
->next
) {
52 if (q
->handler
== handler
)
53 return; /* handler already registered */
57 q
= ((struct eventqueue
*)dmalloc(sizeof(struct eventqueue
), MDL
));
59 log_fatal("register_eventhandler: no memory!");
60 memset(q
, 0, sizeof *q
);
70 unregister_eventhandler(struct eventqueue
**queue
, void (*handler
)(void *))
72 struct eventqueue
*t
, *q
;
74 /* traverse to end of list */
76 for (q
= *queue
; q
; q
= q
->next
) {
77 if (q
->handler
== handler
) {
82 dfree(q
, MDL
); /* Don't access q after this!*/
91 trigger_event(struct eventqueue
**queue
)
95 for (q
=*queue
; q
; q
=q
->next
) {
102 * Callback routine to connect the omapi I/O object and socket with
103 * the isc socket code. The isc socket code will call this routine
104 * which will then call the correct local routine to process the bytes.
106 * Currently we are always willing to read more data, this should be modified
107 * so that on connections we don't read more if we already have enough.
109 * If we have more bytes to write we ask the library to call us when
110 * we can write more. If we indicate we don't have more to write we need
111 * to poke the library via isc_socket_fdwatchpoke.
115 * sockdelete indicates if we are deleting the socket or leaving it in place
116 * 1 is delete, 0 is leave in place
120 omapi_iscsock_cb(isc_task_t
*task
,
121 isc_socket_t
*socket
,
125 omapi_io_object_t
*obj
;
128 /* Get the current time... */
129 gettimeofday (&cur_tv
, (struct timezone
*)0);
131 /* isc socket stuff */
134 * walk through the io states list, if our object is on there
135 * service it. if not ignore it.
137 for (obj
= omapi_io_states
.next
; obj
!= NULL
; obj
= obj
->next
) {
146 /* Not much to be done if we have the wrong type of object. */
147 if (((omapi_object_t
*)cbarg
) -> type
!= omapi_type_io_object
) {
148 log_fatal ("Incorrect object type, must be of type io_object");
150 obj
= (omapi_io_object_t
*)cbarg
;
153 * If the object is marked as closed don't try and process
154 * anything just indicate that we don't want any more.
156 * This should be a temporary fix until we arrange to properly
159 if (obj
->closed
== ISC_TRUE
) {
164 if ((flags
== ISC_SOCKFDWATCH_READ
) &&
165 (obj
->reader
!= NULL
) &&
166 (obj
->inner
!= NULL
)) {
167 status
= obj
->reader(obj
->inner
);
169 * If we are shutting down (basically tried to
170 * read and got no bytes) we don't need to try
173 if (status
== ISC_R_SHUTTINGDOWN
)
175 /* Otherwise We always ask for more when reading */
177 } else if ((flags
== ISC_SOCKFDWATCH_WRITE
) &&
178 (obj
->writer
!= NULL
) &&
179 (obj
->inner
!= NULL
)) {
180 status
= obj
->writer(obj
->inner
);
181 /* If the writer has more to write they should return
182 * ISC_R_INPROGRESS */
183 if (status
== ISC_R_INPROGRESS
) {
189 * We get here if we either had an error (inconsistent
190 * structures etc) or no more to write, tell the socket
191 * lib we don't have more to do right now.
196 /* Register an I/O handle so that we can do asynchronous I/O on it. */
198 isc_result_t
omapi_register_io_object (omapi_object_t
*h
,
199 int (*readfd
) (omapi_object_t
*),
200 int (*writefd
) (omapi_object_t
*),
201 isc_result_t (*reader
)
203 isc_result_t (*writer
)
205 isc_result_t (*reaper
)
209 omapi_io_object_t
*obj
, *p
;
210 int fd_flags
= 0, fd
= 0;
212 /* omapi_io_states is a static object. If its reference count
213 is zero, this is the first I/O handle to be registered, so
214 we need to initialize it. Because there is no inner or outer
215 pointer on this object, and we're setting its refcnt to 1, it
216 will never be freed. */
217 if (!omapi_io_states
.refcnt
) {
218 omapi_io_states
.refcnt
= 1;
219 omapi_io_states
.type
= omapi_type_io_object
;
222 obj
= (omapi_io_object_t
*)0;
223 status
= omapi_io_allocate (&obj
, MDL
);
224 if (status
!= ISC_R_SUCCESS
)
226 obj
->closed
= ISC_FALSE
; /* mark as open */
228 status
= omapi_object_reference (&obj
-> inner
, h
, MDL
);
229 if (status
!= ISC_R_SUCCESS
) {
230 omapi_io_dereference (&obj
, MDL
);
234 status
= omapi_object_reference (&h
-> outer
,
235 (omapi_object_t
*)obj
, MDL
);
236 if (status
!= ISC_R_SUCCESS
) {
237 omapi_io_dereference (&obj
, MDL
);
242 * Attach the I/O object to the isc socket library via the
243 * fdwatch function. This allows the socket library to watch
244 * over a socket that we built. If there are both a read and
245 * a write socket we asssume they are the same socket.
249 fd_flags
|= ISC_SOCKFDWATCH_READ
;
254 fd_flags
|= ISC_SOCKFDWATCH_WRITE
;
259 status
= isc_socket_fdwatchcreate(dhcp_gbl_ctx
.socketmgr
,
265 if (status
!= ISC_R_SUCCESS
) {
266 log_error("Unable to register fd with library %s",
267 isc_result_totext(status
));
270 /* is this the cleanup we need? */
271 omapi_object_dereference(&h
->outer
, MDL
);
272 omapi_io_dereference (&obj
, MDL
);
278 /* Find the last I/O state, if there are any. */
279 for (p
= omapi_io_states
.next
;
280 p
&& p
-> next
; p
= p
-> next
)
283 omapi_io_reference (&p
-> next
, obj
, MDL
);
285 omapi_io_reference (&omapi_io_states
.next
, obj
, MDL
);
287 obj
-> readfd
= readfd
;
288 obj
-> writefd
= writefd
;
289 obj
-> reader
= reader
;
290 obj
-> writer
= writer
;
291 obj
-> reaper
= reaper
;
293 omapi_io_dereference(&obj
, MDL
);
294 return ISC_R_SUCCESS
;
298 * ReRegister an I/O handle so that we can do asynchronous I/O on it.
299 * If the handle doesn't exist we call the register routine to build it.
300 * If it does exist we change the functions associated with it, and
301 * repoke the fd code to make it happy. Neither the objects nor the
302 * fd are allowed to have changed.
305 isc_result_t
omapi_reregister_io_object (omapi_object_t
*h
,
306 int (*readfd
) (omapi_object_t
*),
307 int (*writefd
) (omapi_object_t
*),
308 isc_result_t (*reader
)
310 isc_result_t (*writer
)
312 isc_result_t (*reaper
)
315 omapi_io_object_t
*obj
;
318 if ((!h
-> outer
) || (h
-> outer
-> type
!= omapi_type_io_object
)) {
320 * If we don't have an object or if the type isn't what
321 * we expect do the normal registration (which will overwrite
322 * an incorrect type, that's what we did historically, may
323 * want to change that)
325 return (omapi_register_io_object (h
, readfd
, writefd
,
326 reader
, writer
, reaper
));
329 /* We have an io object of the correct type, try to update it */
331 /* Should we validate that the fd matches the previous one?
332 * It's suppossed to, that's a requirement, don't bother yet */
334 obj
= (omapi_io_object_t
*)h
->outer
;
336 obj
->readfd
= readfd
;
337 obj
->writefd
= writefd
;
338 obj
->reader
= reader
;
339 obj
->writer
= writer
;
340 obj
->reaper
= reaper
;
343 fd_flags
|= ISC_SOCKFDWATCH_READ
;
347 fd_flags
|= ISC_SOCKFDWATCH_WRITE
;
350 isc_socket_fdwatchpoke(obj
->fd
, fd_flags
);
352 return (ISC_R_SUCCESS
);
355 isc_result_t
omapi_unregister_io_object (omapi_object_t
*h
)
357 omapi_io_object_t
*obj
, *ph
;
359 omapi_io_object_t
*p
, *last
;
362 if (!h
-> outer
|| h
-> outer
-> type
!= omapi_type_io_object
)
363 return DHCP_R_INVALIDARG
;
364 obj
= (omapi_io_object_t
*)h
-> outer
;
365 ph
= (omapi_io_object_t
*)0;
366 omapi_io_reference (&ph
, obj
, MDL
);
370 * For now we leave this out. We can't clean up the isc socket
371 * structure cleanly yet so we need to leave the io object in place.
372 * By leaving it on the io states list we avoid it being freed.
373 * We also mark it as closed to avoid using it.
376 /* remove from the list of I/O states */
377 last
= &omapi_io_states
;
378 for (p
= omapi_io_states
.next
; p
; p
= p
-> next
) {
380 omapi_io_dereference (&last
-> next
, MDL
);
381 omapi_io_reference (&last
-> next
, p
-> next
, MDL
);
387 omapi_io_dereference (&obj
-> next
, MDL
);
391 if (obj
-> outer
-> inner
== (omapi_object_t
*)obj
)
392 omapi_object_dereference (&obj
-> outer
-> inner
,
394 omapi_object_dereference (&obj
-> outer
, MDL
);
396 omapi_object_dereference (&obj
-> inner
, MDL
);
397 omapi_object_dereference (&h
-> outer
, MDL
);
400 /* remove isc socket associations */
401 if (obj
->fd
!= NULL
) {
402 isc_socket_cancel(obj
->fd
, dhcp_gbl_ctx
.task
,
404 isc_socket_detach(&obj
->fd
);
407 obj
->closed
= ISC_TRUE
;
410 omapi_io_dereference (&ph
, MDL
);
411 return ISC_R_SUCCESS
;
414 isc_result_t
omapi_dispatch (struct timeval
*t
)
416 #ifdef DEBUG_PROTOCOL
417 log_debug("omapi_dispatch()");
419 return omapi_wait_for_completion ((omapi_object_t
*)&omapi_io_states
,
424 isc_result_t
omapi_wait_for_completion (omapi_object_t
*object
,
427 #ifdef DEBUG_PROTOCOL
429 log_debug ("omapi_wait_for_completion(%u.%u secs)",
430 (unsigned int)(t
->tv_sec
),
431 (unsigned int)(t
->tv_usec
));
433 log_debug ("omapi_wait_for_completion(no timeout)");
437 omapi_waiter_object_t
*waiter
;
438 omapi_object_t
*inner
;
441 waiter
= (omapi_waiter_object_t
*)0;
442 status
= omapi_waiter_allocate (&waiter
, MDL
);
443 if (status
!= ISC_R_SUCCESS
)
446 /* Paste the waiter object onto the inner object we're
448 for (inner
= object
; inner
-> inner
; inner
= inner
-> inner
)
451 status
= omapi_object_reference (&waiter
-> outer
, inner
, MDL
);
452 if (status
!= ISC_R_SUCCESS
) {
453 omapi_waiter_dereference (&waiter
, MDL
);
457 status
= omapi_object_reference (&inner
-> inner
,
458 (omapi_object_t
*)waiter
,
460 if (status
!= ISC_R_SUCCESS
) {
461 omapi_waiter_dereference (&waiter
, MDL
);
465 waiter
= (omapi_waiter_object_t
*)0;
468 status
= omapi_one_dispatch ((omapi_object_t
*)waiter
, t
);
469 if (status
!= ISC_R_SUCCESS
) {
470 #ifdef DEBUG_PROTOCOL
471 log_debug ("- call to omapi_one_dispatch failed: %s",
472 isc_result_totext (status
));
474 /* Break out on failure, to ensure we free up the waiter(s) */
477 } while (!waiter
|| !waiter
-> ready
);
480 if (waiter
-> outer
) {
481 if (waiter
-> outer
-> inner
) {
482 omapi_object_dereference (&waiter
-> outer
-> inner
,
485 omapi_object_reference
486 (&waiter
-> outer
-> inner
,
487 waiter
-> inner
, MDL
);
489 omapi_object_dereference (&waiter
-> outer
, MDL
);
492 omapi_object_dereference (&waiter
-> inner
, MDL
);
494 if (status
== ISC_R_SUCCESS
) {
495 /* If the invocation worked, return the server's
496 * execution status */
497 status
= waiter
-> waitstatus
;
500 omapi_waiter_dereference (&waiter
, MDL
);
504 isc_result_t
omapi_one_dispatch (omapi_object_t
*wo
,
507 #ifdef DEBUG_PROTOCOL
508 log_debug ("omapi_one_dispatch()");
510 fd_set r
, w
, x
, rr
, ww
, xx
;
514 struct timeval now
, to
;
515 omapi_io_object_t
*io
, *prev
, *next
;
516 omapi_waiter_object_t
*waiter
;
517 omapi_object_t
*tmp
= (omapi_object_t
*)0;
519 if (!wo
|| wo
-> type
!= omapi_type_waiter
)
520 waiter
= (omapi_waiter_object_t
*)0;
522 waiter
= (omapi_waiter_object_t
*)wo
;
526 /* First, see if the timeout has expired, and if so return. */
528 gettimeofday (&now
, (struct timezone
*)0);
529 cur_tv
.tv_sec
= now
.tv_sec
;
530 cur_tv
.tv_usec
= now
.tv_usec
;
531 if (now
.tv_sec
> t
-> tv_sec
||
532 (now
.tv_sec
== t
-> tv_sec
&& now
.tv_usec
>= t
-> tv_usec
))
533 return ISC_R_TIMEDOUT
;
535 /* We didn't time out, so figure out how long until
537 to
.tv_sec
= t
-> tv_sec
- now
.tv_sec
;
538 to
.tv_usec
= t
-> tv_usec
- now
.tv_usec
;
539 if (to
.tv_usec
< 0) {
540 to
.tv_usec
+= 1000000;
544 /* It is possible for the timeout to get set larger than
545 the largest time select() is willing to accept.
546 Restricting the timeout to a maximum of one day should
547 work around this. -DPN. (Ref: Bug #416) */
548 if (to
.tv_sec
> (60 * 60 * 24))
549 to
.tv_sec
= 60 * 60 * 24;
552 /* If the object we're waiting on has reached completion,
554 if (waiter
&& waiter
-> ready
)
555 return ISC_R_SUCCESS
;
558 /* If we have no I/O state, we can't proceed. */
559 if (!(io
= omapi_io_states
.next
))
562 /* Set up the read and write masks. */
566 for (; io
; io
= io
-> next
) {
567 /* Check for a read socket. If we shouldn't be
568 trying to read for this I/O object, either there
569 won't be a readfd function, or it'll return -1. */
570 if (io
-> readfd
&& io
-> inner
&&
571 (desc
= (*(io
-> readfd
)) (io
-> inner
)) >= 0) {
577 /* Same deal for write fdets. */
578 if (io
-> writefd
&& io
-> inner
&&
579 (desc
= (*(io
-> writefd
)) (io
-> inner
)) >= 0) {
580 /* This block avoids adding writefds that are already connected
581 * but that do not have data waiting to write. This avoids
582 * select() calls dropping immediately simply because the
583 * the writefd is ready to write. Without this synchronous
584 * waiting becomes CPU intensive polling */
585 if (io
->inner
&& io
->inner
->type
== omapi_type_connection
) {
586 omapi_connection_object_t
* c
;
587 c
= (omapi_connection_object_t
*)(io
->inner
);
588 if (c
->state
== omapi_connection_connected
&& c
->out_bytes
== 0) {
589 /* We are already connected and have no data waiting to
590 * be written, so we avoid registering the fd. */
591 #ifdef DEBUG_PROTOCOL
592 log_debug ("--- Connected, nothing to write, skip writefd\n");
605 /* poll if all reader are dry */
613 count
= select(max
+ 1, &r
, &w
, &x
, &now
);
616 trigger_event(&rw_queue_empty
);
617 /* Wait for a packet or a timeout... XXX */
622 #ifdef DEBUG_PROTOCOL
624 log_debug (" calling select with timout: %u.%u secs",
625 (unsigned int)(to
.tv_sec
),
626 (unsigned int)(to
.tv_usec
));
629 count
= select(max
+ 1, &r
, &w
, &x
, t
? &to
: NULL
);
632 /* Get the current time... */
633 gettimeofday (&cur_tv
, (struct timezone
*)0);
635 /* We probably have a bad file descriptor. Figure out which one.
636 When we find it, call the reaper function on it, which will
637 maybe make it go away, and then try again. */
640 omapi_io_object_t
*prev
= (omapi_io_object_t
*)0;
641 io
= (omapi_io_object_t
*)0;
642 if (omapi_io_states
.next
)
643 omapi_io_reference (&io
, omapi_io_states
.next
, MDL
);
649 t0
.tv_sec
= t0
.tv_usec
= 0;
651 if (io
-> readfd
&& io
-> inner
&&
652 (desc
= (*(io
-> readfd
)) (io
-> inner
)) >= 0) {
654 count
= select (desc
+ 1, &r
, &w
, &x
, &t0
);
657 log_error ("Bad descriptor %d.", desc
);
658 for (obj
= (omapi_object_t
*)io
;
662 for (; obj
; obj
= obj
-> inner
) {
666 ov
= (omapi_value_t
*)0;
667 omapi_get_value_str (obj
,
670 if (ov
&& ov
-> value
&&
671 (ov
-> value
-> type
==
672 omapi_datatype_string
)) {
674 ov
-> value
-> u
.buffer
.value
;
675 len
= ov
-> value
-> u
.buffer
.len
;
680 log_error ("Object %lx %s%s%.*s",
686 omapi_value_dereference (&ov
, MDL
);
688 (*(io
-> reaper
)) (io
-> inner
);
690 omapi_io_dereference (&prev
-> next
, MDL
);
692 omapi_io_reference (&prev
-> next
,
696 (&omapi_io_states
.next
, MDL
);
699 (&omapi_io_states
.next
,
702 omapi_io_dereference (&io
, MDL
);
709 t0
.tv_sec
= t0
.tv_usec
= 0;
711 /* Same deal for write fdets. */
712 if (io
-> writefd
&& io
-> inner
&&
713 (desc
= (*(io
-> writefd
)) (io
-> inner
)) >= 0) {
715 count
= select (desc
+ 1, &r
, &w
, &x
, &t0
);
720 omapi_io_dereference (&prev
, MDL
);
721 omapi_io_reference (&prev
, io
, MDL
);
722 omapi_io_dereference (&io
, MDL
);
724 omapi_io_reference (&io
, prev
-> next
, MDL
);
727 omapi_io_dereference (&prev
, MDL
);
731 for (io
= omapi_io_states
.next
; io
; io
= io
-> next
) {
734 omapi_object_reference (&tmp
, io
-> inner
, MDL
);
735 /* Check for a read descriptor, and if there is one,
736 see if we got input on that socket. */
738 (desc
= (*(io
-> readfd
)) (tmp
)) >= 0) {
739 if (FD_ISSET (desc
, &r
)) {
740 ((*(io
-> reader
)) (tmp
));
744 /* Same deal for write descriptors. */
746 (desc
= (*(io
-> writefd
)) (tmp
)) >= 0)
748 if (FD_ISSET (desc
, &w
)) {
749 ((*(io
-> writer
)) (tmp
));
752 omapi_object_dereference (&tmp
, MDL
);
755 /* Now check for I/O handles that are no longer valid,
756 and remove them from the list. */
759 if (omapi_io_states
.next
!= NULL
) {
760 omapi_io_reference(&io
, omapi_io_states
.next
, MDL
);
763 if ((io
->inner
== NULL
) ||
764 ((io
->reaper
!= NULL
) &&
765 ((io
->reaper
)(io
->inner
) != ISC_R_SUCCESS
)))
768 omapi_io_object_t
*tmp
= NULL
;
769 /* Save a reference to the next
770 pointer, if there is one. */
771 if (io
->next
!= NULL
) {
772 omapi_io_reference(&tmp
, io
->next
, MDL
);
773 omapi_io_dereference(&io
->next
, MDL
);
776 omapi_io_dereference(&prev
->next
, MDL
);
778 omapi_io_reference(&prev
->next
,
781 omapi_io_dereference(&omapi_io_states
.next
,
785 (&omapi_io_states
.next
,
794 omapi_io_dereference(&tmp
, MDL
);
799 omapi_io_dereference(&prev
, MDL
);
801 omapi_io_reference(&prev
, io
, MDL
);
807 * But using our reference counting voodoo.
810 if (io
->next
!= NULL
) {
811 omapi_io_reference(&next
, io
->next
, MDL
);
813 omapi_io_dereference(&io
, MDL
);
815 omapi_io_reference(&io
, next
, MDL
);
816 omapi_io_dereference(&next
, MDL
);
820 omapi_io_dereference(&prev
, MDL
);
823 return ISC_R_SUCCESS
;
826 isc_result_t
omapi_io_set_value (omapi_object_t
*h
,
828 omapi_data_string_t
*name
,
829 omapi_typed_data_t
*value
)
831 if (h
-> type
!= omapi_type_io_object
)
832 return DHCP_R_INVALIDARG
;
834 if (h
-> inner
&& h
-> inner
-> type
-> set_value
)
835 return (*(h
-> inner
-> type
-> set_value
))
836 (h
-> inner
, id
, name
, value
);
837 return ISC_R_NOTFOUND
;
840 isc_result_t
omapi_io_get_value (omapi_object_t
*h
,
842 omapi_data_string_t
*name
,
843 omapi_value_t
**value
)
845 if (h
-> type
!= omapi_type_io_object
)
846 return DHCP_R_INVALIDARG
;
848 if (h
-> inner
&& h
-> inner
-> type
-> get_value
)
849 return (*(h
-> inner
-> type
-> get_value
))
850 (h
-> inner
, id
, name
, value
);
851 return ISC_R_NOTFOUND
;
854 /* omapi_io_destroy (object, MDL);
856 * Find the requested IO [object] and remove it from the list of io
857 * states, causing the cleanup functions to destroy it. Note that we must
858 * hold a reference on the object while moving its ->next reference and
859 * removing the reference in the chain to the target object...otherwise it
860 * may be cleaned up from under us.
862 isc_result_t
omapi_io_destroy (omapi_object_t
*h
, const char *file
, int line
)
864 omapi_io_object_t
*obj
= NULL
, *p
, *last
= NULL
, **holder
;
866 if (h
-> type
!= omapi_type_io_object
)
867 return DHCP_R_INVALIDARG
;
869 /* remove from the list of I/O states */
870 for (p
= omapi_io_states
.next
; p
; p
= p
-> next
) {
871 if (p
== (omapi_io_object_t
*)h
) {
872 omapi_io_reference (&obj
, p
, MDL
);
875 holder
= &last
-> next
;
877 holder
= &omapi_io_states
.next
;
879 omapi_io_dereference (holder
, MDL
);
882 omapi_io_reference (holder
, obj
-> next
, MDL
);
883 omapi_io_dereference (&obj
-> next
, MDL
);
886 return omapi_io_dereference (&obj
, MDL
);
891 return ISC_R_NOTFOUND
;
894 isc_result_t
omapi_io_signal_handler (omapi_object_t
*h
,
895 const char *name
, va_list ap
)
897 #ifdef DEBUG_PROTOCOL
898 log_debug ("omapi_io_signal_handler(%s)", name
);
900 if (h
-> type
!= omapi_type_io_object
)
901 return DHCP_R_INVALIDARG
;
903 if (h
-> inner
&& h
-> inner
-> type
-> signal_handler
)
904 return (*(h
-> inner
-> type
-> signal_handler
)) (h
-> inner
,
906 return ISC_R_NOTFOUND
;
909 isc_result_t
omapi_io_stuff_values (omapi_object_t
*c
,
913 if (i
-> type
!= omapi_type_io_object
)
914 return DHCP_R_INVALIDARG
;
916 if (i
-> inner
&& i
-> inner
-> type
-> stuff_values
)
917 return (*(i
-> inner
-> type
-> stuff_values
)) (c
, id
,
919 return ISC_R_SUCCESS
;
922 isc_result_t
omapi_waiter_signal_handler (omapi_object_t
*h
,
923 const char *name
, va_list ap
)
925 omapi_waiter_object_t
*waiter
;
927 #ifdef DEBUG_PROTOCOL
928 log_debug ("omapi_waiter_signal_handler(%s)", name
);
930 if (h
-> type
!= omapi_type_waiter
)
931 return DHCP_R_INVALIDARG
;
933 if (!strcmp (name
, "ready")) {
934 waiter
= (omapi_waiter_object_t
*)h
;
936 waiter
-> waitstatus
= ISC_R_SUCCESS
;
937 return ISC_R_SUCCESS
;
940 if (!strcmp(name
, "status")) {
941 waiter
= (omapi_waiter_object_t
*)h
;
943 waiter
->waitstatus
= va_arg(ap
, isc_result_t
);
944 return ISC_R_SUCCESS
;
947 if (!strcmp (name
, "disconnect")) {
948 waiter
= (omapi_waiter_object_t
*)h
;
950 waiter
-> waitstatus
= DHCP_R_CONNRESET
;
951 return ISC_R_SUCCESS
;
954 if (h
-> inner
&& h
-> inner
-> type
-> signal_handler
)
955 return (*(h
-> inner
-> type
-> signal_handler
)) (h
-> inner
,
957 return ISC_R_NOTFOUND
;
960 /** @brief calls a given function on every object
962 * @param func function to be called
963 * @param p parameter to be passed to each function instance
965 * @return result (ISC_R_SUCCESS if successful, error code otherwise)
967 isc_result_t
omapi_io_state_foreach (isc_result_t (*func
) (omapi_object_t
*,
971 omapi_io_object_t
*io
= NULL
;
973 omapi_io_object_t
*next
= NULL
;
976 * This just calls func on every inner object on the list. It would
977 * be much simpler in general case, but one of the operations could be
978 * release of the objects. Therefore we need to ref count the io and
982 if (omapi_io_states
.next
) {
983 omapi_object_reference((omapi_object_t
**)&io
,
984 (omapi_object_t
*)omapi_io_states
.next
,
989 /* If there's a next object, save it */
991 omapi_object_reference((omapi_object_t
**)&next
,
992 (omapi_object_t
*)io
->next
, MDL
);
995 status
= (*func
) (io
->inner
, p
);
996 if (status
!= ISC_R_SUCCESS
) {
997 /* Something went wrong. Let's stop using io & next pointer
999 omapi_object_dereference((omapi_object_t
**)&io
, MDL
);
1001 omapi_object_dereference((omapi_object_t
**)&next
, MDL
);
1006 /* Update the io pointer and free the next pointer */
1007 omapi_object_dereference((omapi_object_t
**)&io
, MDL
);
1009 omapi_object_reference((omapi_object_t
**)&io
,
1010 (omapi_object_t
*)next
,
1012 omapi_object_dereference((omapi_object_t
**)&next
, MDL
);
1017 * The only way to get here is when next is NULL. There's no need
1018 * to dereference it.
1020 return ISC_R_SUCCESS
;