3 Buffer access functions for the object management protocol... */
6 * Copyright (c) 1999-2001 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
44 #include <omapip/omapip_p.h>
47 static void trace_connection_input_input (trace_type_t *, unsigned, char *);
48 static void trace_connection_input_stop (trace_type_t *);
49 static void trace_connection_output_input (trace_type_t *, unsigned, char *);
50 static void trace_connection_output_stop (trace_type_t *);
51 static trace_type_t *trace_connection_input;
52 static trace_type_t *trace_connection_output;
53 static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
56 extern omapi_array_t *omapi_connections;
58 void omapi_buffer_trace_setup ()
60 trace_connection_input =
61 trace_type_register ("connection-input",
63 trace_connection_input_input,
64 trace_connection_input_stop, MDL);
65 trace_connection_output =
66 trace_type_register ("connection-output",
68 trace_connection_output_input,
69 trace_connection_output_stop, MDL);
72 static void trace_connection_input_input (trace_type_t *ttype,
73 unsigned length, char *buf)
75 unsigned left, taken, cc = 0;
77 int32_t connect_index;
79 omapi_connection_object_t *c = (omapi_connection_object_t *)0;
81 memcpy (&connect_index, buf, sizeof connect_index);
82 connect_index = ntohl (connect_index);
84 omapi_array_foreach_begin (omapi_connections,
85 omapi_connection_object_t, lp) {
86 if (lp -> index == ntohl (connect_index)) {
87 omapi_connection_reference (&c, lp, MDL);
88 omapi_connection_dereference (&lp, MDL);
91 } omapi_array_foreach_end (omapi_connections,
92 omapi_connection_object_t, lp);
95 log_error ("trace connection input: no connection index %ld",
96 (long int)connect_index);
100 s = buf + sizeof connect_index;
101 left = length - sizeof connect_index;
105 status = omapi_connection_reader_trace ((omapi_object_t *)c,
107 if (status != ISC_R_SUCCESS) {
108 log_error ("trace connection input: %s",
109 isc_result_totext (status));
114 log_error ("trace connection_input: %s",
115 "input is not being consumed.");
124 omapi_connection_dereference (&c, MDL);
127 static void trace_connection_input_stop (trace_type_t *ttype) { }
129 static void trace_connection_output_input (trace_type_t *ttype,
130 unsigned length, char *buf)
132 /* We *could* check to see if the output is correct, but for now
133 we aren't going to do that. */
136 static void trace_connection_output_stop (trace_type_t *ttype) { }
140 /* Make sure that at least len bytes are in the input buffer, and if not,
141 read enough bytes to make up the difference. */
143 isc_result_t omapi_connection_reader (omapi_object_t *h)
145 #if defined (TRACING)
146 return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
149 static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
152 unsigned *stuff_taken)
155 omapi_buffer_t *buffer;
159 omapi_connection_object_t *c;
160 unsigned bytes_to_read;
162 if (!h || h -> type != omapi_type_connection)
163 return ISC_R_INVALIDARG;
164 c = (omapi_connection_object_t *)h;
166 /* Make sure c -> bytes_needed is valid. */
167 if (c -> bytes_needed < 0)
168 return ISC_R_INVALIDARG;
170 /* See if there are enough bytes. */
171 if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
172 c -> in_bytes > c -> bytes_needed)
173 return ISC_R_SUCCESS;
177 for (buffer = c -> inbufs; buffer -> next;
178 buffer = buffer -> next)
180 if (!BUFFER_BYTES_FREE (buffer)) {
181 status = omapi_buffer_new (&buffer -> next, MDL);
182 if (status != ISC_R_SUCCESS)
184 buffer = buffer -> next;
187 status = omapi_buffer_new (&c -> inbufs, MDL);
188 if (status != ISC_R_SUCCESS)
190 buffer = c -> inbufs;
193 bytes_to_read = BUFFER_BYTES_FREE (buffer);
195 while (bytes_to_read) {
196 if (buffer -> tail > buffer -> head)
197 read_len = sizeof (buffer -> buf) - buffer -> tail;
199 read_len = buffer -> head - buffer -> tail;
201 #if defined (TRACING)
202 if (trace_playback()) {
204 if (read_len > stuff_len)
205 read_len = stuff_len;
207 *stuff_taken += read_len;
208 memcpy (&buffer -> buf [buffer -> tail],
209 stuff_buf, read_len);
210 stuff_len -= read_len;
211 stuff_buf += read_len;
212 read_status = read_len;
219 read_status = read (c -> socket,
220 &buffer -> buf [buffer -> tail],
223 if (read_status < 0) {
224 if (errno == EWOULDBLOCK)
226 else if (errno == EIO)
227 return ISC_R_IOERROR;
228 else if (errno == EINVAL)
229 return ISC_R_INVALIDARG;
230 else if (errno == ECONNRESET) {
231 omapi_disconnect (h, 1);
232 return ISC_R_SHUTTINGDOWN;
234 return ISC_R_UNEXPECTED;
237 /* If we got a zero-length read, as opposed to EWOULDBLOCK,
238 the remote end closed the connection. */
239 if (read_status == 0) {
240 omapi_disconnect (h, 0);
241 return ISC_R_SHUTTINGDOWN;
243 #if defined (TRACING)
244 if (trace_record ()) {
246 int32_t connect_index;
248 connect_index = htonl (c -> index);
250 iov [0].buf = (char *)&connect_index;
251 iov [0].len = sizeof connect_index;
252 iov [1].buf = &buffer -> buf [buffer -> tail];
253 iov [1].len = read_status;
255 status = (trace_write_packet_iov
256 (trace_connection_input, 2, iov, MDL));
257 if (status != ISC_R_SUCCESS) {
259 log_error ("trace connection input: %s",
260 isc_result_totext (status));
264 buffer -> tail += read_status;
265 c -> in_bytes += read_status;
266 if (buffer -> tail == sizeof buffer -> buf)
268 if (read_status < read_len)
270 bytes_to_read -= read_status;
273 if (c -> bytes_needed <= c -> in_bytes) {
274 omapi_signal (h, "ready", c);
276 return ISC_R_SUCCESS;
279 /* Put some bytes into the output buffer for a connection. */
281 isc_result_t omapi_connection_copyin (omapi_object_t *h,
282 const unsigned char *bufp,
285 omapi_buffer_t *buffer;
287 int bytes_copied = 0;
289 int sig_flags = SIG_MODE_UPDATE;
290 omapi_connection_object_t *c;
292 /* Make sure len is valid. */
294 return ISC_R_INVALIDARG;
295 if (!h || h -> type != omapi_type_connection)
296 return ISC_R_INVALIDARG;
297 c = (omapi_connection_object_t *)h;
299 /* If the connection is closed, return an error if the caller
301 if (c -> state == omapi_connection_disconnecting ||
302 c -> state == omapi_connection_closed)
303 return ISC_R_NOTCONNECTED;
306 for (buffer = c -> outbufs;
307 buffer -> next; buffer = buffer -> next)
310 status = omapi_buffer_new (&c -> outbufs, MDL);
311 if (status != ISC_R_SUCCESS)
313 buffer = c -> outbufs;
316 while (bytes_copied < len) {
317 /* If there is no space available in this buffer,
318 allocate a new one. */
319 if (!BUFFER_BYTES_FREE (buffer)) {
320 status = (omapi_buffer_new (&buffer -> next, MDL));
321 if (status != ISC_R_SUCCESS)
323 buffer = buffer -> next;
326 if (buffer -> tail > buffer -> head)
327 copy_len = sizeof (buffer -> buf) - buffer -> tail;
329 copy_len = buffer -> head - buffer -> tail;
331 if (copy_len > (len - bytes_copied))
332 copy_len = len - bytes_copied;
335 if (!c -> out_context)
336 sig_flags |= SIG_MODE_INIT;
337 status = omapi_connection_sign_data
338 (sig_flags, c -> out_key, &c -> out_context,
339 &bufp [bytes_copied], copy_len,
340 (omapi_typed_data_t **)0);
341 if (status != ISC_R_SUCCESS)
345 memcpy (&buffer -> buf [buffer -> tail],
346 &bufp [bytes_copied], copy_len);
347 buffer -> tail += copy_len;
348 c -> out_bytes += copy_len;
349 bytes_copied += copy_len;
350 if (buffer -> tail == sizeof buffer -> buf)
353 return ISC_R_SUCCESS;
356 /* Copy some bytes from the input buffer, and advance the input buffer
357 pointer beyond the bytes copied out. */
359 isc_result_t omapi_connection_copyout (unsigned char *buf,
363 unsigned bytes_remaining;
364 unsigned bytes_this_copy;
366 omapi_buffer_t *buffer;
368 int sig_flags = SIG_MODE_UPDATE;
369 omapi_connection_object_t *c;
372 if (!h || h -> type != omapi_type_connection)
373 return ISC_R_INVALIDARG;
374 c = (omapi_connection_object_t *)h;
376 if (size > c -> in_bytes)
379 bytes_remaining = size;
380 buffer = c -> inbufs;
382 while (bytes_remaining) {
384 return ISC_R_UNEXPECTED;
385 if (BYTES_IN_BUFFER (buffer)) {
386 if (buffer -> head == (sizeof buffer -> buf) - 1)
389 first_byte = buffer -> head + 1;
391 if (first_byte > buffer -> tail) {
392 bytes_this_copy = (sizeof buffer -> buf -
396 buffer -> tail - first_byte;
398 if (bytes_this_copy > bytes_remaining)
399 bytes_this_copy = bytes_remaining;
402 if (!c -> in_context)
403 sig_flags |= SIG_MODE_INIT;
404 status = omapi_connection_sign_data
409 &buffer -> buf [first_byte],
411 (omapi_typed_data_t **)0);
412 if (status != ISC_R_SUCCESS)
416 memcpy (bufp, &buffer -> buf [first_byte],
418 bufp += bytes_this_copy;
420 bytes_remaining -= bytes_this_copy;
421 buffer -> head = first_byte + bytes_this_copy - 1;
422 c -> in_bytes -= bytes_this_copy;
425 if (!BYTES_IN_BUFFER (buffer))
426 buffer = buffer -> next;
429 /* Get rid of any input buffers that we emptied. */
430 buffer = (omapi_buffer_t *)0;
431 while (c -> inbufs &&
432 !BYTES_IN_BUFFER (c -> inbufs)) {
433 if (c -> inbufs -> next) {
434 omapi_buffer_reference (&buffer,
435 c -> inbufs -> next, MDL);
436 omapi_buffer_dereference (&c -> inbufs -> next, MDL);
438 omapi_buffer_dereference (&c -> inbufs, MDL);
440 omapi_buffer_reference
441 (&c -> inbufs, buffer, MDL);
442 omapi_buffer_dereference (&buffer, MDL);
445 return ISC_R_SUCCESS;
448 isc_result_t omapi_connection_writer (omapi_object_t *h)
450 unsigned bytes_this_write;
453 omapi_buffer_t *buffer;
455 omapi_connection_object_t *c;
458 if (!h || h -> type != omapi_type_connection)
459 return ISC_R_INVALIDARG;
460 c = (omapi_connection_object_t *)h;
462 /* Already flushed... */
464 return ISC_R_SUCCESS;
466 buffer = c -> outbufs;
468 while (c -> out_bytes) {
470 return ISC_R_UNEXPECTED;
471 if (BYTES_IN_BUFFER (buffer)) {
472 if (buffer -> head == (sizeof buffer -> buf) - 1)
475 first_byte = buffer -> head + 1;
477 if (first_byte > buffer -> tail) {
478 bytes_this_write = (sizeof buffer -> buf -
482 buffer -> tail - first_byte;
484 bytes_written = write (c -> socket,
485 &buffer -> buf [first_byte],
487 /* If the write failed with EWOULDBLOCK or we wrote
488 zero bytes, a further write would block, so we have
489 flushed as much as we can for now. Other errors
490 are really errors. */
491 if (bytes_written < 0) {
492 if (errno == EWOULDBLOCK || errno == EAGAIN)
493 return ISC_R_SUCCESS;
494 else if (errno == EPIPE)
497 else if (errno == EFBIG || errno == EDQUOT)
499 else if (errno == EFBIG)
501 return ISC_R_NORESOURCES;
502 else if (errno == ENOSPC)
503 return ISC_R_NOSPACE;
504 else if (errno == EIO)
505 return ISC_R_IOERROR;
506 else if (errno == EINVAL)
507 return ISC_R_INVALIDARG;
508 else if (errno == ECONNRESET)
509 return ISC_R_SHUTTINGDOWN;
511 return ISC_R_UNEXPECTED;
513 if (bytes_written == 0)
514 return ISC_R_SUCCESS;
516 #if defined (TRACING)
517 if (trace_record ()) {
519 int32_t connect_index;
521 connect_index = htonl (c -> index);
523 iov [0].buf = (char *)&connect_index;
524 iov [0].len = sizeof connect_index;
525 iov [1].buf = &buffer -> buf [buffer -> tail];
526 iov [1].len = bytes_written;
528 status = (trace_write_packet_iov
529 (trace_connection_input, 2, iov,
531 if (status != ISC_R_SUCCESS) {
533 log_error ("trace %s output: %s",
535 isc_result_totext (status));
540 buffer -> head = first_byte + bytes_written - 1;
541 c -> out_bytes -= bytes_written;
543 /* If we didn't finish out the write, we filled the
544 O.S. output buffer and a further write would block,
545 so stop trying to flush now. */
546 if (bytes_written != bytes_this_write)
547 return ISC_R_SUCCESS;
550 if (!BYTES_IN_BUFFER (buffer))
551 buffer = buffer -> next;
554 /* Get rid of any output buffers we emptied. */
555 buffer = (omapi_buffer_t *)0;
556 while (c -> outbufs &&
557 !BYTES_IN_BUFFER (c -> outbufs)) {
558 if (c -> outbufs -> next) {
559 omapi_buffer_reference (&buffer,
560 c -> outbufs -> next, MDL);
561 omapi_buffer_dereference (&c -> outbufs -> next, MDL);
563 omapi_buffer_dereference (&c -> outbufs, MDL);
565 omapi_buffer_reference (&c -> outbufs, buffer, MDL);
566 omapi_buffer_dereference (&buffer, MDL);
569 return ISC_R_SUCCESS;
572 isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
578 status = omapi_connection_copyout ((unsigned char *)&inbuf,
580 if (status != ISC_R_SUCCESS)
583 *result = ntohl (inbuf);
584 return ISC_R_SUCCESS;
587 isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
593 inbuf = htonl (value);
595 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
599 isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
605 status = omapi_connection_copyout ((unsigned char *)&inbuf,
607 if (status != ISC_R_SUCCESS)
610 *result = ntohs (inbuf);
611 return ISC_R_SUCCESS;
614 isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
620 inbuf = htons (value);
622 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
626 isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
627 omapi_typed_data_t *data)
630 omapi_handle_t handle;
632 /* Null data is valid. */
634 return omapi_connection_put_uint32 (c, 0);
636 switch (data -> type) {
637 case omapi_datatype_int:
638 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
639 if (status != ISC_R_SUCCESS)
641 return omapi_connection_put_uint32 (c, ((u_int32_t)
642 (data -> u.integer)));
644 case omapi_datatype_string:
645 case omapi_datatype_data:
646 status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
647 if (status != ISC_R_SUCCESS)
649 if (data -> u.buffer.len)
650 return omapi_connection_copyin
651 (c, data -> u.buffer.value,
652 data -> u.buffer.len);
653 return ISC_R_SUCCESS;
655 case omapi_datatype_object:
656 if (data -> u.object) {
657 status = omapi_object_handle (&handle,
659 if (status != ISC_R_SUCCESS)
663 status = omapi_connection_put_uint32 (c, sizeof handle);
664 if (status != ISC_R_SUCCESS)
666 return omapi_connection_put_uint32 (c, handle);
669 return ISC_R_INVALIDARG;
672 isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
675 unsigned len = strlen (name);
677 status = omapi_connection_put_uint16 (c, len);
678 if (status != ISC_R_SUCCESS)
680 return omapi_connection_copyin (c, (const unsigned char *)name, len);
683 isc_result_t omapi_connection_put_string (omapi_object_t *c,
690 len = strlen (string);
694 status = omapi_connection_put_uint32 (c, len);
695 if (status != ISC_R_SUCCESS)
698 return omapi_connection_copyin
699 (c, (const unsigned char *)string, len);
700 return ISC_R_SUCCESS;
703 isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
706 omapi_handle_t handle;
709 status = omapi_object_handle (&handle, h);
710 if (status != ISC_R_SUCCESS)
713 handle = 0; /* The null handle. */
714 status = omapi_connection_put_uint32 (c, sizeof handle);
715 if (status != ISC_R_SUCCESS)
717 return omapi_connection_put_uint32 (c, handle);