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