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
= read (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 omapi_connection_object_t
*c
;
448 if (!h
|| h
-> type
!= omapi_type_connection
)
449 return ISC_R_INVALIDARG
;
450 c
= (omapi_connection_object_t
*)h
;
452 /* Already flushed... */
454 return ISC_R_SUCCESS
;
456 buffer
= c
-> outbufs
;
458 while (c
-> out_bytes
) {
460 return ISC_R_UNEXPECTED
;
461 if (BYTES_IN_BUFFER (buffer
)) {
462 if (buffer
-> head
== (sizeof buffer
-> buf
) - 1)
465 first_byte
= buffer
-> head
+ 1;
467 if (first_byte
> buffer
-> tail
) {
468 bytes_this_write
= (sizeof buffer
-> buf
-
472 buffer
-> tail
- first_byte
;
474 bytes_written
= write (c
-> socket
,
475 &buffer
-> buf
[first_byte
],
477 /* If the write failed with EWOULDBLOCK or we wrote
478 zero bytes, a further write would block, so we have
479 flushed as much as we can for now. Other errors
480 are really errors. */
481 if (bytes_written
< 0) {
482 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
483 return ISC_R_SUCCESS
;
484 else if (errno
== EPIPE
)
487 else if (errno
== EFBIG
|| errno
== EDQUOT
)
489 else if (errno
== EFBIG
)
491 return ISC_R_NORESOURCES
;
492 else if (errno
== ENOSPC
)
493 return ISC_R_NOSPACE
;
494 else if (errno
== EIO
)
495 return ISC_R_IOERROR
;
496 else if (errno
== EINVAL
)
497 return ISC_R_INVALIDARG
;
498 else if (errno
== ECONNRESET
)
499 return ISC_R_SHUTTINGDOWN
;
501 return ISC_R_UNEXPECTED
;
503 if (bytes_written
== 0)
504 return ISC_R_SUCCESS
;
506 #if defined (TRACING)
507 if (trace_record ()) {
509 int32_t connect_index
;
511 connect_index
= htonl (c
-> index
);
513 iov
[0].buf
= (char *)&connect_index
;
514 iov
[0].len
= sizeof connect_index
;
515 iov
[1].buf
= &buffer
-> buf
[buffer
-> tail
];
516 iov
[1].len
= bytes_written
;
518 status
= (trace_write_packet_iov
519 (trace_connection_input
, 2, iov
,
521 if (status
!= ISC_R_SUCCESS
) {
523 log_error ("trace %s output: %s",
525 isc_result_totext (status
));
530 buffer
-> head
= first_byte
+ bytes_written
- 1;
531 c
-> out_bytes
-= bytes_written
;
533 /* If we didn't finish out the write, we filled the
534 O.S. output buffer and a further write would block,
535 so stop trying to flush now. */
536 if (bytes_written
!= bytes_this_write
)
537 return ISC_R_SUCCESS
;
540 if (!BYTES_IN_BUFFER (buffer
))
541 buffer
= buffer
-> next
;
544 /* Get rid of any output buffers we emptied. */
545 buffer
= (omapi_buffer_t
*)0;
546 while (c
-> outbufs
&&
547 !BYTES_IN_BUFFER (c
-> outbufs
)) {
548 if (c
-> outbufs
-> next
) {
549 omapi_buffer_reference (&buffer
,
550 c
-> outbufs
-> next
, MDL
);
551 omapi_buffer_dereference (&c
-> outbufs
-> next
, MDL
);
553 omapi_buffer_dereference (&c
-> outbufs
, MDL
);
555 omapi_buffer_reference (&c
-> outbufs
, buffer
, MDL
);
556 omapi_buffer_dereference (&buffer
, MDL
);
559 return ISC_R_SUCCESS
;
562 isc_result_t
omapi_connection_get_uint32 (omapi_object_t
*c
,
568 status
= omapi_connection_copyout ((unsigned char *)&inbuf
,
570 if (status
!= ISC_R_SUCCESS
)
573 *result
= ntohl (inbuf
);
574 return ISC_R_SUCCESS
;
577 isc_result_t
omapi_connection_put_uint32 (omapi_object_t
*c
,
582 inbuf
= htonl (value
);
584 return omapi_connection_copyin (c
, (unsigned char *)&inbuf
,
588 isc_result_t
omapi_connection_get_uint16 (omapi_object_t
*c
,
594 status
= omapi_connection_copyout ((unsigned char *)&inbuf
,
596 if (status
!= ISC_R_SUCCESS
)
599 *result
= ntohs (inbuf
);
600 return ISC_R_SUCCESS
;
603 isc_result_t
omapi_connection_put_uint16 (omapi_object_t
*c
,
608 inbuf
= htons (value
);
610 return omapi_connection_copyin (c
, (unsigned char *)&inbuf
,
614 isc_result_t
omapi_connection_write_typed_data (omapi_object_t
*c
,
615 omapi_typed_data_t
*data
)
618 omapi_handle_t handle
;
620 /* Null data is valid. */
622 return omapi_connection_put_uint32 (c
, 0);
624 switch (data
-> type
) {
625 case omapi_datatype_int
:
626 status
= omapi_connection_put_uint32 (c
, sizeof (u_int32_t
));
627 if (status
!= ISC_R_SUCCESS
)
629 return omapi_connection_put_uint32 (c
, ((u_int32_t
)
630 (data
-> u
.integer
)));
632 case omapi_datatype_string
:
633 case omapi_datatype_data
:
634 status
= omapi_connection_put_uint32 (c
, data
-> u
.buffer
.len
);
635 if (status
!= ISC_R_SUCCESS
)
637 if (data
-> u
.buffer
.len
)
638 return omapi_connection_copyin
639 (c
, data
-> u
.buffer
.value
,
640 data
-> u
.buffer
.len
);
641 return ISC_R_SUCCESS
;
643 case omapi_datatype_object
:
644 if (data
-> u
.object
) {
645 status
= omapi_object_handle (&handle
,
647 if (status
!= ISC_R_SUCCESS
)
651 status
= omapi_connection_put_uint32 (c
, sizeof handle
);
652 if (status
!= ISC_R_SUCCESS
)
654 return omapi_connection_put_uint32 (c
, handle
);
657 return ISC_R_INVALIDARG
;
660 isc_result_t
omapi_connection_put_name (omapi_object_t
*c
, const char *name
)
663 unsigned len
= strlen (name
);
665 status
= omapi_connection_put_uint16 (c
, len
);
666 if (status
!= ISC_R_SUCCESS
)
668 return omapi_connection_copyin (c
, (const unsigned char *)name
, len
);
671 isc_result_t
omapi_connection_put_string (omapi_object_t
*c
,
678 len
= strlen (string
);
682 status
= omapi_connection_put_uint32 (c
, len
);
683 if (status
!= ISC_R_SUCCESS
)
686 return omapi_connection_copyin
687 (c
, (const unsigned char *)string
, len
);
688 return ISC_R_SUCCESS
;
691 isc_result_t
omapi_connection_put_handle (omapi_object_t
*c
, omapi_object_t
*h
)
694 omapi_handle_t handle
;
697 status
= omapi_object_handle (&handle
, h
);
698 if (status
!= ISC_R_SUCCESS
)
701 handle
= 0; /* The null handle. */
702 status
= omapi_connection_put_uint32 (c
, sizeof handle
);
703 if (status
!= ISC_R_SUCCESS
)
705 return omapi_connection_put_uint32 (c
, handle
);