Annotation of embedaddon/dhcp/omapip/connection.c, revision 1.1.1.1
1.1 misho 1: /* connection.c
2:
3: Subroutines for dealing with connections. */
4:
5: /*
6: * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 2004,2007 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 <arpa/inet.h>
40: #include <arpa/nameser.h>
41: #include <errno.h>
42:
43:
44: #if defined (TRACING)
45: static void trace_connect_input (trace_type_t *, unsigned, char *);
46: static void trace_connect_stop (trace_type_t *);
47: static void trace_disconnect_input (trace_type_t *, unsigned, char *);
48: static void trace_disconnect_stop (trace_type_t *);
49: trace_type_t *trace_connect;
50: trace_type_t *trace_disconnect;
51: extern omapi_array_t *trace_listeners;
52: #endif
53: static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
54:
55: OMAPI_OBJECT_ALLOC (omapi_connection,
56: omapi_connection_object_t, omapi_type_connection)
57:
58: isc_result_t omapi_connect (omapi_object_t *c,
59: const char *server_name,
60: unsigned port)
61: {
62: struct hostent *he;
63: unsigned i, hix;
64: omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
65: struct in_addr foo;
66: isc_result_t status;
67:
68: #ifdef DEBUG_PROTOCOL
69: log_debug ("omapi_connect(%s, port=%d)", server_name, port);
70: #endif
71:
72: if (!inet_aton (server_name, &foo)) {
73: /* If we didn't get a numeric address, try for a domain
74: name. It's okay for this call to block. */
75: he = gethostbyname (server_name);
76: if (!he)
77: return ISC_R_HOSTUNKNOWN;
78: for (i = 0; he -> h_addr_list [i]; i++)
79: ;
80: if (i == 0)
81: return ISC_R_HOSTUNKNOWN;
82: hix = i;
83:
84: status = omapi_addr_list_new (&addrs, hix, MDL);
85: if (status != ISC_R_SUCCESS)
86: return status;
87: for (i = 0; i < hix; i++) {
88: addrs -> addresses [i].addrtype = he -> h_addrtype;
89: addrs -> addresses [i].addrlen = he -> h_length;
90: memcpy (addrs -> addresses [i].address,
91: he -> h_addr_list [i],
92: (unsigned)he -> h_length);
93: addrs -> addresses [i].port = port;
94: }
95: } else {
96: status = omapi_addr_list_new (&addrs, 1, MDL);
97: if (status != ISC_R_SUCCESS)
98: return status;
99: addrs -> addresses [0].addrtype = AF_INET;
100: addrs -> addresses [0].addrlen = sizeof foo;
101: memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
102: addrs -> addresses [0].port = port;
103: hix = 1;
104: }
105: status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
106: omapi_addr_list_dereference (&addrs, MDL);
107: return status;
108: }
109:
110: isc_result_t omapi_connect_list (omapi_object_t *c,
111: omapi_addr_list_t *remote_addrs,
112: omapi_addr_t *local_addr)
113: {
114: isc_result_t status;
115: omapi_connection_object_t *obj;
116: int flag;
117: struct sockaddr_in local_sin;
118:
119: obj = (omapi_connection_object_t *)0;
120: status = omapi_connection_allocate (&obj, MDL);
121: if (status != ISC_R_SUCCESS)
122: return status;
123:
124: status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
125: MDL);
126: if (status != ISC_R_SUCCESS) {
127: omapi_connection_dereference (&obj, MDL);
128: return status;
129: }
130: status = omapi_object_reference (&obj -> inner, c, MDL);
131: if (status != ISC_R_SUCCESS) {
132: omapi_connection_dereference (&obj, MDL);
133: return status;
134: }
135:
136: /* Store the address list on the object. */
137: omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
138: obj -> cptr = 0;
139: obj -> state = omapi_connection_unconnected;
140:
141: #if defined (TRACING)
142: /* If we're playing back, don't actually try to connect - just leave
143: the object available for a subsequent connect or disconnect. */
144: if (!trace_playback ()) {
145: #endif
146: /* Create a socket on which to communicate. */
147: obj -> socket =
148: socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
149: if (obj -> socket < 0) {
150: omapi_connection_dereference (&obj, MDL);
151: if (errno == EMFILE || errno == ENFILE
152: || errno == ENOBUFS)
153: return ISC_R_NORESOURCES;
154: return ISC_R_UNEXPECTED;
155: }
156:
157: /* Set up the local address, if any. */
158: if (local_addr) {
159: /* Only do TCPv4 so far. */
160: if (local_addr -> addrtype != AF_INET) {
161: omapi_connection_dereference (&obj, MDL);
162: return ISC_R_INVALIDARG;
163: }
164: local_sin.sin_port = htons (local_addr -> port);
165: memcpy (&local_sin.sin_addr,
166: local_addr -> address,
167: local_addr -> addrlen);
168: #if defined (HAVE_SA_LEN)
169: local_sin.sin_len = sizeof local_addr;
170: #endif
171: local_sin.sin_family = AF_INET;
172: memset (&local_sin.sin_zero, 0,
173: sizeof local_sin.sin_zero);
174:
175: if (bind (obj -> socket, (struct sockaddr *)&local_sin,
176: sizeof local_sin) < 0) {
177: omapi_connection_object_t **objp = &obj;
178: omapi_object_t **o = (omapi_object_t **)objp;
179: omapi_object_dereference(o, MDL);
180: if (errno == EADDRINUSE)
181: return ISC_R_ADDRINUSE;
182: if (errno == EADDRNOTAVAIL)
183: return ISC_R_ADDRNOTAVAIL;
184: if (errno == EACCES)
185: return ISC_R_NOPERM;
186: return ISC_R_UNEXPECTED;
187: }
188: obj -> local_addr = local_sin;
189: }
190:
191: #if defined(F_SETFD)
192: if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
193: close (obj -> socket);
194: omapi_connection_dereference (&obj, MDL);
195: return ISC_R_UNEXPECTED;
196: }
197: #endif
198:
199: /* Set the SO_REUSEADDR flag (this should not fail). */
200: flag = 1;
201: if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
202: (char *)&flag, sizeof flag) < 0) {
203: omapi_connection_dereference (&obj, MDL);
204: return ISC_R_UNEXPECTED;
205: }
206:
207: /* Set the file to nonblocking mode. */
208: if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
209: omapi_connection_dereference (&obj, MDL);
210: return ISC_R_UNEXPECTED;
211: }
212:
213: #ifdef SO_NOSIGPIPE
214: /*
215: * If available stop the OS from killing our
216: * program on a SIGPIPE failure
217: */
218: flag = 1;
219: if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
220: (char *)&flag, sizeof(flag)) < 0) {
221: omapi_connection_dereference (&obj, MDL);
222: return ISC_R_UNEXPECTED;
223: }
224: #endif
225:
226: status = (omapi_register_io_object
227: ((omapi_object_t *)obj,
228: 0, omapi_connection_writefd,
229: 0, omapi_connection_connect,
230: omapi_connection_reaper));
231: if (status != ISC_R_SUCCESS)
232: goto out;
233: status = omapi_connection_connect_internal ((omapi_object_t *)
234: obj);
235: #if defined (TRACING)
236: }
237: omapi_connection_register (obj, MDL);
238: #endif
239:
240: out:
241: omapi_connection_dereference (&obj, MDL);
242: return status;
243: }
244:
245: #if defined (TRACING)
246: omapi_array_t *omapi_connections;
247:
248: OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
249:
250: void omapi_connection_trace_setup (void) {
251: trace_connect = trace_type_register ("connect", (void *)0,
252: trace_connect_input,
253: trace_connect_stop, MDL);
254: trace_disconnect = trace_type_register ("disconnect", (void *)0,
255: trace_disconnect_input,
256: trace_disconnect_stop, MDL);
257: }
258:
259: void omapi_connection_register (omapi_connection_object_t *obj,
260: const char *file, int line)
261: {
262: isc_result_t status;
263: trace_iov_t iov [6];
264: int iov_count = 0;
265: int32_t connect_index, listener_index;
266: static int32_t index;
267:
268: if (!omapi_connections) {
269: status = omapi_connection_array_allocate (&omapi_connections,
270: file, line);
271: if (status != ISC_R_SUCCESS)
272: return;
273: }
274:
275: status = omapi_connection_array_extend (omapi_connections, obj,
276: (int *)0, file, line);
277: if (status != ISC_R_SUCCESS) {
278: obj -> index = -1;
279: return;
280: }
281:
282: #if defined (TRACING)
283: if (trace_record ()) {
284: /* Connection registration packet:
285:
286: int32_t index
287: int32_t listener_index [-1 means no listener]
288: u_int16_t remote_port
289: u_int16_t local_port
290: u_int32_t remote_addr
291: u_int32_t local_addr */
292:
293: connect_index = htonl (index);
294: index++;
295: if (obj -> listener)
296: listener_index = htonl (obj -> listener -> index);
297: else
298: listener_index = htonl (-1);
299: iov [iov_count].buf = (char *)&connect_index;
300: iov [iov_count++].len = sizeof connect_index;
301: iov [iov_count].buf = (char *)&listener_index;
302: iov [iov_count++].len = sizeof listener_index;
303: iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
304: iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
305: iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
306: iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
307: iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
308: iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
309: iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
310: iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
311:
312: status = trace_write_packet_iov (trace_connect,
313: iov_count, iov, file, line);
314: }
315: #endif
316: }
317:
318: static void trace_connect_input (trace_type_t *ttype,
319: unsigned length, char *buf)
320: {
321: struct sockaddr_in remote, local;
322: int32_t connect_index, listener_index;
323: char *s = buf;
324: omapi_connection_object_t *obj;
325: isc_result_t status;
326: int i;
327:
328: if (length != ((sizeof connect_index) +
329: (sizeof remote.sin_port) +
330: (sizeof remote.sin_addr)) * 2) {
331: log_error ("Trace connect: invalid length %d", length);
332: return;
333: }
334:
335: memset (&remote, 0, sizeof remote);
336: memset (&local, 0, sizeof local);
337: memcpy (&connect_index, s, sizeof connect_index);
338: s += sizeof connect_index;
339: memcpy (&listener_index, s, sizeof listener_index);
340: s += sizeof listener_index;
341: memcpy (&remote.sin_port, s, sizeof remote.sin_port);
342: s += sizeof remote.sin_port;
343: memcpy (&local.sin_port, s, sizeof local.sin_port);
344: s += sizeof local.sin_port;
345: memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
346: s += sizeof remote.sin_addr;
347: memcpy (&local.sin_addr, s, sizeof local.sin_addr);
348: s += sizeof local.sin_addr;
349:
350: connect_index = ntohl (connect_index);
351: listener_index = ntohl (listener_index);
352:
353: /* If this was a connect to a listener, then we just slap together
354: a new connection. */
355: if (listener_index != -1) {
356: omapi_listener_object_t *listener;
357: listener = (omapi_listener_object_t *)0;
358: omapi_array_foreach_begin (trace_listeners,
359: omapi_listener_object_t, lp) {
360: if (lp -> address.sin_port == local.sin_port) {
361: omapi_listener_reference (&listener, lp, MDL);
362: omapi_listener_dereference (&lp, MDL);
363: break;
364: }
365: } omapi_array_foreach_end (trace_listeners,
366: omapi_listener_object_t, lp);
367: if (!listener) {
368: log_error ("%s%ld, addr %s, port %d",
369: "Spurious traced listener connect - index ",
370: (long int)listener_index,
371: inet_ntoa (local.sin_addr),
372: ntohs (local.sin_port));
373: return;
374: }
375: obj = (omapi_connection_object_t *)0;
376: status = omapi_listener_connect (&obj, listener, -1, &remote);
377: if (status != ISC_R_SUCCESS) {
378: log_error ("traced listener connect: %s",
379: isc_result_totext (status));
380: }
381: if (obj)
382: omapi_connection_dereference (&obj, MDL);
383: omapi_listener_dereference (&listener, MDL);
384: return;
385: }
386:
387: /* Find the matching connect object, if there is one. */
388: omapi_array_foreach_begin (omapi_connections,
389: omapi_connection_object_t, lp) {
390: for (i = 0; (lp -> connect_list &&
391: i < lp -> connect_list -> count); i++) {
392: if (!memcmp (&remote.sin_addr,
393: &lp -> connect_list -> addresses [i].address,
394: sizeof remote.sin_addr) &&
395: (ntohs (remote.sin_port) ==
396: lp -> connect_list -> addresses [i].port))
397: lp -> state = omapi_connection_connected;
398: lp -> remote_addr = remote;
399: lp -> remote_addr.sin_family = AF_INET;
400: omapi_addr_list_dereference (&lp -> connect_list, MDL);
401: lp -> index = connect_index;
402: status = omapi_signal_in ((omapi_object_t *)lp,
403: "connect");
404: omapi_connection_dereference (&lp, MDL);
405: return;
406: }
407: } omapi_array_foreach_end (omapi_connections,
408: omapi_connection_object_t, lp);
409:
410: log_error ("Spurious traced connect - index %ld, addr %s, port %d",
411: (long int)connect_index, inet_ntoa (remote.sin_addr),
412: ntohs (remote.sin_port));
413: return;
414: }
415:
416: static void trace_connect_stop (trace_type_t *ttype) { }
417:
418: static void trace_disconnect_input (trace_type_t *ttype,
419: unsigned length, char *buf)
420: {
421: int32_t *index;
422: if (length != sizeof *index) {
423: log_error ("trace disconnect: wrong length %d", length);
424: return;
425: }
426:
427: index = (int32_t *)buf;
428:
429: omapi_array_foreach_begin (omapi_connections,
430: omapi_connection_object_t, lp) {
431: if (lp -> index == ntohl (*index)) {
432: omapi_disconnect ((omapi_object_t *)lp, 1);
433: omapi_connection_dereference (&lp, MDL);
434: return;
435: }
436: } omapi_array_foreach_end (omapi_connections,
437: omapi_connection_object_t, lp);
438:
439: log_error ("trace disconnect: no connection matching index %ld",
440: (long int)ntohl (*index));
441: }
442:
443: static void trace_disconnect_stop (trace_type_t *ttype) { }
444: #endif
445:
446: /* Disconnect a connection object from the remote end. If force is nonzero,
447: close the connection immediately. Otherwise, shut down the receiving end
448: but allow any unsent data to be sent before actually closing the socket. */
449:
450: isc_result_t omapi_disconnect (omapi_object_t *h,
451: int force)
452: {
453: omapi_connection_object_t *c;
454:
455: #ifdef DEBUG_PROTOCOL
456: log_debug ("omapi_disconnect(%s)", force ? "force" : "");
457: #endif
458:
459: c = (omapi_connection_object_t *)h;
460: if (c -> type != omapi_type_connection)
461: return ISC_R_INVALIDARG;
462:
463: #if defined (TRACING)
464: if (trace_record ()) {
465: isc_result_t status;
466: int32_t index;
467:
468: index = htonl (c -> index);
469: status = trace_write_packet (trace_disconnect,
470: sizeof index, (char *)&index,
471: MDL);
472: if (status != ISC_R_SUCCESS) {
473: trace_stop ();
474: log_error ("trace_write_packet: %s",
475: isc_result_totext (status));
476: }
477: }
478: if (!trace_playback ()) {
479: #endif
480: if (!force) {
481: /* If we're already disconnecting, we don't have to do
482: anything. */
483: if (c -> state == omapi_connection_disconnecting)
484: return ISC_R_SUCCESS;
485:
486: /* Try to shut down the socket - this sends a FIN to
487: the remote end, so that it won't send us any more
488: data. If the shutdown succeeds, and we still
489: have bytes left to write, defer closing the socket
490: until that's done. */
491: if (!shutdown (c -> socket, SHUT_RD)) {
492: if (c -> out_bytes > 0) {
493: c -> state =
494: omapi_connection_disconnecting;
495: return ISC_R_SUCCESS;
496: }
497: }
498: }
499: close (c -> socket);
500: #if defined (TRACING)
501: }
502: #endif
503: c -> state = omapi_connection_closed;
504:
505: /* Disconnect from I/O object, if any. */
506: if (h -> outer) {
507: if (h -> outer -> inner)
508: omapi_object_dereference (&h -> outer -> inner, MDL);
509: omapi_object_dereference (&h -> outer, MDL);
510: }
511:
512: /* If whatever created us registered a signal handler, send it
513: a disconnect signal. */
514: omapi_signal (h, "disconnect", h);
515:
516: /* Disconnect from protocol object, if any. */
517: if (h->inner != NULL) {
518: if (h->inner->outer != NULL) {
519: omapi_object_dereference(&h->inner->outer, MDL);
520: }
521: omapi_object_dereference(&h->inner, MDL);
522: }
523:
524: /* XXX: the code to free buffers should be in the dereference
525: function, but there is no special-purpose function to
526: dereference connections, so these just get leaked */
527: /* Free any buffers */
528: if (c->inbufs != NULL) {
529: omapi_buffer_dereference(&c->inbufs, MDL);
530: }
531: c->in_bytes = 0;
532: if (c->outbufs != NULL) {
533: omapi_buffer_dereference(&c->outbufs, MDL);
534: }
535: c->out_bytes = 0;
536:
537: return ISC_R_SUCCESS;
538: }
539:
540: isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
541: {
542: omapi_connection_object_t *c;
543:
544: if (h -> type != omapi_type_connection)
545: return ISC_R_INVALIDARG;
546: c = (omapi_connection_object_t *)h;
547:
548: c -> bytes_needed = bytes;
549: if (c -> bytes_needed <= c -> in_bytes) {
550: return ISC_R_SUCCESS;
551: }
552: return ISC_R_NOTYET;
553: }
554:
555: /* Return the socket on which the dispatcher should wait for readiness
556: to read, for a connection object. If we already have more bytes than
557: we need to do the next thing, and we have at least a single full input
558: buffer, then don't indicate that we're ready to read. */
559: int omapi_connection_readfd (omapi_object_t *h)
560: {
561: omapi_connection_object_t *c;
562: if (h -> type != omapi_type_connection)
563: return -1;
564: c = (omapi_connection_object_t *)h;
565: if (c -> state != omapi_connection_connected)
566: return -1;
567: if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
568: c -> in_bytes > c -> bytes_needed)
569: return -1;
570: return c -> socket;
571: }
572:
573: /* Return the socket on which the dispatcher should wait for readiness
574: to write, for a connection object. If there are no bytes buffered
575: for writing, then don't indicate that we're ready to write. */
576: int omapi_connection_writefd (omapi_object_t *h)
577: {
578: omapi_connection_object_t *c;
579: if (h -> type != omapi_type_connection)
580: return -1;
581: c = (omapi_connection_object_t *)h;
582: if (c -> state == omapi_connection_connecting)
583: return c -> socket;
584: if (c -> out_bytes)
585: return c -> socket;
586: else
587: return -1;
588: }
589:
590: isc_result_t omapi_connection_connect (omapi_object_t *h)
591: {
592: isc_result_t status;
593:
594: status = omapi_connection_connect_internal (h);
595: if (status != ISC_R_SUCCESS)
596: omapi_signal (h, "status", status);
597: return ISC_R_SUCCESS;
598: }
599:
600: static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
601: {
602: int error;
603: omapi_connection_object_t *c;
604: socklen_t sl;
605: isc_result_t status;
606:
607: if (h -> type != omapi_type_connection)
608: return ISC_R_INVALIDARG;
609: c = (omapi_connection_object_t *)h;
610:
611: if (c -> state == omapi_connection_connecting) {
612: sl = sizeof error;
613: if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
614: (char *)&error, &sl) < 0) {
615: omapi_disconnect (h, 1);
616: return ISC_R_SUCCESS;
617: }
618: if (!error)
619: c -> state = omapi_connection_connected;
620: }
621: if (c -> state == omapi_connection_connecting ||
622: c -> state == omapi_connection_unconnected) {
623: if (c -> cptr >= c -> connect_list -> count) {
624: switch (error) {
625: case ECONNREFUSED:
626: status = ISC_R_CONNREFUSED;
627: break;
628: case ENETUNREACH:
629: status = ISC_R_NETUNREACH;
630: break;
631: default:
632: status = uerr2isc (error);
633: break;
634: }
635: omapi_disconnect (h, 1);
636: return status;
637: }
638:
639: if (c -> connect_list -> addresses [c -> cptr].addrtype !=
640: AF_INET) {
641: omapi_disconnect (h, 1);
642: return ISC_R_INVALIDARG;
643: }
644:
645: memcpy (&c -> remote_addr.sin_addr,
646: &c -> connect_list -> addresses [c -> cptr].address,
647: sizeof c -> remote_addr.sin_addr);
648: c -> remote_addr.sin_family = AF_INET;
649: c -> remote_addr.sin_port =
650: htons (c -> connect_list -> addresses [c -> cptr].port);
651: #if defined (HAVE_SA_LEN)
652: c -> remote_addr.sin_len = sizeof c -> remote_addr;
653: #endif
654: memset (&c -> remote_addr.sin_zero, 0,
655: sizeof c -> remote_addr.sin_zero);
656: ++c -> cptr;
657:
658: error = connect (c -> socket,
659: (struct sockaddr *)&c -> remote_addr,
660: sizeof c -> remote_addr);
661: if (error < 0) {
662: error = errno;
663: if (error != EINPROGRESS) {
664: omapi_disconnect (h, 1);
665: switch (error) {
666: case ECONNREFUSED:
667: status = ISC_R_CONNREFUSED;
668: break;
669: case ENETUNREACH:
670: status = ISC_R_NETUNREACH;
671: break;
672: default:
673: status = uerr2isc (error);
674: break;
675: }
676: return status;
677: }
678: c -> state = omapi_connection_connecting;
679: return ISC_R_INCOMPLETE;
680: }
681: c -> state = omapi_connection_connected;
682: }
683:
684: /* I don't know why this would fail, so I'm tempted not to test
685: the return value. */
686: sl = sizeof (c -> local_addr);
687: if (getsockname (c -> socket,
688: (struct sockaddr *)&c -> local_addr, &sl) < 0) {
689: }
690:
691: /* Reregister with the I/O object. If we don't already have an
692: I/O object this turns into a register call, otherwise we simply
693: modify the pointers in the I/O object. */
694:
695: status = omapi_reregister_io_object (h,
696: omapi_connection_readfd,
697: omapi_connection_writefd,
698: omapi_connection_reader,
699: omapi_connection_writer,
700: omapi_connection_reaper);
701:
702: if (status != ISC_R_SUCCESS) {
703: omapi_disconnect (h, 1);
704: return status;
705: }
706:
707: omapi_signal_in (h, "connect");
708: omapi_addr_list_dereference (&c -> connect_list, MDL);
709: return ISC_R_SUCCESS;
710: }
711:
712: /* Reaper function for connection - if the connection is completely closed,
713: reap it. If it's in the disconnecting state, there were bytes left
714: to write when the user closed it, so if there are now no bytes left to
715: write, we can close it. */
716: isc_result_t omapi_connection_reaper (omapi_object_t *h)
717: {
718: omapi_connection_object_t *c;
719:
720: if (h -> type != omapi_type_connection)
721: return ISC_R_INVALIDARG;
722:
723: c = (omapi_connection_object_t *)h;
724: if (c -> state == omapi_connection_disconnecting &&
725: c -> out_bytes == 0) {
726: #ifdef DEBUG_PROTOCOL
727: log_debug ("omapi_connection_reaper(): disconnect");
728: #endif
729: omapi_disconnect (h, 1);
730: }
731: if (c -> state == omapi_connection_closed) {
732: #ifdef DEBUG_PROTOCOL
733: log_debug ("omapi_connection_reaper(): closed");
734: #endif
735: return ISC_R_NOTCONNECTED;
736: }
737: return ISC_R_SUCCESS;
738: }
739:
740: static isc_result_t make_dst_key (DST_KEY **dst_key, omapi_object_t *a) {
741: omapi_value_t *name = (omapi_value_t *)0;
742: omapi_value_t *algorithm = (omapi_value_t *)0;
743: omapi_value_t *key = (omapi_value_t *)0;
744: int algorithm_id = UNKNOWN_KEYALG;
745: char *name_str = NULL;
746: isc_result_t status = ISC_R_SUCCESS;
747:
748: if (status == ISC_R_SUCCESS)
749: status = omapi_get_value_str
750: (a, (omapi_object_t *)0, "name", &name);
751:
752: if (status == ISC_R_SUCCESS)
753: status = omapi_get_value_str
754: (a, (omapi_object_t *)0, "algorithm", &algorithm);
755:
756: if (status == ISC_R_SUCCESS)
757: status = omapi_get_value_str
758: (a, (omapi_object_t *)0, "key", &key);
759:
760: if (status == ISC_R_SUCCESS) {
761: if ((algorithm -> value -> type == omapi_datatype_data ||
762: algorithm -> value -> type == omapi_datatype_string) &&
763: strncasecmp ((char *)algorithm -> value -> u.buffer.value,
764: NS_TSIG_ALG_HMAC_MD5 ".",
765: algorithm -> value -> u.buffer.len) == 0) {
766: algorithm_id = KEY_HMAC_MD5;
767: } else {
768: status = ISC_R_INVALIDARG;
769: }
770: }
771:
772: if (status == ISC_R_SUCCESS) {
773: name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
774: if (!name_str)
775: status = ISC_R_NOMEMORY;
776: }
777:
778: if (status == ISC_R_SUCCESS) {
779: memcpy (name_str,
780: name -> value -> u.buffer.value,
781: name -> value -> u.buffer.len);
782: name_str [name -> value -> u.buffer.len] = 0;
783:
784: *dst_key = dst_buffer_to_key (name_str, algorithm_id, 0, 0,
785: key -> value -> u.buffer.value,
786: key -> value -> u.buffer.len);
787: if (!*dst_key)
788: status = ISC_R_NOMEMORY;
789: }
790:
791: if (name_str)
792: dfree (name_str, MDL);
793: if (key)
794: omapi_value_dereference (&key, MDL);
795: if (algorithm)
796: omapi_value_dereference (&algorithm, MDL);
797: if (name)
798: omapi_value_dereference (&name, MDL);
799:
800: return status;
801: }
802:
803: isc_result_t omapi_connection_sign_data (int mode,
804: DST_KEY *key,
805: void **context,
806: const unsigned char *data,
807: const unsigned len,
808: omapi_typed_data_t **result)
809: {
810: omapi_typed_data_t *td = (omapi_typed_data_t *)0;
811: isc_result_t status;
812: int r;
813:
814: if (mode & SIG_MODE_FINAL) {
815: status = omapi_typed_data_new (MDL, &td,
816: omapi_datatype_data,
817: dst_sig_size (key));
818: if (status != ISC_R_SUCCESS)
819: return status;
820: }
821:
822: r = dst_sign_data (mode, key, context, data, len,
823: td ? td -> u.buffer.value : (u_char *)0,
824: td ? td -> u.buffer.len : 0);
825:
826: /* dst_sign_data() really should do this for us, shouldn't it? */
827: if (mode & SIG_MODE_FINAL)
828: *context = (void *)0;
829:
830: if (r < 0) {
831: if (td)
832: omapi_typed_data_dereference (&td, MDL);
833: return ISC_R_INVALIDKEY;
834: }
835:
836: if (result && td) {
837: omapi_typed_data_reference (result, td, MDL);
838: }
839:
840: if (td)
841: omapi_typed_data_dereference (&td, MDL);
842:
843: return ISC_R_SUCCESS;
844: }
845:
846: isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
847: unsigned *l)
848: {
849: omapi_connection_object_t *c;
850:
851: if (h -> type != omapi_type_connection)
852: return ISC_R_INVALIDARG;
853: c = (omapi_connection_object_t *)h;
854:
855: if (!c -> out_key)
856: return ISC_R_NOTFOUND;
857:
858: *l = dst_sig_size (c -> out_key);
859: return ISC_R_SUCCESS;
860: }
861:
862: isc_result_t omapi_connection_set_value (omapi_object_t *h,
863: omapi_object_t *id,
864: omapi_data_string_t *name,
865: omapi_typed_data_t *value)
866: {
867: omapi_connection_object_t *c;
868: isc_result_t status;
869:
870: if (h -> type != omapi_type_connection)
871: return ISC_R_INVALIDARG;
872: c = (omapi_connection_object_t *)h;
873:
874: if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
875: if (value && value -> type != omapi_datatype_object)
876: return ISC_R_INVALIDARG;
877:
878: if (c -> in_context) {
879: omapi_connection_sign_data (SIG_MODE_FINAL,
880: c -> in_key,
881: &c -> in_context,
882: 0, 0,
883: (omapi_typed_data_t **) 0);
884: }
885:
886: if (c -> in_key) {
887: dst_free_key (c -> in_key);
888: c -> in_key = (DST_KEY *)0;
889: }
890:
891: if (value) {
892: status = make_dst_key (&c -> in_key,
893: value -> u.object);
894: if (status != ISC_R_SUCCESS)
895: return status;
896: }
897:
898: return ISC_R_SUCCESS;
899: }
900: else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
901: if (value && value -> type != omapi_datatype_object)
902: return ISC_R_INVALIDARG;
903:
904: if (c -> out_context) {
905: omapi_connection_sign_data (SIG_MODE_FINAL,
906: c -> out_key,
907: &c -> out_context,
908: 0, 0,
909: (omapi_typed_data_t **) 0);
910: }
911:
912: if (c -> out_key) {
913: dst_free_key (c -> out_key);
914: c -> out_key = (DST_KEY *)0;
915: }
916:
917: if (value) {
918: status = make_dst_key (&c -> out_key,
919: value -> u.object);
920: if (status != ISC_R_SUCCESS)
921: return status;
922: }
923:
924: return ISC_R_SUCCESS;
925: }
926:
927: if (h -> inner && h -> inner -> type -> set_value)
928: return (*(h -> inner -> type -> set_value))
929: (h -> inner, id, name, value);
930: return ISC_R_NOTFOUND;
931: }
932:
933: isc_result_t omapi_connection_get_value (omapi_object_t *h,
934: omapi_object_t *id,
935: omapi_data_string_t *name,
936: omapi_value_t **value)
937: {
938: omapi_connection_object_t *c;
939: omapi_typed_data_t *td = (omapi_typed_data_t *)0;
940: isc_result_t status;
941:
942: if (h -> type != omapi_type_connection)
943: return ISC_R_INVALIDARG;
944: c = (omapi_connection_object_t *)h;
945:
946: if (omapi_ds_strcmp (name, "input-signature") == 0) {
947: if (!c -> in_key || !c -> in_context)
948: return ISC_R_NOTFOUND;
949:
950: status = omapi_connection_sign_data (SIG_MODE_FINAL,
951: c -> in_key,
952: &c -> in_context,
953: 0, 0, &td);
954: if (status != ISC_R_SUCCESS)
955: return status;
956:
957: status = omapi_make_value (value, name, td, MDL);
958: omapi_typed_data_dereference (&td, MDL);
959: return status;
960:
961: } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
962: if (!c -> in_key)
963: return ISC_R_NOTFOUND;
964:
965: return omapi_make_int_value (value, name,
966: dst_sig_size (c -> in_key), MDL);
967:
968: } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
969: if (!c -> out_key || !c -> out_context)
970: return ISC_R_NOTFOUND;
971:
972: status = omapi_connection_sign_data (SIG_MODE_FINAL,
973: c -> out_key,
974: &c -> out_context,
975: 0, 0, &td);
976: if (status != ISC_R_SUCCESS)
977: return status;
978:
979: status = omapi_make_value (value, name, td, MDL);
980: omapi_typed_data_dereference (&td, MDL);
981: return status;
982:
983: } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
984: if (!c -> out_key)
985: return ISC_R_NOTFOUND;
986:
987: return omapi_make_int_value (value, name,
988: dst_sig_size (c -> out_key), MDL);
989: }
990:
991: if (h -> inner && h -> inner -> type -> get_value)
992: return (*(h -> inner -> type -> get_value))
993: (h -> inner, id, name, value);
994: return ISC_R_NOTFOUND;
995: }
996:
997: isc_result_t omapi_connection_destroy (omapi_object_t *h,
998: const char *file, int line)
999: {
1000: omapi_connection_object_t *c;
1001:
1002: #ifdef DEBUG_PROTOCOL
1003: log_debug ("omapi_connection_destroy()");
1004: #endif
1005:
1006: if (h -> type != omapi_type_connection)
1007: return ISC_R_UNEXPECTED;
1008: c = (omapi_connection_object_t *)(h);
1009: if (c -> state == omapi_connection_connected)
1010: omapi_disconnect (h, 1);
1011: if (c -> listener)
1012: omapi_listener_dereference (&c -> listener, file, line);
1013: if (c -> connect_list)
1014: omapi_addr_list_dereference (&c -> connect_list, file, line);
1015: return ISC_R_SUCCESS;
1016: }
1017:
1018: isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
1019: const char *name, va_list ap)
1020: {
1021: if (h -> type != omapi_type_connection)
1022: return ISC_R_INVALIDARG;
1023:
1024: #ifdef DEBUG_PROTOCOL
1025: log_debug ("omapi_connection_signal_handler(%s)", name);
1026: #endif
1027:
1028: if (h -> inner && h -> inner -> type -> signal_handler)
1029: return (*(h -> inner -> type -> signal_handler)) (h -> inner,
1030: name, ap);
1031: return ISC_R_NOTFOUND;
1032: }
1033:
1034: /* Write all the published values associated with the object through the
1035: specified connection. */
1036:
1037: isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
1038: omapi_object_t *id,
1039: omapi_object_t *m)
1040: {
1041: if (m -> type != omapi_type_connection)
1042: return ISC_R_INVALIDARG;
1043:
1044: if (m -> inner && m -> inner -> type -> stuff_values)
1045: return (*(m -> inner -> type -> stuff_values)) (c, id,
1046: m -> inner);
1047: return ISC_R_SUCCESS;
1048: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>