3 Buffer access functions for the object management protocol... */
6 * Copyright (c) 2004 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
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 * ``http://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''.
35 #include <omapip/omapip_p.h>
38 static void trace_connection_input_input (trace_type_t
*, unsigned, char *);
39 static void trace_connection_input_stop (trace_type_t
*);
40 static void trace_connection_output_input (trace_type_t
*, unsigned, char *);
41 static void trace_connection_output_stop (trace_type_t
*);
42 static trace_type_t
*trace_connection_input
;
43 static trace_type_t
*trace_connection_output
;
44 static isc_result_t
omapi_connection_reader_trace (omapi_object_t
*,
47 extern omapi_array_t
*omapi_connections
;
49 void omapi_buffer_trace_setup ()
51 trace_connection_input
=
52 trace_type_register ("connection-input",
54 trace_connection_input_input
,
55 trace_connection_input_stop
, MDL
);
56 trace_connection_output
=
57 trace_type_register ("connection-output",
59 trace_connection_output_input
,
60 trace_connection_output_stop
, MDL
);
63 static void trace_connection_input_input (trace_type_t
*ttype
,
64 unsigned length
, char *buf
)
66 unsigned left
, taken
, cc
= 0;
68 int32_t connect_index
;
70 omapi_connection_object_t
*c
= (omapi_connection_object_t
*)0;
72 memcpy (&connect_index
, buf
, sizeof connect_index
);
73 connect_index
= ntohl (connect_index
);
75 omapi_array_foreach_begin (omapi_connections
,
76 omapi_connection_object_t
, lp
) {
77 if (lp
-> index
== ntohl (connect_index
)) {
78 omapi_connection_reference (&c
, lp
, MDL
);
79 omapi_connection_dereference (&lp
, MDL
);
82 } omapi_array_foreach_end (omapi_connections
,
83 omapi_connection_object_t
, lp
);
86 log_error ("trace connection input: no connection index %ld",
87 (long int)connect_index
);
91 s
= buf
+ sizeof connect_index
;
92 left
= length
- sizeof connect_index
;
96 status
= omapi_connection_reader_trace ((omapi_object_t
*)c
,
98 if (status
!= ISC_R_SUCCESS
) {
99 log_error ("trace connection input: %s",
100 isc_result_totext (status
));
105 log_error ("trace connection_input: %s",
106 "input is not being consumed.");
115 omapi_connection_dereference (&c
, MDL
);
118 static void trace_connection_input_stop (trace_type_t
*ttype
) { }
120 static void trace_connection_output_input (trace_type_t
*ttype
,
121 unsigned length
, char *buf
)
123 /* We *could* check to see if the output is correct, but for now
124 we aren't going to do that. */
127 static void trace_connection_output_stop (trace_type_t
*ttype
) { }
131 /* Make sure that at least len bytes are in the input buffer, and if not,
132 read enough bytes to make up the difference. */
134 isc_result_t
omapi_connection_reader (omapi_object_t
*h
)
136 #if defined (TRACING)
137 return omapi_connection_reader_trace (h
, 0, (char *)0, (unsigned *)0);
140 static isc_result_t
omapi_connection_reader_trace (omapi_object_t
*h
,
143 unsigned *stuff_taken
)
146 omapi_buffer_t
*buffer
;
150 omapi_connection_object_t
*c
;
151 unsigned bytes_to_read
;
153 if (!h
|| h
-> type
!= omapi_type_connection
)
154 return ISC_R_INVALIDARG
;
155 c
= (omapi_connection_object_t
*)h
;
157 /* Make sure c -> bytes_needed is valid. */
158 if (c
-> bytes_needed
< 0)
159 return ISC_R_INVALIDARG
;
161 /* See if there are enough bytes. */
162 if (c
-> in_bytes
>= OMAPI_BUF_SIZE
- 1 &&
163 c
-> in_bytes
> c
-> bytes_needed
)
164 return ISC_R_SUCCESS
;
168 for (buffer
= c
-> inbufs
; buffer
-> next
;
169 buffer
= buffer
-> next
)
171 if (!BUFFER_BYTES_FREE (buffer
)) {
172 status
= omapi_buffer_new (&buffer
-> next
, MDL
);
173 if (status
!= ISC_R_SUCCESS
)
175 buffer
= buffer
-> next
;
178 status
= omapi_buffer_new (&c
-> inbufs
, MDL
);
179 if (status
!= ISC_R_SUCCESS
)
181 buffer
= c
-> inbufs
;
184 bytes_to_read
= BUFFER_BYTES_FREE (buffer
);
186 while (bytes_to_read
) {
187 if (buffer
-> tail
> buffer
-> head
)
188 read_len
= sizeof (buffer
-> buf
) - buffer
-> tail
;
190 read_len
= buffer
-> head
- buffer
-> tail
;
192 #if defined (TRACING)
193 if (trace_playback()) {
195 if (read_len
> stuff_len
)
196 read_len
= stuff_len
;
198 *stuff_taken
+= read_len
;
199 memcpy (&buffer
-> buf
[buffer
-> tail
],
200 stuff_buf
, read_len
);
201 stuff_len
-= read_len
;
202 stuff_buf
+= read_len
;
203 read_status
= read_len
;
210 read_status
= recv (c
-> socket
,
211 &buffer
-> buf
[buffer
-> tail
],
214 if (read_status
< 0) {
215 if (errno
== EWOULDBLOCK
)
217 else if (errno
== EIO
)
218 return ISC_R_IOERROR
;
219 else if (errno
== EINVAL
)
220 return ISC_R_INVALIDARG
;
221 else if (errno
== ECONNRESET
) {
222 omapi_disconnect (h
, 1);
223 return ISC_R_SHUTTINGDOWN
;
225 return ISC_R_UNEXPECTED
;
228 /* If we got a zero-length read, as opposed to EWOULDBLOCK,
229 the remote end closed the connection. */
230 if (read_status
== 0) {
231 omapi_disconnect (h
, 0);
232 return ISC_R_SHUTTINGDOWN
;
234 #if defined (TRACING)
235 if (trace_record ()) {
237 int32_t connect_index
;
239 connect_index
= htonl (c
-> index
);
241 iov
[0].buf
= (char *)&connect_index
;
242 iov
[0].len
= sizeof connect_index
;
243 iov
[1].buf
= &buffer
-> buf
[buffer
-> tail
];
244 iov
[1].len
= read_status
;
246 status
= (trace_write_packet_iov
247 (trace_connection_input
, 2, iov
, MDL
));
248 if (status
!= ISC_R_SUCCESS
) {
250 log_error ("trace connection input: %s",
251 isc_result_totext (status
));
255 buffer
-> tail
+= read_status
;
256 c
-> in_bytes
+= read_status
;
257 if (buffer
-> tail
== sizeof buffer
-> buf
)
259 if (read_status
< read_len
)
261 bytes_to_read
-= read_status
;
264 if (c
-> bytes_needed
<= c
-> in_bytes
) {
265 omapi_signal (h
, "ready", c
);
267 return ISC_R_SUCCESS
;
270 /* Put some bytes into the output buffer for a connection. */
272 isc_result_t
omapi_connection_copyin (omapi_object_t
*h
,
273 const unsigned char *bufp
,
276 omapi_buffer_t
*buffer
;
278 int bytes_copied
= 0;
280 int sig_flags
= SIG_MODE_UPDATE
;
281 omapi_connection_object_t
*c
;
283 /* Make sure len is valid. */
285 return ISC_R_INVALIDARG
;
286 if (!h
|| h
-> type
!= omapi_type_connection
)
287 return ISC_R_INVALIDARG
;
288 c
= (omapi_connection_object_t
*)h
;
290 /* If the connection is closed, return an error if the caller
292 if (c
-> state
== omapi_connection_disconnecting
||
293 c
-> state
== omapi_connection_closed
)
294 return ISC_R_NOTCONNECTED
;
297 for (buffer
= c
-> outbufs
;
298 buffer
-> next
; buffer
= buffer
-> next
)
301 status
= omapi_buffer_new (&c
-> outbufs
, MDL
);
302 if (status
!= ISC_R_SUCCESS
)
304 buffer
= c
-> outbufs
;
307 while (bytes_copied
< len
) {
308 /* If there is no space available in this buffer,
309 allocate a new one. */
310 if (!BUFFER_BYTES_FREE (buffer
)) {
311 status
= (omapi_buffer_new (&buffer
-> next
, MDL
));
312 if (status
!= ISC_R_SUCCESS
)
314 buffer
= buffer
-> next
;
317 if (buffer
-> tail
> buffer
-> head
)
318 copy_len
= sizeof (buffer
-> buf
) - buffer
-> tail
;
320 copy_len
= buffer
-> head
- buffer
-> tail
;
322 if (copy_len
> (len
- bytes_copied
))
323 copy_len
= len
- bytes_copied
;
326 if (!c
-> out_context
)
327 sig_flags
|= SIG_MODE_INIT
;
328 status
= omapi_connection_sign_data
329 (sig_flags
, c
-> out_key
, &c
-> out_context
,
330 &bufp
[bytes_copied
], copy_len
,
331 (omapi_typed_data_t
**)0);
332 if (status
!= ISC_R_SUCCESS
)
336 memcpy (&buffer
-> buf
[buffer
-> tail
],
337 &bufp
[bytes_copied
], copy_len
);
338 buffer
-> tail
+= copy_len
;
339 c
-> out_bytes
+= copy_len
;
340 bytes_copied
+= copy_len
;
341 if (buffer
-> tail
== sizeof buffer
-> buf
)
344 return ISC_R_SUCCESS
;
347 /* Copy some bytes from the input buffer, and advance the input buffer
348 pointer beyond the bytes copied out. */
350 isc_result_t
omapi_connection_copyout (unsigned char *buf
,
354 unsigned bytes_remaining
;
355 unsigned bytes_this_copy
;
357 omapi_buffer_t
*buffer
;
359 int sig_flags
= SIG_MODE_UPDATE
;
360 omapi_connection_object_t
*c
;
363 if (!h
|| h
-> type
!= omapi_type_connection
)
364 return ISC_R_INVALIDARG
;
365 c
= (omapi_connection_object_t
*)h
;
367 if (size
> c
-> in_bytes
)
370 bytes_remaining
= size
;
371 buffer
= c
-> inbufs
;
373 while (bytes_remaining
) {
375 return ISC_R_UNEXPECTED
;
376 if (BYTES_IN_BUFFER (buffer
)) {
377 if (buffer
-> head
== (sizeof buffer
-> buf
) - 1)
380 first_byte
= buffer
-> head
+ 1;
382 if (first_byte
> buffer
-> tail
) {
383 bytes_this_copy
= (sizeof buffer
-> buf
-
387 buffer
-> tail
- first_byte
;
389 if (bytes_this_copy
> bytes_remaining
)
390 bytes_this_copy
= bytes_remaining
;
393 if (!c
-> in_context
)
394 sig_flags
|= SIG_MODE_INIT
;
395 status
= omapi_connection_sign_data
400 &buffer
-> buf
[first_byte
],
402 (omapi_typed_data_t
**)0);
403 if (status
!= ISC_R_SUCCESS
)
407 memcpy (bufp
, &buffer
-> buf
[first_byte
],
409 bufp
+= bytes_this_copy
;
411 bytes_remaining
-= bytes_this_copy
;
412 buffer
-> head
= first_byte
+ bytes_this_copy
- 1;
413 c
-> in_bytes
-= bytes_this_copy
;
416 if (!BYTES_IN_BUFFER (buffer
))
417 buffer
= buffer
-> next
;
420 /* Get rid of any input buffers that we emptied. */
421 buffer
= (omapi_buffer_t
*)0;
422 while (c
-> inbufs
&&
423 !BYTES_IN_BUFFER (c
-> inbufs
)) {
424 if (c
-> inbufs
-> next
) {
425 omapi_buffer_reference (&buffer
,
426 c
-> inbufs
-> next
, MDL
);
427 omapi_buffer_dereference (&c
-> inbufs
-> next
, MDL
);
429 omapi_buffer_dereference (&c
-> inbufs
, MDL
);
431 omapi_buffer_reference
432 (&c
-> inbufs
, buffer
, MDL
);
433 omapi_buffer_dereference (&buffer
, MDL
);
436 return ISC_R_SUCCESS
;
439 isc_result_t
omapi_connection_writer (omapi_object_t
*h
)
441 unsigned bytes_this_write
;
444 omapi_buffer_t
*buffer
;
445 // unsigned char *bufp;
446 omapi_connection_object_t
*c
;
449 if (!h
|| h
-> type
!= omapi_type_connection
)
450 return ISC_R_INVALIDARG
;
451 c
= (omapi_connection_object_t
*)h
;
453 /* Already flushed... */
455 return ISC_R_SUCCESS
;
457 buffer
= c
-> outbufs
;
459 while (c
-> out_bytes
) {
461 return ISC_R_UNEXPECTED
;
462 if (BYTES_IN_BUFFER (buffer
)) {
463 if (buffer
-> head
== (sizeof buffer
-> buf
) - 1)
466 first_byte
= buffer
-> head
+ 1;
468 if (first_byte
> buffer
-> tail
) {
469 bytes_this_write
= (sizeof buffer
-> buf
-
473 buffer
-> tail
- first_byte
;
475 bytes_written
= send (c
-> socket
,
476 &buffer
-> buf
[first_byte
],
477 bytes_this_write
, 0);
478 /* If the write failed with EWOULDBLOCK or we wrote
479 zero bytes, a further write would block, so we have
480 flushed as much as we can for now. Other errors
481 are really errors. */
482 if (bytes_written
< 0) {
483 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
484 return ISC_R_SUCCESS
;
485 else if (errno
== EPIPE
)
488 else if (errno
== EFBIG
|| errno
== EDQUOT
)
490 else if (errno
== EFBIG
)
492 return ISC_R_NORESOURCES
;
493 else if (errno
== ENOSPC
)
494 return ISC_R_NOSPACE
;
495 else if (errno
== EIO
)
496 return ISC_R_IOERROR
;
497 else if (errno
== EINVAL
)
498 return ISC_R_INVALIDARG
;
499 else if (errno
== ECONNRESET
)
500 return ISC_R_SHUTTINGDOWN
;
502 return ISC_R_UNEXPECTED
;
504 if (bytes_written
== 0)
505 return ISC_R_SUCCESS
;
507 #if defined (TRACING)
508 if (trace_record ()) {
510 int32_t connect_index
;
512 connect_index
= htonl (c
-> index
);
514 iov
[0].buf
= (char *)&connect_index
;
515 iov
[0].len
= sizeof connect_index
;
516 iov
[1].buf
= &buffer
-> buf
[buffer
-> tail
];
517 iov
[1].len
= bytes_written
;
519 status
= (trace_write_packet_iov
520 (trace_connection_input
, 2, iov
,
522 if (status
!= ISC_R_SUCCESS
) {
524 log_error ("trace %s output: %s",
526 isc_result_totext (status
));
531 buffer
-> head
= first_byte
+ bytes_written
- 1;
532 c
-> out_bytes
-= bytes_written
;
534 /* If we didn't finish out the write, we filled the
535 O.S. output buffer and a further write would block,
536 so stop trying to flush now. */
537 if (bytes_written
!= bytes_this_write
)
538 return ISC_R_SUCCESS
;
541 if (!BYTES_IN_BUFFER (buffer
))
542 buffer
= buffer
-> next
;
545 /* Get rid of any output buffers we emptied. */
546 buffer
= (omapi_buffer_t
*)0;
547 while (c
-> outbufs
&&
548 !BYTES_IN_BUFFER (c
-> outbufs
)) {
549 if (c
-> outbufs
-> next
) {
550 omapi_buffer_reference (&buffer
,
551 c
-> outbufs
-> next
, MDL
);
552 omapi_buffer_dereference (&c
-> outbufs
-> next
, MDL
);
554 omapi_buffer_dereference (&c
-> outbufs
, MDL
);
556 omapi_buffer_reference (&c
-> outbufs
, buffer
, MDL
);
557 omapi_buffer_dereference (&buffer
, MDL
);
560 return ISC_R_SUCCESS
;
563 isc_result_t
omapi_connection_get_uint32 (omapi_object_t
*c
,
569 status
= omapi_connection_copyout ((unsigned char *)&inbuf
,
571 if (status
!= ISC_R_SUCCESS
)
574 *result
= ntohl (inbuf
);
575 return ISC_R_SUCCESS
;
578 isc_result_t
omapi_connection_put_uint32 (omapi_object_t
*c
,
582 // isc_result_t status;
584 inbuf
= htonl (value
);
586 return omapi_connection_copyin (c
, (unsigned char *)&inbuf
,
590 isc_result_t
omapi_connection_get_uint16 (omapi_object_t
*c
,
596 status
= omapi_connection_copyout ((unsigned char *)&inbuf
,
598 if (status
!= ISC_R_SUCCESS
)
601 *result
= ntohs (inbuf
);
602 return ISC_R_SUCCESS
;
605 isc_result_t
omapi_connection_put_uint16 (omapi_object_t
*c
,
609 // isc_result_t status;
611 inbuf
= htons (value
);
613 return omapi_connection_copyin (c
, (unsigned char *)&inbuf
,
617 isc_result_t
omapi_connection_write_typed_data (omapi_object_t
*c
,
618 omapi_typed_data_t
*data
)
621 omapi_handle_t handle
;
623 /* Null data is valid. */
625 return omapi_connection_put_uint32 (c
, 0);
627 switch (data
-> type
) {
628 case omapi_datatype_int
:
629 status
= omapi_connection_put_uint32 (c
, sizeof (u_int32_t
));
630 if (status
!= ISC_R_SUCCESS
)
632 return omapi_connection_put_uint32 (c
, ((u_int32_t
)
633 (data
-> u
.integer
)));
635 case omapi_datatype_string
:
636 case omapi_datatype_data
:
637 status
= omapi_connection_put_uint32 (c
, data
-> u
.buffer
.len
);
638 if (status
!= ISC_R_SUCCESS
)
640 if (data
-> u
.buffer
.len
)
641 return omapi_connection_copyin
642 (c
, data
-> u
.buffer
.value
,
643 data
-> u
.buffer
.len
);
644 return ISC_R_SUCCESS
;
646 case omapi_datatype_object
:
647 if (data
-> u
.object
) {
648 status
= omapi_object_handle (&handle
,
650 if (status
!= ISC_R_SUCCESS
)
654 status
= omapi_connection_put_uint32 (c
, sizeof handle
);
655 if (status
!= ISC_R_SUCCESS
)
657 return omapi_connection_put_uint32 (c
, handle
);
660 return ISC_R_INVALIDARG
;
663 isc_result_t
omapi_connection_put_name (omapi_object_t
*c
, const char *name
)
666 unsigned len
= strlen (name
);
668 status
= omapi_connection_put_uint16 (c
, len
);
669 if (status
!= ISC_R_SUCCESS
)
671 return omapi_connection_copyin (c
, (const unsigned char *)name
, len
);
674 isc_result_t
omapi_connection_put_string (omapi_object_t
*c
,
681 len
= strlen (string
);
685 status
= omapi_connection_put_uint32 (c
, len
);
686 if (status
!= ISC_R_SUCCESS
)
689 return omapi_connection_copyin
690 (c
, (const unsigned char *)string
, len
);
691 return ISC_R_SUCCESS
;
694 isc_result_t
omapi_connection_put_handle (omapi_object_t
*c
, omapi_object_t
*h
)
697 omapi_handle_t handle
;
700 status
= omapi_object_handle (&handle
, h
);
701 if (status
!= ISC_R_SUCCESS
)
704 handle
= 0; /* The null handle. */
705 status
= omapi_connection_put_uint32 (c
, sizeof handle
);
706 if (status
!= ISC_R_SUCCESS
)
708 return omapi_connection_put_uint32 (c
, handle
);