Annotation of embedaddon/dhcp/omapip/buffer.c, revision 1.1.1.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 (len < 0)
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;
289:
290: /* If the connection is closed, return an error if the caller
291: tries to copy in. */
292: if (c -> state == omapi_connection_disconnecting ||
293: c -> state == omapi_connection_closed)
294: return ISC_R_NOTCONNECTED;
295:
296: if (c -> outbufs) {
297: for (buffer = c -> outbufs;
298: buffer -> next; buffer = buffer -> next)
299: ;
300: } else {
301: status = omapi_buffer_new (&c -> outbufs, MDL);
302: if (status != ISC_R_SUCCESS)
303: return status;
304: buffer = c -> outbufs;
305: }
306:
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)
313: return status;
314: buffer = buffer -> next;
315: }
316:
317: if (buffer -> tail > buffer -> head)
318: copy_len = sizeof (buffer -> buf) - buffer -> tail;
319: else
320: copy_len = buffer -> head - buffer -> tail;
321:
322: if (copy_len > (len - bytes_copied))
323: copy_len = len - bytes_copied;
324:
325: if (c -> out_key) {
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)
333: return status;
334: }
335:
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)
342: buffer -> tail = 0;
343: }
344: return ISC_R_SUCCESS;
345: }
346:
347: /* Copy some bytes from the input buffer, and advance the input buffer
348: pointer beyond the bytes copied out. */
349:
350: isc_result_t omapi_connection_copyout (unsigned char *buf,
351: omapi_object_t *h,
352: unsigned size)
353: {
354: unsigned bytes_remaining;
355: unsigned bytes_this_copy;
356: unsigned first_byte;
357: omapi_buffer_t *buffer;
358: unsigned char *bufp;
359: int sig_flags = SIG_MODE_UPDATE;
360: omapi_connection_object_t *c;
361: isc_result_t status;
362:
363: if (!h || h -> type != omapi_type_connection)
364: return ISC_R_INVALIDARG;
365: c = (omapi_connection_object_t *)h;
366:
367: if (size > c -> in_bytes)
368: return ISC_R_NOMORE;
369: bufp = buf;
370: bytes_remaining = size;
371: buffer = c -> inbufs;
372:
373: while (bytes_remaining) {
374: if (!buffer)
375: return ISC_R_UNEXPECTED;
376: if (BYTES_IN_BUFFER (buffer)) {
377: if (buffer -> head == (sizeof buffer -> buf) - 1)
378: first_byte = 0;
379: else
380: first_byte = buffer -> head + 1;
381:
382: if (first_byte > buffer -> tail) {
383: bytes_this_copy = (sizeof buffer -> buf -
384: first_byte);
385: } else {
386: bytes_this_copy =
387: buffer -> tail - first_byte;
388: }
389: if (bytes_this_copy > bytes_remaining)
390: bytes_this_copy = bytes_remaining;
391: if (bufp) {
392: if (c -> in_key) {
393: if (!c -> in_context)
394: sig_flags |= SIG_MODE_INIT;
395: status = omapi_connection_sign_data
396: (sig_flags,
397: c -> in_key,
398: &c -> in_context,
399: (unsigned char *)
400: &buffer -> buf [first_byte],
401: bytes_this_copy,
402: (omapi_typed_data_t **)0);
403: if (status != ISC_R_SUCCESS)
404: return status;
405: }
406:
407: memcpy (bufp, &buffer -> buf [first_byte],
408: bytes_this_copy);
409: bufp += bytes_this_copy;
410: }
411: bytes_remaining -= bytes_this_copy;
412: buffer -> head = first_byte + bytes_this_copy - 1;
413: c -> in_bytes -= bytes_this_copy;
414: }
415:
416: if (!BYTES_IN_BUFFER (buffer))
417: buffer = buffer -> next;
418: }
419:
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);
428: }
429: omapi_buffer_dereference (&c -> inbufs, MDL);
430: if (buffer) {
431: omapi_buffer_reference
432: (&c -> inbufs, buffer, MDL);
433: omapi_buffer_dereference (&buffer, MDL);
434: }
435: }
436: return ISC_R_SUCCESS;
437: }
438:
439: isc_result_t omapi_connection_writer (omapi_object_t *h)
440: {
441: unsigned bytes_this_write;
442: int bytes_written;
443: unsigned first_byte;
444: omapi_buffer_t *buffer;
445: omapi_connection_object_t *c;
446:
447: if (!h || h -> type != omapi_type_connection)
448: return ISC_R_INVALIDARG;
449: c = (omapi_connection_object_t *)h;
450:
451: /* Already flushed... */
452: if (!c -> out_bytes)
453: return ISC_R_SUCCESS;
454:
455: buffer = c -> outbufs;
456:
457: while (c -> out_bytes) {
458: if (!buffer)
459: return ISC_R_UNEXPECTED;
460: if (BYTES_IN_BUFFER (buffer)) {
461: if (buffer -> head == (sizeof buffer -> buf) - 1)
462: first_byte = 0;
463: else
464: first_byte = buffer -> head + 1;
465:
466: if (first_byte > buffer -> tail) {
467: bytes_this_write = (sizeof buffer -> buf -
468: first_byte);
469: } else {
470: bytes_this_write =
471: buffer -> tail - first_byte;
472: }
473: bytes_written = write (c -> socket,
474: &buffer -> buf [first_byte],
475: bytes_this_write);
476: /* If the write failed with EWOULDBLOCK or we wrote
477: zero bytes, a further write would block, so we have
478: flushed as much as we can for now. Other errors
479: are really errors. */
480: if (bytes_written < 0) {
481: if (errno == EWOULDBLOCK || errno == EAGAIN)
482: return ISC_R_SUCCESS;
483: else if (errno == EPIPE)
484: return ISC_R_NOCONN;
485: #ifdef EDQUOT
486: else if (errno == EFBIG || errno == EDQUOT)
487: #else
488: else if (errno == EFBIG)
489: #endif
490: return ISC_R_NORESOURCES;
491: else if (errno == ENOSPC)
492: return ISC_R_NOSPACE;
493: else if (errno == EIO)
494: return ISC_R_IOERROR;
495: else if (errno == EINVAL)
496: return ISC_R_INVALIDARG;
497: else if (errno == ECONNRESET)
498: return ISC_R_SHUTTINGDOWN;
499: else
500: return ISC_R_UNEXPECTED;
501: }
502: if (bytes_written == 0)
503: return ISC_R_SUCCESS;
504:
505: #if defined (TRACING)
506: if (trace_record ()) {
507: isc_result_t status;
508: trace_iov_t iov [2];
509: int32_t connect_index;
510:
511: connect_index = htonl (c -> index);
512:
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;
517:
518: status = (trace_write_packet_iov
519: (trace_connection_input, 2, iov,
520: MDL));
521: if (status != ISC_R_SUCCESS) {
522: trace_stop ();
523: log_error ("trace %s output: %s",
524: "connection",
525: isc_result_totext (status));
526: }
527: }
528: #endif
529:
530: buffer -> head = first_byte + bytes_written - 1;
531: c -> out_bytes -= bytes_written;
532:
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;
538: }
539:
540: if (!BYTES_IN_BUFFER (buffer))
541: buffer = buffer -> next;
542: }
543:
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);
552: }
553: omapi_buffer_dereference (&c -> outbufs, MDL);
554: if (buffer) {
555: omapi_buffer_reference (&c -> outbufs, buffer, MDL);
556: omapi_buffer_dereference (&buffer, MDL);
557: }
558: }
559: return ISC_R_SUCCESS;
560: }
561:
562: isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
563: u_int32_t *result)
564: {
565: u_int32_t inbuf;
566: isc_result_t status;
567:
568: status = omapi_connection_copyout ((unsigned char *)&inbuf,
569: c, sizeof inbuf);
570: if (status != ISC_R_SUCCESS)
571: return status;
572:
573: *result = ntohl (inbuf);
574: return ISC_R_SUCCESS;
575: }
576:
577: isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
578: u_int32_t value)
579: {
580: u_int32_t inbuf;
581:
582: inbuf = htonl (value);
583:
584: return omapi_connection_copyin (c, (unsigned char *)&inbuf,
585: sizeof inbuf);
586: }
587:
588: isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
589: u_int16_t *result)
590: {
591: u_int16_t inbuf;
592: isc_result_t status;
593:
594: status = omapi_connection_copyout ((unsigned char *)&inbuf,
595: c, sizeof inbuf);
596: if (status != ISC_R_SUCCESS)
597: return status;
598:
599: *result = ntohs (inbuf);
600: return ISC_R_SUCCESS;
601: }
602:
603: isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
604: u_int32_t value)
605: {
606: u_int16_t inbuf;
607:
608: inbuf = htons (value);
609:
610: return omapi_connection_copyin (c, (unsigned char *)&inbuf,
611: sizeof inbuf);
612: }
613:
614: isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
615: omapi_typed_data_t *data)
616: {
617: isc_result_t status;
618: omapi_handle_t handle;
619:
620: /* Null data is valid. */
621: if (!data)
622: return omapi_connection_put_uint32 (c, 0);
623:
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)
628: return status;
629: return omapi_connection_put_uint32 (c, ((u_int32_t)
630: (data -> u.integer)));
631:
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)
636: return status;
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;
642:
643: case omapi_datatype_object:
644: if (data -> u.object) {
645: status = omapi_object_handle (&handle,
646: data -> u.object);
647: if (status != ISC_R_SUCCESS)
648: return status;
649: } else
650: handle = 0;
651: status = omapi_connection_put_uint32 (c, sizeof handle);
652: if (status != ISC_R_SUCCESS)
653: return status;
654: return omapi_connection_put_uint32 (c, handle);
655:
656: }
657: return ISC_R_INVALIDARG;
658: }
659:
660: isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
661: {
662: isc_result_t status;
663: unsigned len = strlen (name);
664:
665: status = omapi_connection_put_uint16 (c, len);
666: if (status != ISC_R_SUCCESS)
667: return status;
668: return omapi_connection_copyin (c, (const unsigned char *)name, len);
669: }
670:
671: isc_result_t omapi_connection_put_string (omapi_object_t *c,
672: const char *string)
673: {
674: isc_result_t status;
675: unsigned len;
676:
677: if (string)
678: len = strlen (string);
679: else
680: len = 0;
681:
682: status = omapi_connection_put_uint32 (c, len);
683: if (status != ISC_R_SUCCESS)
684: return status;
685: if (len)
686: return omapi_connection_copyin
687: (c, (const unsigned char *)string, len);
688: return ISC_R_SUCCESS;
689: }
690:
691: isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
692: {
693: isc_result_t status;
694: omapi_handle_t handle;
695:
696: if (h) {
697: status = omapi_object_handle (&handle, h);
698: if (status != ISC_R_SUCCESS)
699: return status;
700: } else
701: handle = 0; /* The null handle. */
702: status = omapi_connection_put_uint32 (c, sizeof handle);
703: if (status != ISC_R_SUCCESS)
704: return status;
705: return omapi_connection_put_uint32 (c, handle);
706: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>