]>
Commit | Line | Data |
---|---|---|
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 | ||
28 | isc_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 | ||
113 | isc_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 |
173 | isc_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 | 245 | isc_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 | ||
340 | isc_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 | ||
355 | isc_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 | ||
367 | isc_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 | ||
382 | isc_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 |
394 | isc_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 | 436 | isc_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 |
447 | isc_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 | ||
467 | isc_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 | } |