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