1 /* buffer.c
2 
3    Buffer access functions for the object management protocol... */
4 
5 /*
6  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
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/.
12  *
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.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   https://www.isc.org/
26  *
27  */
28 
29 #include "dhcpd.h"
30 
31 #include <omapip/omapip_p.h>
32 #include <errno.h>
33 
34 #if defined (TRACING)
35 static void trace_connection_input_input (trace_type_t *, unsigned, char *);
36 static void trace_connection_input_stop (trace_type_t *);
37 static void trace_connection_output_input (trace_type_t *, unsigned, char *);
38 static void trace_connection_output_stop (trace_type_t *);
39 static trace_type_t *trace_connection_input;
40 static trace_type_t *trace_connection_output;
41 static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
42 						   unsigned, char *,
43 						   unsigned *);
44 extern omapi_array_t *omapi_connections;
45 
omapi_buffer_trace_setup()46 void omapi_buffer_trace_setup ()
47 {
48 	trace_connection_input =
49 		trace_type_register ("connection-input",
50 				     (void *)0,
51 				     trace_connection_input_input,
52 				     trace_connection_input_stop, MDL);
53 	trace_connection_output =
54 		trace_type_register ("connection-output",
55 				     (void *)0,
56 				     trace_connection_output_input,
57 				     trace_connection_output_stop, MDL);
58 }
59 
trace_connection_input_input(trace_type_t * ttype,unsigned length,char * buf)60 static void trace_connection_input_input (trace_type_t *ttype,
61 					  unsigned length, char *buf)
62 {
63 	unsigned left, taken, cc = 0;
64 	char *s;
65 	int32_t connect_index;
66 	isc_result_t status;
67 	omapi_connection_object_t *c = (omapi_connection_object_t *)0;
68 
69 	memcpy (&connect_index, buf, sizeof connect_index);
70 	connect_index = ntohl (connect_index);
71 
72 	omapi_array_foreach_begin (omapi_connections,
73 				   omapi_connection_object_t, lp) {
74 		if (lp -> index == ntohl (connect_index)) {
75 			omapi_connection_reference (&c, lp, MDL);
76 			omapi_connection_dereference (&lp, MDL);
77 			break;
78 		}
79 	} omapi_array_foreach_end (omapi_connections,
80 				   omapi_connection_object_t, lp);
81 
82 	if (!c) {
83 		log_error ("trace connection input: no connection index %ld",
84 			   (long int)connect_index);
85 		return;
86 	}
87 
88 	s = buf + sizeof connect_index;
89 	left = length - sizeof connect_index;
90 
91 	while (left) {
92 		taken = 0;
93 		status = omapi_connection_reader_trace ((omapi_object_t *)c,
94 							left, s, &taken);
95 		if (status != ISC_R_SUCCESS) {
96 			log_error ("trace connection input: %s",
97 				   isc_result_totext (status));
98 			break;
99 		}
100 		if (!taken) {
101 			if (cc > 0) {
102 				log_error ("trace connection_input: %s",
103 					   "input is not being consumed.");
104 				break;
105 			}
106 			cc++;
107 		} else {
108 			cc = 0;
109 			left -= taken;
110 		}
111 	}
112 	omapi_connection_dereference (&c, MDL);
113 }
114 
trace_connection_input_stop(trace_type_t * ttype)115 static void trace_connection_input_stop (trace_type_t *ttype) { }
116 
trace_connection_output_input(trace_type_t * ttype,unsigned length,char * buf)117 static void trace_connection_output_input (trace_type_t *ttype,
118 					  unsigned length, char *buf)
119 {
120 	/* We *could* check to see if the output is correct, but for now
121 	   we aren't going to do that. */
122 }
123 
trace_connection_output_stop(trace_type_t * ttype)124 static void trace_connection_output_stop (trace_type_t *ttype) { }
125 
126 #endif
127 
128 /* Make sure that at least len bytes are in the input buffer, and if not,
129    read enough bytes to make up the difference. */
130 
omapi_connection_reader(omapi_object_t * h)131 isc_result_t omapi_connection_reader (omapi_object_t *h)
132 {
133 #if defined (TRACING)
134 	return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
135 }
136 
omapi_connection_reader_trace(omapi_object_t * h,unsigned stuff_len,char * stuff_buf,unsigned * stuff_taken)137 static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
138 						   unsigned stuff_len,
139 						   char *stuff_buf,
140 						   unsigned *stuff_taken)
141 {
142 #endif
143 	omapi_buffer_t *buffer;
144 	isc_result_t status;
145 	unsigned read_len;
146 	int read_status;
147 	omapi_connection_object_t *c;
148 	unsigned bytes_to_read;
149 
150 	if (!h || h -> type != omapi_type_connection)
151 		return DHCP_R_INVALIDARG;
152 	c = (omapi_connection_object_t *)h;
153 
154 	/* See if there are enough bytes. */
155 	if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
156 	    c -> in_bytes > c -> bytes_needed)
157 		return ISC_R_SUCCESS;
158 
159 
160 	if (c -> inbufs) {
161 		for (buffer = c -> inbufs; buffer -> next;
162 		     buffer = buffer -> next)
163 			;
164 		if (!BUFFER_BYTES_FREE (buffer)) {
165 			status = omapi_buffer_new (&buffer -> next, MDL);
166 			if (status != ISC_R_SUCCESS)
167 				return status;
168 			buffer = buffer -> next;
169 		}
170 	} else {
171 		status = omapi_buffer_new (&c -> inbufs, MDL);
172 		if (status != ISC_R_SUCCESS)
173 			return status;
174 		buffer = c -> inbufs;
175 	}
176 
177 	bytes_to_read = BUFFER_BYTES_FREE (buffer);
178 
179 	while (bytes_to_read) {
180 		if (buffer -> tail > buffer -> head)
181 			read_len = sizeof (buffer -> buf) - buffer -> tail;
182 		else
183 			read_len = buffer -> head - buffer -> tail;
184 
185 #if defined (TRACING)
186 		if (trace_playback()) {
187 			if (stuff_len) {
188 				if (read_len > stuff_len)
189 					read_len = stuff_len;
190 				if (stuff_taken)
191 					*stuff_taken += read_len;
192 				memcpy (&buffer -> buf [buffer -> tail],
193 					stuff_buf, read_len);
194 				stuff_len -= read_len;
195 				stuff_buf += read_len;
196 				read_status = read_len;
197 			} else {
198 				break;
199 			}
200 		} else
201 #endif
202 		{
203 			read_status = read (c -> socket,
204 					    &buffer -> buf [buffer -> tail],
205 					    read_len);
206 		}
207 		if (read_status < 0) {
208 			if (errno == EWOULDBLOCK)
209 				break;
210 			else if (errno == EIO)
211 				return ISC_R_IOERROR;
212 			else if (errno == EINVAL)
213 				return DHCP_R_INVALIDARG;
214 			else if (errno == ECONNRESET) {
215 				omapi_disconnect (h, 1);
216 				return ISC_R_SHUTTINGDOWN;
217 			} else
218 				return ISC_R_UNEXPECTED;
219 		}
220 
221 		/* If we got a zero-length read, as opposed to EWOULDBLOCK,
222 		   the remote end closed the connection. */
223 		if (read_status == 0) {
224 			omapi_disconnect (h, 0);
225 			return ISC_R_SHUTTINGDOWN;
226 		}
227 #if defined (TRACING)
228 		if (trace_record ()) {
229 			trace_iov_t iov [2];
230 			int32_t connect_index;
231 
232 			connect_index = htonl (c -> index);
233 
234 			iov [0].buf = (char *)&connect_index;
235 			iov [0].len = sizeof connect_index;
236 			iov [1].buf = &buffer -> buf [buffer -> tail];
237 			iov [1].len = read_status;
238 
239 			status = (trace_write_packet_iov
240 				  (trace_connection_input, 2, iov, MDL));
241 			if (status != ISC_R_SUCCESS) {
242 				trace_stop ();
243 				log_error ("trace connection input: %s",
244 					   isc_result_totext (status));
245 			}
246 		}
247 #endif
248 		buffer -> tail += read_status;
249 		c -> in_bytes += read_status;
250 		if (buffer -> tail == sizeof buffer -> buf)
251 			buffer -> tail = 0;
252 		if (read_status < read_len)
253 			break;
254 		bytes_to_read -= read_status;
255 	}
256 
257 	if (c -> bytes_needed <= c -> in_bytes) {
258 		omapi_signal (h, "ready", c);
259 	}
260 	return ISC_R_SUCCESS;
261 }
262 
263 /* Put some bytes into the output buffer for a connection. */
264 
omapi_connection_copyin(omapi_object_t * h,const unsigned char * bufp,unsigned len)265 isc_result_t omapi_connection_copyin (omapi_object_t *h,
266 				      const unsigned char *bufp,
267 				      unsigned len)
268 {
269 	omapi_buffer_t *buffer;
270 	isc_result_t status;
271 	int bytes_copied = 0;
272 	unsigned copy_len;
273 	int sig_flags = SIG_MODE_UPDATE;
274 	omapi_connection_object_t *c;
275 
276 	/* no need to verify len as it's unsigned */
277 	if (!h || h -> type != omapi_type_connection)
278 		return DHCP_R_INVALIDARG;
279 	c = (omapi_connection_object_t *)h;
280 
281 	/* If the connection is closed, return an error if the caller
282 	   tries to copy in. */
283 	if (c -> state == omapi_connection_disconnecting ||
284 	    c -> state == omapi_connection_closed)
285 		return ISC_R_NOTCONNECTED;
286 
287 	if (c -> outbufs) {
288 		for (buffer = c -> outbufs;
289 		     buffer -> next; buffer = buffer -> next)
290 			;
291 	} else {
292 		status = omapi_buffer_new (&c -> outbufs, MDL);
293 		if (status != ISC_R_SUCCESS)
294 			goto leave;
295 		buffer = c -> outbufs;
296 	}
297 
298 	while (bytes_copied < len) {
299 		/* If there is no space available in this buffer,
300                    allocate a new one. */
301 		if (!BUFFER_BYTES_FREE (buffer)) {
302 			status = (omapi_buffer_new (&buffer -> next, MDL));
303 			if (status != ISC_R_SUCCESS)
304 				goto leave;
305 			buffer = buffer -> next;
306 		}
307 
308 		if (buffer -> tail > buffer -> head)
309 			copy_len = sizeof (buffer -> buf) - buffer -> tail;
310 		else
311 			copy_len = buffer -> head - buffer -> tail;
312 
313 		if (copy_len > (len - bytes_copied))
314 			copy_len = len - bytes_copied;
315 
316 		if (c -> out_key) {
317 			if (!c -> out_context)
318 				sig_flags |= SIG_MODE_INIT;
319 			status = omapi_connection_sign_data
320 				(sig_flags, c -> out_key, &c -> out_context,
321 				 &bufp [bytes_copied], copy_len,
322 				 (omapi_typed_data_t **)0);
323 			if (status != ISC_R_SUCCESS)
324 				goto leave;
325 		}
326 
327 		memcpy (&buffer -> buf [buffer -> tail],
328 			&bufp [bytes_copied], copy_len);
329 		buffer -> tail += copy_len;
330 		c -> out_bytes += copy_len;
331 		bytes_copied += copy_len;
332 		if (buffer -> tail == sizeof buffer -> buf)
333 			buffer -> tail = 0;
334 	}
335 
336 	status = ISC_R_SUCCESS;
337 
338  leave:
339 	/*
340 	 * If we have any bytes to send and we have a proper io object
341 	 * inform the socket code that we would like to know when we
342 	 * can send more bytes.
343 	 */
344 	if (c->out_bytes != 0) {
345 		if ((c->outer != NULL) &&
346 		    (c->outer->type == omapi_type_io_object)) {
347 			omapi_io_object_t *io = (omapi_io_object_t *)c->outer;
348 			isc_socket_fdwatchpoke(io->fd,
349 					       ISC_SOCKFDWATCH_WRITE);
350 		}
351 	}
352 
353 	return (status);
354 }
355 
356 /* Copy some bytes from the input buffer, and advance the input buffer
357    pointer beyond the bytes copied out. */
358 
omapi_connection_copyout(unsigned char * buf,omapi_object_t * h,unsigned size)359 isc_result_t omapi_connection_copyout (unsigned char *buf,
360 				       omapi_object_t *h,
361 				       unsigned size)
362 {
363 	unsigned bytes_remaining;
364 	unsigned bytes_this_copy;
365 	unsigned first_byte;
366 	omapi_buffer_t *buffer;
367 	unsigned char *bufp;
368 	int sig_flags = SIG_MODE_UPDATE;
369 	omapi_connection_object_t *c;
370 	isc_result_t status;
371 
372 	if (!h || h -> type != omapi_type_connection)
373 		return DHCP_R_INVALIDARG;
374 	c = (omapi_connection_object_t *)h;
375 
376 	if (size > c -> in_bytes)
377 		return ISC_R_NOMORE;
378 	bufp = buf;
379 	bytes_remaining = size;
380 	buffer = c -> inbufs;
381 
382 	while (bytes_remaining) {
383 		if (!buffer)
384 			return ISC_R_UNEXPECTED;
385 		if (BYTES_IN_BUFFER (buffer)) {
386 			if (buffer -> head == (sizeof buffer -> buf) - 1)
387 				first_byte = 0;
388 			else
389 				first_byte = buffer -> head + 1;
390 
391 			if (first_byte > buffer -> tail) {
392 				bytes_this_copy = (sizeof buffer -> buf -
393 						   first_byte);
394 			} else {
395 				bytes_this_copy =
396 					buffer -> tail - first_byte;
397 			}
398 			if (bytes_this_copy > bytes_remaining)
399 				bytes_this_copy = bytes_remaining;
400 			if (bufp) {
401 				if (c -> in_key) {
402 					if (!c -> in_context)
403 						sig_flags |= SIG_MODE_INIT;
404 					status = omapi_connection_sign_data
405 						(sig_flags,
406 						 c -> in_key,
407 						 &c -> in_context,
408 						 (unsigned char *)
409 						 &buffer -> buf [first_byte],
410 						 bytes_this_copy,
411 						 (omapi_typed_data_t **)0);
412 					if (status != ISC_R_SUCCESS)
413 						return status;
414 				}
415 
416 				memcpy (bufp, &buffer -> buf [first_byte],
417 					bytes_this_copy);
418 				bufp += bytes_this_copy;
419 			}
420 			bytes_remaining -= bytes_this_copy;
421 			buffer -> head = first_byte + bytes_this_copy - 1;
422 			c -> in_bytes -= bytes_this_copy;
423 		}
424 
425 		if (!BYTES_IN_BUFFER (buffer))
426 			buffer = buffer -> next;
427 	}
428 
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);
437 		}
438 		omapi_buffer_dereference (&c -> inbufs, MDL);
439 		if (buffer) {
440 			omapi_buffer_reference
441 				(&c -> inbufs, buffer, MDL);
442 			omapi_buffer_dereference (&buffer, MDL);
443 		}
444 	}
445 	return ISC_R_SUCCESS;
446 }
447 
omapi_connection_writer(omapi_object_t * h)448 isc_result_t omapi_connection_writer (omapi_object_t *h)
449 {
450 	unsigned bytes_this_write;
451 	int bytes_written;
452 	unsigned first_byte;
453 	omapi_buffer_t *buffer;
454 	omapi_connection_object_t *c;
455 
456 	if (!h || h -> type != omapi_type_connection)
457 		return DHCP_R_INVALIDARG;
458 	c = (omapi_connection_object_t *)h;
459 
460 	/* Already flushed... */
461 	if (!c -> out_bytes)
462 		return ISC_R_SUCCESS;
463 
464 	buffer = c -> outbufs;
465 
466 	while (c -> out_bytes) {
467 		if (!buffer)
468 			return ISC_R_UNEXPECTED;
469 		if (BYTES_IN_BUFFER (buffer)) {
470 			if (buffer -> head == (sizeof buffer -> buf) - 1)
471 				first_byte = 0;
472 			else
473 				first_byte = buffer -> head + 1;
474 
475 			if (first_byte > buffer -> tail) {
476 				bytes_this_write = (sizeof buffer -> buf -
477 						   first_byte);
478 			} else {
479 				bytes_this_write =
480 					buffer -> tail - first_byte;
481 			}
482 			bytes_written = write (c -> socket,
483 					       &buffer -> buf [first_byte],
484 					       bytes_this_write);
485 			/* If the write failed with EWOULDBLOCK or we wrote
486 			   zero bytes, a further write would block, so we have
487 			   flushed as much as we can for now.   Other errors
488 			   are really errors. */
489 			if (bytes_written < 0) {
490 				if (errno == EWOULDBLOCK || errno == EAGAIN)
491 					return ISC_R_INPROGRESS;
492 				else if (errno == EPIPE)
493 					return ISC_R_NOCONN;
494 #ifdef EDQUOT
495 				else if (errno == EFBIG || errno == EDQUOT)
496 #else
497 				else if (errno == EFBIG)
498 #endif
499 					return ISC_R_NORESOURCES;
500 				else if (errno == ENOSPC)
501 					return ISC_R_NOSPACE;
502 				else if (errno == EIO)
503 					return ISC_R_IOERROR;
504 				else if (errno == EINVAL)
505 					return DHCP_R_INVALIDARG;
506 				else if (errno == ECONNRESET)
507 					return ISC_R_SHUTTINGDOWN;
508 				else
509 					return ISC_R_UNEXPECTED;
510 			}
511 			if (bytes_written == 0)
512 				return ISC_R_INPROGRESS;
513 
514 #if defined (TRACING)
515 			if (trace_record ()) {
516 				isc_result_t status;
517 				trace_iov_t iov [2];
518 				int32_t connect_index;
519 
520 				connect_index = htonl (c -> index);
521 
522 				iov [0].buf = (char *)&connect_index;
523 				iov [0].len = sizeof connect_index;
524 				iov [1].buf = &buffer -> buf [buffer -> tail];
525 				iov [1].len = bytes_written;
526 
527 				status = (trace_write_packet_iov
528 					  (trace_connection_input, 2, iov,
529 					   MDL));
530 				if (status != ISC_R_SUCCESS) {
531 					trace_stop ();
532 					log_error ("trace %s output: %s",
533 						   "connection",
534 						   isc_result_totext (status));
535 				}
536 			}
537 #endif
538 
539 			buffer -> head = first_byte + bytes_written - 1;
540 			c -> out_bytes -= bytes_written;
541 
542 			/* If we didn't finish out the write, we filled the
543 			   O.S. output buffer and a further write would block,
544 			   so stop trying to flush now. */
545 			if (bytes_written != bytes_this_write)
546 				return ISC_R_INPROGRESS;
547 		}
548 
549 		if (!BYTES_IN_BUFFER (buffer))
550 			buffer = buffer -> next;
551 	}
552 
553 	/* Get rid of any output buffers we emptied. */
554 	buffer = (omapi_buffer_t *)0;
555 	while (c -> outbufs &&
556 	       !BYTES_IN_BUFFER (c -> outbufs)) {
557 		if (c -> outbufs -> next) {
558 			omapi_buffer_reference (&buffer,
559 						c -> outbufs -> next, MDL);
560 			omapi_buffer_dereference (&c -> outbufs -> next, MDL);
561 		}
562 		omapi_buffer_dereference (&c -> outbufs, MDL);
563 		if (buffer) {
564 			omapi_buffer_reference (&c -> outbufs, buffer, MDL);
565 			omapi_buffer_dereference (&buffer, MDL);
566 		}
567 	}
568 
569 	/* If we had data left to write when we're told to disconnect,
570 	* we need recall disconnect, now that we're done writing.
571 	* See rt46767. */
572 	if (c->out_bytes == 0 && c->state == omapi_connection_disconnecting) {
573 		omapi_disconnect (h, 1);
574 		return ISC_R_SHUTTINGDOWN;
575 	}
576 
577 	return ISC_R_SUCCESS;
578 }
579 
omapi_connection_get_uint32(omapi_object_t * c,u_int32_t * result)580 isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
581 					  u_int32_t *result)
582 {
583 	u_int32_t inbuf;
584 	isc_result_t status;
585 
586 	status = omapi_connection_copyout ((unsigned char *)&inbuf,
587 					   c, sizeof inbuf);
588 	if (status != ISC_R_SUCCESS)
589 		return status;
590 
591 	*result = ntohl (inbuf);
592 	return ISC_R_SUCCESS;
593 }
594 
omapi_connection_put_uint32(omapi_object_t * c,u_int32_t value)595 isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
596 					  u_int32_t value)
597 {
598 	u_int32_t inbuf;
599 
600 	inbuf = htonl (value);
601 
602 	return omapi_connection_copyin (c, (unsigned char *)&inbuf,
603 					sizeof inbuf);
604 }
605 
omapi_connection_get_uint16(omapi_object_t * c,u_int16_t * result)606 isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
607 					  u_int16_t *result)
608 {
609 	u_int16_t inbuf;
610 	isc_result_t status;
611 
612 	status = omapi_connection_copyout ((unsigned char *)&inbuf,
613 					   c, sizeof inbuf);
614 	if (status != ISC_R_SUCCESS)
615 		return status;
616 
617 	*result = ntohs (inbuf);
618 	return ISC_R_SUCCESS;
619 }
620 
omapi_connection_put_uint16(omapi_object_t * c,u_int32_t value)621 isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
622 					  u_int32_t value)
623 {
624 	u_int16_t inbuf;
625 
626 	inbuf = htons (value);
627 
628 	return omapi_connection_copyin (c, (unsigned char *)&inbuf,
629 					sizeof inbuf);
630 }
631 
omapi_connection_write_typed_data(omapi_object_t * c,omapi_typed_data_t * data)632 isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
633 						omapi_typed_data_t *data)
634 {
635 	isc_result_t status;
636 	omapi_handle_t handle;
637 
638 	/* Null data is valid. */
639 	if (!data)
640 		return omapi_connection_put_uint32 (c, 0);
641 
642 	switch (data -> type) {
643 	      case omapi_datatype_int:
644 		status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
645 		if (status != ISC_R_SUCCESS)
646 			return status;
647 		return omapi_connection_put_uint32 (c, ((u_int32_t)
648 							(data -> u.integer)));
649 
650 	      case omapi_datatype_string:
651 	      case omapi_datatype_data:
652 		status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
653 		if (status != ISC_R_SUCCESS)
654 			return status;
655 		if (data -> u.buffer.len)
656 			return omapi_connection_copyin
657 				(c, data -> u.buffer.value,
658 				 data -> u.buffer.len);
659 		return ISC_R_SUCCESS;
660 
661 	      case omapi_datatype_object:
662 		if (data -> u.object) {
663 			status = omapi_object_handle (&handle,
664 						      data -> u.object);
665 			if (status != ISC_R_SUCCESS)
666 				return status;
667 		} else
668 			handle = 0;
669 		status = omapi_connection_put_uint32 (c, sizeof handle);
670 		if (status != ISC_R_SUCCESS)
671 			return status;
672 		return omapi_connection_put_uint32 (c, handle);
673 
674 	}
675 	return DHCP_R_INVALIDARG;
676 }
677 
omapi_connection_put_name(omapi_object_t * c,const char * name)678 isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
679 {
680 	isc_result_t status;
681 	unsigned len = strlen (name);
682 
683 	status = omapi_connection_put_uint16 (c, len);
684 	if (status != ISC_R_SUCCESS)
685 		return status;
686 	return omapi_connection_copyin (c, (const unsigned char *)name, len);
687 }
688 
omapi_connection_put_string(omapi_object_t * c,const char * string)689 isc_result_t omapi_connection_put_string (omapi_object_t *c,
690 					  const char *string)
691 {
692 	isc_result_t status;
693 	unsigned len;
694 
695 	if (string)
696 		len = strlen (string);
697 	else
698 		len = 0;
699 
700 	status = omapi_connection_put_uint32 (c, len);
701 	if (status != ISC_R_SUCCESS)
702 		return status;
703 	if (len)
704 		return omapi_connection_copyin
705 			(c, (const unsigned char *)string, len);
706 	return ISC_R_SUCCESS;
707 }
708 
omapi_connection_put_handle(omapi_object_t * c,omapi_object_t * h)709 isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
710 {
711 	isc_result_t status;
712 	omapi_handle_t handle;
713 
714 	if (h) {
715 		status = omapi_object_handle (&handle, h);
716 		if (status != ISC_R_SUCCESS)
717 			return status;
718 	} else
719 		handle = 0;	/* The null handle. */
720 	status = omapi_connection_put_uint32 (c, sizeof handle);
721 	if (status != ISC_R_SUCCESS)
722 		return status;
723 	return omapi_connection_put_uint32 (c, handle);
724 }
725 
omapi_connection_put_named_uint32(omapi_object_t * c,const char * name,u_int32_t value)726 isc_result_t omapi_connection_put_named_uint32 (omapi_object_t *c,
727 						const char *name,
728 						u_int32_t value)
729 {
730 	isc_result_t status;
731 
732 	status = omapi_connection_put_name(c, name);
733 	if (status != ISC_R_SUCCESS)
734 		return (status);
735 
736 	status = omapi_connection_put_uint32(c, sizeof(u_int32_t));
737 	if (status != ISC_R_SUCCESS)
738 		return (status);
739 
740 	status = omapi_connection_put_uint32(c, value);
741 	return (status);
742 }
743 
744