]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/buffer.c
Fix corner case where REBIND would be ignored rather than NAKed.
[thirdparty/dhcp.git] / omapip / buffer.c
CommitLineData
61b844bf
TL
1/* buffer.c
2
3 Buffer access functions for the object management protocol... */
4
5/*
6 * Copyright (c) 1996-1999 Internet Software Consortium.
7 * Use is subject to license terms which appear in the file named
8 * ISC-LICENSE that should have accompanied this file when you
9 * received it. If a file named ISC-LICENSE did not accompany this
10 * file, or you are not sure the one you have is correct, you may
11 * obtain an applicable copy of the license at:
12 *
13 * http://www.isc.org/isc-license-1.0.html.
14 *
15 * This file is part of the ISC DHCP distribution. The documentation
16 * associated with this file is listed in the file DOCUMENTATION,
17 * included in the top-level directory of this release.
18 *
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
21 */
22
6a4c4be8 23#include <omapip/omapip_p.h>
61b844bf
TL
24
25/* Make sure that at least len bytes are in the input buffer, and if not,
26 read enough bytes to make up the difference. */
27
28isc_result_t omapi_connection_reader (omapi_object_t *h)
29{
30 omapi_buffer_t *buffer;
31 isc_result_t status;
b1b7b521
TL
32 unsigned read_len;
33 int read_status;
61b844bf 34 omapi_connection_object_t *c;
b1b7b521 35 unsigned bytes_to_read;
61b844bf
TL
36
37 if (!h || h -> type != omapi_type_connection)
38 return ISC_R_INVALIDARG;
39 c = (omapi_connection_object_t *)h;
40
41 /* Make sure c -> bytes_needed is valid. */
42 if (c -> bytes_needed < 0)
43 return ISC_R_INVALIDARG;
44
45 /* See if there are enough bytes. */
46 if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
47 c -> in_bytes > c -> bytes_needed)
48 return ISC_R_SUCCESS;
49
50 if (c -> inbufs) {
51 for (buffer = c -> inbufs; buffer -> next;
52 buffer = buffer -> next)
53 ;
c936e8c1 54 if (!BUFFER_BYTES_FREE (buffer)) {
4bd8800e 55 status = omapi_buffer_new (&buffer -> next, MDL);
61b844bf
TL
56 if (status != ISC_R_SUCCESS)
57 return status;
58 buffer = buffer -> next;
59 }
60 } else {
4bd8800e 61 status = omapi_buffer_new (&c -> inbufs, MDL);
61b844bf
TL
62 if (status != ISC_R_SUCCESS)
63 return status;
64 buffer = c -> inbufs;
65 }
66
c936e8c1 67 bytes_to_read = BUFFER_BYTES_FREE (buffer);
61b844bf
TL
68
69 while (bytes_to_read) {
c936e8c1
TL
70 if (buffer -> tail > buffer -> head)
71 read_len = sizeof (buffer -> buf) - buffer -> tail;
61b844bf 72 else
c936e8c1 73 read_len = buffer -> head - buffer -> tail;
61b844bf
TL
74
75 read_status = read (c -> socket,
76 &buffer -> buf [buffer -> tail], read_len);
77 if (read_status < 0) {
78 if (errno == EWOULDBLOCK)
c936e8c1 79 break;
61b844bf
TL
80 else if (errno == EIO)
81 return ISC_R_IOERROR;
82 else if (errno == EINVAL)
83 return ISC_R_INVALIDARG;
84 else if (errno == ECONNRESET) {
85 omapi_disconnect (h, 0);
86 return ISC_R_SHUTTINGDOWN;
87 } else
88 return ISC_R_UNEXPECTED;
89 }
c936e8c1
TL
90 /* If we got a zero-length read, as opposed to EWOULDBLOCK,
91 the remote end closed the connection. */
61b844bf
TL
92 if (read_status == 0) {
93 omapi_disconnect (h, 0);
94 return ISC_R_SHUTTINGDOWN;
95 }
96 buffer -> tail += read_status;
97 c -> in_bytes += read_status;
98 if (buffer -> tail == sizeof buffer -> buf)
99 buffer -> tail = 0;
100 if (read_status < read_len)
101 break;
102 bytes_to_read -= read_status;
103 }
104
581e37e4 105 if (c -> bytes_needed <= c -> in_bytes) {
61b844bf
TL
106 omapi_signal (h, "ready", c);
107 }
108 return ISC_R_SUCCESS;
109}
110
111/* Put some bytes into the output buffer for a connection. */
112
113isc_result_t omapi_connection_copyin (omapi_object_t *h,
b1b7b521
TL
114 const unsigned char *bufp,
115 unsigned len)
61b844bf
TL
116{
117 omapi_buffer_t *buffer;
118 isc_result_t status;
119 int bytes_copied = 0;
b1b7b521 120 unsigned copy_len;
61b844bf
TL
121 omapi_connection_object_t *c;
122
123 /* Make sure len is valid. */
124 if (len < 0)
125 return ISC_R_INVALIDARG;
126 if (!h || h -> type != omapi_type_connection)
127 return ISC_R_INVALIDARG;
128 c = (omapi_connection_object_t *)h;
129
130 if (c -> outbufs) {
131 for (buffer = c -> outbufs;
132 buffer -> next; buffer = buffer -> next)
133 ;
134 } else {
4bd8800e 135 status = omapi_buffer_new (&c -> outbufs, MDL);
61b844bf
TL
136 if (status != ISC_R_SUCCESS)
137 return status;
138 buffer = c -> outbufs;
139 }
140
141 while (bytes_copied < len) {
142 /* If there is no space available in this buffer,
143 allocate a new one. */
c936e8c1 144 if (!BUFFER_BYTES_FREE (buffer)) {
4bd8800e 145 status = (omapi_buffer_new (&buffer -> next, MDL));
61b844bf
TL
146 if (status != ISC_R_SUCCESS)
147 return status;
148 buffer = buffer -> next;
149 }
150
c936e8c1
TL
151 if (buffer -> tail > buffer -> head)
152 copy_len = sizeof (buffer -> buf) - buffer -> tail;
61b844bf 153 else
c936e8c1
TL
154 copy_len = buffer -> head - buffer -> tail;
155
61b844bf
TL
156 if (copy_len > (len - bytes_copied))
157 copy_len = len - bytes_copied;
158
159 memcpy (&buffer -> buf [buffer -> tail],
160 &bufp [bytes_copied], copy_len);
161 buffer -> tail += copy_len;
162 c -> out_bytes += copy_len;
163 bytes_copied += copy_len;
164 if (buffer -> tail == sizeof buffer -> buf)
165 buffer -> tail = 0;
166 }
167 return ISC_R_SUCCESS;
168}
169
170/* Copy some bytes from the input buffer, and advance the input buffer
171 pointer beyond the bytes copied out. */
172
e92653f1
TL
173isc_result_t omapi_connection_copyout (unsigned char *buf,
174 omapi_object_t *h,
b1b7b521 175 unsigned size)
61b844bf 176{
b1b7b521
TL
177 unsigned bytes_remaining;
178 unsigned bytes_this_copy;
c936e8c1 179 unsigned first_byte;
61b844bf
TL
180 omapi_buffer_t *buffer;
181 unsigned char *bufp;
182 omapi_connection_object_t *c;
183
184 if (!h || h -> type != omapi_type_connection)
185 return ISC_R_INVALIDARG;
186 c = (omapi_connection_object_t *)h;
187
188 if (size > c -> in_bytes)
189 return ISC_R_NOMORE;
190 bufp = buf;
191 bytes_remaining = size;
192 buffer = c -> inbufs;
193
194 while (bytes_remaining) {
195 if (!buffer)
196 return ISC_R_UNEXPECTED;
c936e8c1
TL
197 if (BYTES_IN_BUFFER (buffer)) {
198 if (buffer -> head == (sizeof buffer -> buf) - 1)
199 first_byte = 0;
200 else
201 first_byte = buffer -> head + 1;
202
203 if (first_byte > buffer -> tail) {
61b844bf 204 bytes_this_copy = (sizeof buffer -> buf -
c936e8c1 205 first_byte);
61b844bf
TL
206 } else {
207 bytes_this_copy =
c936e8c1 208 buffer -> tail - first_byte;
61b844bf
TL
209 }
210 if (bytes_this_copy > bytes_remaining)
211 bytes_this_copy = bytes_remaining;
212 if (bufp) {
c936e8c1 213 memcpy (bufp, &buffer -> buf [first_byte],
61b844bf
TL
214 bytes_this_copy);
215 bufp += bytes_this_copy;
216 }
217 bytes_remaining -= bytes_this_copy;
c936e8c1 218 buffer -> head = first_byte + bytes_this_copy - 1;
61b844bf
TL
219 c -> in_bytes -= bytes_this_copy;
220 }
221
c936e8c1 222 if (!BYTES_IN_BUFFER (buffer))
61b844bf
TL
223 buffer = buffer -> next;
224 }
225
226 /* Get rid of any input buffers that we emptied. */
227 buffer = (omapi_buffer_t *)0;
228 while (c -> inbufs &&
c936e8c1 229 !BYTES_IN_BUFFER (c -> inbufs)) {
61b844bf 230 if (c -> inbufs -> next) {
4bd8800e
TL
231 omapi_buffer_reference (&buffer,
232 c -> inbufs -> next, MDL);
233 omapi_buffer_dereference (&c -> inbufs -> next, MDL);
61b844bf 234 }
4bd8800e 235 omapi_buffer_dereference (&c -> inbufs, MDL);
c936e8c1
TL
236 if (buffer) {
237 omapi_buffer_reference
4bd8800e
TL
238 (&c -> inbufs, buffer, MDL);
239 omapi_buffer_dereference (&buffer, MDL);
c936e8c1 240 }
61b844bf
TL
241 }
242 return ISC_R_SUCCESS;
243}
244
e92653f1 245isc_result_t omapi_connection_writer (omapi_object_t *h)
61b844bf 246{
b1b7b521 247 unsigned bytes_this_write;
f0b8a59f 248 int bytes_written;
c936e8c1 249 unsigned first_byte;
61b844bf
TL
250 omapi_buffer_t *buffer;
251 unsigned char *bufp;
252 omapi_connection_object_t *c;
253
254 if (!h || h -> type != omapi_type_connection)
255 return ISC_R_INVALIDARG;
256 c = (omapi_connection_object_t *)h;
257
258 /* Already flushed... */
259 if (!c -> out_bytes)
260 return ISC_R_SUCCESS;
261
262 buffer = c -> outbufs;
263
264 while (c -> out_bytes) {
265 if (!buffer)
266 return ISC_R_UNEXPECTED;
c936e8c1
TL
267 if (BYTES_IN_BUFFER (buffer)) {
268 if (buffer -> head == (sizeof buffer -> buf) - 1)
269 first_byte = 0;
270 else
271 first_byte = buffer -> head + 1;
272
273 if (first_byte > buffer -> tail) {
61b844bf 274 bytes_this_write = (sizeof buffer -> buf -
c936e8c1 275 first_byte);
61b844bf
TL
276 } else {
277 bytes_this_write =
c936e8c1 278 buffer -> tail - first_byte;
61b844bf
TL
279 }
280 bytes_written = write (c -> socket,
c936e8c1 281 &buffer -> buf [first_byte],
61b844bf
TL
282 bytes_this_write);
283 /* If the write failed with EWOULDBLOCK or we wrote
284 zero bytes, a further write would block, so we have
285 flushed as much as we can for now. Other errors
286 are really errors. */
287 if (bytes_written < 0) {
288 if (errno == EWOULDBLOCK || errno == EAGAIN)
289 return ISC_R_SUCCESS;
290 else if (errno == EPIPE)
291 return ISC_R_NOCONN;
292 else if (errno == EFBIG || errno == EDQUOT)
293 return ISC_R_NORESOURCES;
294 else if (errno == ENOSPC)
295 return ISC_R_NOSPACE;
296 else if (errno == EIO)
297 return ISC_R_IOERROR;
298 else if (errno == EINVAL)
299 return ISC_R_INVALIDARG;
300 else if (errno == ECONNRESET)
301 return ISC_R_SHUTTINGDOWN;
302 else
303 return ISC_R_UNEXPECTED;
304 }
305 if (bytes_written == 0)
306 return ISC_R_SUCCESS;
307
c936e8c1 308 buffer -> head = first_byte + bytes_written - 1;
61b844bf
TL
309 c -> out_bytes -= bytes_written;
310
311 /* If we didn't finish out the write, we filled the
312 O.S. output buffer and a further write would block,
313 so stop trying to flush now. */
314 if (bytes_written != bytes_this_write)
315 return ISC_R_SUCCESS;
316 }
317
c936e8c1 318 if (!BYTES_IN_BUFFER (buffer))
61b844bf
TL
319 buffer = buffer -> next;
320 }
321
322 /* Get rid of any output buffers we emptied. */
323 buffer = (omapi_buffer_t *)0;
324 while (c -> outbufs &&
c936e8c1 325 !BYTES_IN_BUFFER (c -> outbufs)) {
61b844bf 326 if (c -> outbufs -> next) {
4bd8800e
TL
327 omapi_buffer_reference (&buffer,
328 c -> outbufs -> next, MDL);
329 omapi_buffer_dereference (&c -> outbufs -> next, MDL);
61b844bf 330 }
4bd8800e 331 omapi_buffer_dereference (&c -> outbufs, MDL);
61b844bf 332 if (buffer) {
4bd8800e
TL
333 omapi_buffer_reference (&c -> outbufs, buffer, MDL);
334 omapi_buffer_dereference (&buffer, MDL);
61b844bf
TL
335 }
336 }
337 return ISC_R_SUCCESS;
338}
339
340isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
341 u_int32_t *result)
342{
343 u_int32_t inbuf;
344 isc_result_t status;
345
346 status = omapi_connection_copyout ((unsigned char *)&inbuf,
347 c, sizeof inbuf);
348 if (status != ISC_R_SUCCESS)
349 return status;
350
351 *result = ntohl (inbuf);
352 return ISC_R_SUCCESS;
353}
354
355isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
356 u_int32_t value)
357{
358 u_int32_t inbuf;
359 isc_result_t status;
360
361 inbuf = htonl (value);
362
363 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
364 sizeof inbuf);
365}
366
367isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
368 u_int16_t *result)
369{
370 u_int16_t inbuf;
371 isc_result_t status;
372
373 status = omapi_connection_copyout ((unsigned char *)&inbuf,
374 c, sizeof inbuf);
375 if (status != ISC_R_SUCCESS)
376 return status;
377
378 *result = ntohs (inbuf);
379 return ISC_R_SUCCESS;
380}
381
382isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
b1b7b521 383 u_int32_t value)
61b844bf
TL
384{
385 u_int16_t inbuf;
386 isc_result_t status;
387
388 inbuf = htons (value);
389
390 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
391 sizeof inbuf);
392}
393
581e37e4
TL
394isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
395 omapi_typed_data_t *data)
396{
397 isc_result_t status;
398 omapi_handle_t handle;
399
400 switch (data -> type) {
401 case omapi_datatype_int:
402 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
403 if (status != ISC_R_SUCCESS)
404 return status;
b1b7b521
TL
405 return omapi_connection_put_uint32 (c, ((u_int32_t)
406 (data -> u.integer)));
581e37e4
TL
407
408 case omapi_datatype_string:
409 case omapi_datatype_data:
410 status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
411 if (status != ISC_R_SUCCESS)
412 return status;
0e603324
TL
413 if (data -> u.buffer.len)
414 return omapi_connection_copyin
415 (c, data -> u.buffer.value,
416 data -> u.buffer.len);
417 return ISC_R_SUCCESS;
581e37e4
TL
418
419 case omapi_datatype_object:
0e603324
TL
420 if (data -> u.object) {
421 status = omapi_object_handle (&handle,
422 data -> u.object);
423 if (status != ISC_R_SUCCESS)
424 return status;
425 } else
426 handle = 0;
581e37e4
TL
427 status = omapi_connection_put_uint32 (c, sizeof handle);
428 if (status != ISC_R_SUCCESS)
429 return status;
430 return omapi_connection_put_uint32 (c, handle);
431
432 }
433 return ISC_R_INVALIDARG;
434}
435
b1b7b521 436isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
581e37e4
TL
437{
438 isc_result_t status;
b1b7b521 439 unsigned len = strlen (name);
581e37e4
TL
440
441 status = omapi_connection_put_uint16 (c, len);
442 if (status != ISC_R_SUCCESS)
443 return status;
b1b7b521 444 return omapi_connection_copyin (c, (const unsigned char *)name, len);
581e37e4
TL
445}
446
b1b7b521
TL
447isc_result_t omapi_connection_put_string (omapi_object_t *c,
448 const char *string)
581e37e4
TL
449{
450 isc_result_t status;
b1b7b521 451 unsigned len;
581e37e4 452
0e603324
TL
453 if (string)
454 len = strlen (string);
455 else
456 len = 0;
581e37e4
TL
457
458 status = omapi_connection_put_uint32 (c, len);
459 if (status != ISC_R_SUCCESS)
460 return status;
0e603324
TL
461 if (len)
462 return omapi_connection_copyin
463 (c, (const unsigned char *)string, len);
464 return ISC_R_SUCCESS;
581e37e4
TL
465}
466
467isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
468{
469 isc_result_t status;
470 omapi_handle_t handle;
471
0e603324
TL
472 if (h) {
473 status = omapi_object_handle (&handle, h);
474 if (status != ISC_R_SUCCESS)
475 return status;
476 } else
477 handle = 0; /* The null handle. */
581e37e4
TL
478 status = omapi_connection_put_uint32 (c, sizeof handle);
479 if (status != ISC_R_SUCCESS)
480 return status;
481 return omapi_connection_put_uint32 (c, handle);
482}