Update for less-415.
[dragonfly.git] / contrib / dhcp-3.0 / dhcpctl / dhcpctl.c
1 /* dhcpctl.c
2
3    Subroutines providing general support for objects. */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 #ifndef lint
36 static char copyright[] =
37 "$Id: dhcpctl.c,v 1.22.2.7 2004/06/10 17:59:24 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #include <omapip/omapip_p.h>
41 #include "dhcpctl.h"
42
43 omapi_object_type_t *dhcpctl_callback_type;
44 omapi_object_type_t *dhcpctl_remote_type;
45
46 /* dhcpctl_initialize ()
47
48    Must be called before any other dhcpctl function. */
49
50 dhcpctl_status dhcpctl_initialize ()
51 {
52         isc_result_t status;
53
54         status = omapi_init();
55         if (status != ISC_R_SUCCESS)
56                 return status;
57
58         status = omapi_object_type_register (&dhcpctl_callback_type,
59                                              "dhcpctl-callback",
60                                              dhcpctl_callback_set_value,
61                                              dhcpctl_callback_get_value,
62                                              dhcpctl_callback_destroy,
63                                              dhcpctl_callback_signal_handler,
64                                              dhcpctl_callback_stuff_values,
65                                              0, 0, 0, 0, 0, 0,
66                                              sizeof
67                                              (dhcpctl_callback_object_t), 0,
68                                              RC_MISC);
69         if (status != ISC_R_SUCCESS)
70                 return status;
71
72         status = omapi_object_type_register (&dhcpctl_remote_type,
73                                              "dhcpctl-remote",
74                                              dhcpctl_remote_set_value,
75                                              dhcpctl_remote_get_value,
76                                              dhcpctl_remote_destroy,
77                                              dhcpctl_remote_signal_handler,
78                                              dhcpctl_remote_stuff_values,
79                                              0, 0, 0, 0, 0, 0,
80                                              sizeof (dhcpctl_remote_object_t),
81                                              0, RC_MISC);
82         if (status != ISC_R_SUCCESS)
83                 return status;
84
85         return ISC_R_SUCCESS;
86 }
87
88 /* dhcpctl_connect
89
90    synchronous
91    returns nonzero status code if it didn't connect, zero otherwise
92    stores connection handle through connection, which can be used
93    for subsequent access to the specified server. 
94    server_name is the name of the server, and port is the TCP
95    port on which it is listening.
96    authinfo is the handle to an object containing authentication
97    information. */
98
99 dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
100                                 const char *server_name, int port,
101                                 dhcpctl_handle authinfo)
102 {
103         isc_result_t status;
104         dhcpctl_status waitstatus;
105
106         status = omapi_generic_new (connection, MDL);
107         if (status != ISC_R_SUCCESS) {
108                 return status;
109         }
110
111         status = omapi_protocol_connect (*connection, server_name,
112                                          (unsigned)port, authinfo);
113         if (status == ISC_R_SUCCESS)
114                 return status;
115         if (status != ISC_R_INCOMPLETE) {
116                 omapi_object_dereference (connection, MDL);
117                 return status;
118         }
119
120         status = omapi_wait_for_completion (*connection, 0);
121         if (status != ISC_R_SUCCESS) {
122                 omapi_object_dereference (connection, MDL);
123                 return status;
124         }
125
126         return status;
127 }
128
129 /* dhcpctl_wait_for_completion
130
131    synchronous
132    returns zero if the callback completes, a nonzero status if
133    there was some problem relating to the wait operation.   The
134    status of the queued request will be stored through s, and
135    will also be either zero for success or nonzero for some kind
136    of failure.    Never returns until completion or until the
137    connection to the server is lost.   This performs the same
138    function as dhcpctl_set_callback and the subsequent callback,
139    for programs that want to do inline execution instead of using
140    callbacks. */
141
142 dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
143                                             dhcpctl_status *s)
144 {
145         isc_result_t status;
146         status = omapi_wait_for_completion (h, 0);
147         if (status != ISC_R_SUCCESS)
148                 return status;
149         if (h -> type == dhcpctl_remote_type)
150                 *s = ((dhcpctl_remote_object_t *)h) -> waitstatus;
151         return ISC_R_SUCCESS;
152 }
153
154 /* dhcpctl_get_value
155
156    synchronous
157    returns zero if the call succeeded, a nonzero status code if
158    it didn't. 
159    result is the address of an empty data string (initialized
160    with bzero or cleared with data_string_forget).   On
161    successful completion, the addressed data string will contain
162    the value that was fetched.
163    dhcpctl_handle refers to some dhcpctl item
164    value_name refers to some value related to that item - e.g.,
165    for a handle associated with a completed host lookup, value
166    could be one of "hardware-address", "dhcp-client-identifier",
167    "known" or "client-hostname". */
168
169 dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *result,
170                                   dhcpctl_handle h, const char *value_name)
171 {
172         isc_result_t status;
173         omapi_value_t *tv = (omapi_value_t *)0;
174         omapi_data_string_t *value = (omapi_data_string_t *)0;
175         unsigned len;
176         int ip;
177
178         status = omapi_get_value_str (h, (omapi_object_t *)0, value_name, &tv);
179         if (status != ISC_R_SUCCESS)
180                 return status;
181
182         switch (tv -> value -> type) {
183               case omapi_datatype_int:
184                 len = sizeof (int);
185                 break;
186
187               case omapi_datatype_string:
188               case omapi_datatype_data:
189                 len = tv -> value -> u.buffer.len;
190                 break;
191
192               case omapi_datatype_object:
193                 len = sizeof (omapi_handle_t);
194                 break;
195
196               default:
197                 omapi_typed_data_dereference (&tv -> value, MDL);
198                 return ISC_R_UNEXPECTED;
199         }
200
201         status = omapi_data_string_new (result, len, MDL);
202         if (status != ISC_R_SUCCESS) {
203                 omapi_typed_data_dereference (&tv -> value, MDL);
204                 return status;
205         }
206
207         switch (tv -> value -> type) {
208               case omapi_datatype_int:
209                 ip = htonl (tv -> value -> u.integer);
210                 memcpy ((*result) -> value, &ip, sizeof ip);
211                 break;
212
213               case omapi_datatype_string:
214               case omapi_datatype_data:
215                 memcpy ((*result) -> value,
216                         tv -> value -> u.buffer.value,
217                         tv -> value -> u.buffer.len);
218                 break;
219
220               case omapi_datatype_object:
221                 ip = htonl (tv -> value -> u.object -> handle);
222                 memcpy ((*result) -> value, &ip, sizeof ip);
223                 break;
224         }
225
226         omapi_value_dereference (&tv, MDL);
227         return ISC_R_SUCCESS;
228 }
229
230 /* dhcpctl_get_boolean
231
232    like dhcpctl_get_value, but more convenient for boolean
233    values, since no data_string needs to be dealt with. */
234
235 dhcpctl_status dhcpctl_get_boolean (int *result,
236                                     dhcpctl_handle h, const char *value_name)
237 {
238         isc_result_t status;
239         dhcpctl_data_string data = (dhcpctl_data_string)0;
240         int rv;
241         
242         status = dhcpctl_get_value (&data, h, value_name);
243         if (status != ISC_R_SUCCESS)
244                 return status;
245         if (data -> len != sizeof rv) {
246                 omapi_data_string_dereference (&data, MDL);
247                 return ISC_R_UNEXPECTED;
248         }
249         memcpy (&rv, data -> value, sizeof rv);
250         *result = ntohl (rv);
251         return ISC_R_SUCCESS;
252 }
253
254 /* dhcpctl_set_value
255
256    Sets a value on an object referred to by a dhcpctl_handle.
257    The opposite of dhcpctl_get_value.   Does not update the
258    server - just sets the value on the handle. */
259
260 dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, dhcpctl_data_string value,
261                                   const char *value_name)
262 {
263         isc_result_t status;
264         omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
265         omapi_data_string_t *name = (omapi_data_string_t *)0;
266         int len;
267
268         status = omapi_data_string_new (&name, strlen (value_name), MDL);
269         if (status != ISC_R_SUCCESS)
270                 return status;
271         memcpy (name -> value, value_name, strlen (value_name));
272
273         status = omapi_typed_data_new (MDL, &tv, omapi_datatype_data,
274                                        value -> len);
275         if (status != ISC_R_SUCCESS) {
276                 omapi_data_string_dereference (&name, MDL);
277                 return status;
278         }
279         memcpy (tv -> u.buffer.value, value -> value, value -> len);
280
281         status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
282         omapi_data_string_dereference (&name, MDL);
283         omapi_typed_data_dereference (&tv, MDL);
284         return status;
285 }
286
287 /* dhcpctl_set_string_value
288
289    Sets a NUL-terminated ASCII value on an object referred to by
290    a dhcpctl_handle.   like dhcpctl_set_value, but saves the
291    trouble of creating a data_string for a NUL-terminated string.
292    Does not update the server - just sets the value on the handle. */
293
294 dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, const char *value,
295                                          const char *value_name)
296 {
297         isc_result_t status;
298         omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
299         omapi_data_string_t *name = (omapi_data_string_t *)0;
300         int len;
301
302         status = omapi_data_string_new (&name, strlen (value_name), MDL);
303         if (status != ISC_R_SUCCESS)
304                 return status;
305         memcpy (name -> value, value_name, strlen (value_name));
306
307         status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value);
308         if (status != ISC_R_SUCCESS) {
309                 omapi_data_string_dereference (&name, MDL);
310                 return status;
311         }
312
313         status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
314         omapi_data_string_dereference (&name, MDL);
315         omapi_typed_data_dereference (&tv, MDL);
316         return status;
317 }
318
319 /* dhcpctl_set_buffer_value
320
321    Sets a value on an object referred to by a dhcpctl_handle.  like
322    dhcpctl_set_value, but saves the trouble of creating a data_string
323    for string for which we have a buffer and length.  Does not update
324    the server - just sets the value on the handle. */
325
326 dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle h,
327                                        const char *value, unsigned len,
328                                        const char *value_name)
329 {
330         isc_result_t status;
331         omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
332         omapi_data_string_t *name = (omapi_data_string_t *)0;
333         unsigned ll;
334
335         ll = strlen (value_name);
336         status = omapi_data_string_new (&name, ll, MDL);
337         if (status != ISC_R_SUCCESS)
338                 return status;
339         memcpy (name -> value, value_name, ll);
340
341         status = omapi_typed_data_new (MDL, &tv,
342                                        omapi_datatype_data, len, value);
343         if (status != ISC_R_SUCCESS) {
344                 omapi_data_string_dereference (&name, MDL);
345                 return status;
346         }
347         memcpy (tv -> u.buffer.value, value, len);
348
349         status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
350         omapi_data_string_dereference (&name, MDL);
351         omapi_typed_data_dereference (&tv, MDL);
352         return status;
353 }
354
355 /* dhcpctl_set_null_value
356
357    Sets a null value on an object referred to by a dhcpctl_handle. */
358
359 dhcpctl_status dhcpctl_set_null_value (dhcpctl_handle h,
360                                        const char *value_name)
361 {
362         isc_result_t status;
363         omapi_data_string_t *name = (omapi_data_string_t *)0;
364         unsigned ll;
365
366         ll = strlen (value_name);
367         status = omapi_data_string_new (&name, ll, MDL);
368         if (status != ISC_R_SUCCESS)
369                 return status;
370         memcpy (name -> value, value_name, ll);
371
372         status = omapi_set_value (h, (omapi_object_t *)0, name,
373                                   (omapi_typed_data_t *)0);
374         omapi_data_string_dereference (&name, MDL);
375         return status;
376 }
377
378 /* dhcpctl_set_boolean_value
379
380    Sets a boolean value on an object - like dhcpctl_set_value,
381    only more convenient for booleans. */
382
383 dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle h, int value,
384                                           const char *value_name)
385 {
386         isc_result_t status;
387         omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
388         omapi_data_string_t *name = (omapi_data_string_t *)0;
389         int len;
390
391         status = omapi_data_string_new (&name, strlen (value_name), MDL);
392         if (status != ISC_R_SUCCESS)
393                 return status;
394         memcpy (name -> value, value_name, strlen (value_name));
395
396         status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
397         if (status != ISC_R_SUCCESS) {
398                 omapi_data_string_dereference (&name, MDL);
399                 return status;
400         }
401
402         status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
403         omapi_data_string_dereference (&name, MDL);
404         omapi_typed_data_dereference (&tv, MDL);
405         return status;
406 }
407
408 /* dhcpctl_set_int_value
409
410    Sets a boolean value on an object - like dhcpctl_set_value,
411    only more convenient for booleans. */
412
413 dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle h, int value,
414                                       const char *value_name)
415 {
416         isc_result_t status;
417         omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
418         omapi_data_string_t *name = (omapi_data_string_t *)0;
419         int len;
420
421         status = omapi_data_string_new (&name, strlen (value_name), MDL);
422         if (status != ISC_R_SUCCESS)
423                 return status;
424         memcpy (name -> value, value_name, strlen (value_name));
425
426         status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
427         if (status != ISC_R_SUCCESS) {
428                 omapi_data_string_dereference (&name, MDL);
429                 return status;
430         }
431
432         status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
433         omapi_data_string_dereference (&name, MDL);
434         omapi_typed_data_dereference (&tv, MDL);
435         return status;
436 }
437
438 /* dhcpctl_object_update
439
440    Queues an update on the object referenced by the handle (there
441    can't be any other work in progress on the handle).   An
442    update means local parameters will be sent to the server. */
443
444 dhcpctl_status dhcpctl_object_update (dhcpctl_handle connection,
445                                       dhcpctl_handle h)
446 {
447         isc_result_t status;
448         omapi_object_t *message = (omapi_object_t *)0;
449         dhcpctl_remote_object_t *ro;
450
451         if (h -> type != dhcpctl_remote_type)
452                 return ISC_R_INVALIDARG;
453         ro = (dhcpctl_remote_object_t *)h;
454
455         status = omapi_message_new (&message, MDL);
456         if (status != ISC_R_SUCCESS) {
457                 omapi_object_dereference (&message, MDL);
458                 return status;
459         }
460         status = omapi_set_int_value (message, (omapi_object_t *)0,
461                                       "op", OMAPI_OP_UPDATE);
462         if (status != ISC_R_SUCCESS) {
463                 omapi_object_dereference (&message, MDL);
464                 return status;
465         }
466
467         status = omapi_set_object_value (message, (omapi_object_t *)0,
468                                          "object", h);
469         if (status != ISC_R_SUCCESS) {
470                 omapi_object_dereference (&message, MDL);
471                 return status;
472         }
473
474         status = omapi_set_int_value (message, (omapi_object_t *)0, "handle",
475                                       (int)(ro -> remote_handle));
476         if (status != ISC_R_SUCCESS) {
477                 omapi_object_dereference (&message, MDL);
478                 return status;
479         }
480
481         omapi_message_register (message);
482         status = omapi_protocol_send_message (connection -> outer,
483                                               (omapi_object_t *)0,
484                                               message, (omapi_object_t *)0);
485         omapi_object_dereference (&message, MDL);
486         return status;
487 }
488
489 /* Requests a refresh on the object referenced by the handle (there
490    can't be any other work in progress on the handle).   A
491    refresh means local parameters are updated from the server. */
492
493 dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle connection,
494                                        dhcpctl_handle h)
495 {
496         isc_result_t status;
497         omapi_object_t *message = (omapi_object_t *)0;
498         dhcpctl_remote_object_t *ro;
499
500         if (h -> type != dhcpctl_remote_type)
501                 return ISC_R_INVALIDARG;
502         ro = (dhcpctl_remote_object_t *)h;
503
504         status = omapi_message_new (&message, MDL);
505         if (status != ISC_R_SUCCESS) {
506                 omapi_object_dereference (&message, MDL);
507                 return status;
508         }
509         status = omapi_set_int_value (message, (omapi_object_t *)0,
510                                       "op", OMAPI_OP_REFRESH);
511         if (status != ISC_R_SUCCESS) {
512                 omapi_object_dereference (&message, MDL);
513                 return status;
514         }
515         status = omapi_set_int_value (message, (omapi_object_t *)0,
516                                       "handle", (int)(ro -> remote_handle));
517         if (status != ISC_R_SUCCESS) {
518                 omapi_object_dereference (&message, MDL);
519                 return status;
520         }
521
522         omapi_message_register (message);
523         status = omapi_protocol_send_message (connection -> outer,
524                                               (omapi_object_t *)0,
525                                               message, (omapi_object_t *)0);
526
527         /* We don't want to send the contents of the object down the
528            wire, but we do need to reference it so that we know what
529            to do with the update. */
530         status = omapi_set_object_value (message, (omapi_object_t *)0,
531                                          "object", h);
532         if (status != ISC_R_SUCCESS) {
533                 omapi_object_dereference (&message, MDL);
534                 return status;
535         }
536
537         omapi_object_dereference (&message, MDL);
538         return status;
539 }
540
541 /* Requests the removal of the object referenced by the handle (there
542    can't be any other work in progress on the handle).   A
543    removal means that all searchable references to the object on the
544    server are deleted. */
545
546 dhcpctl_status dhcpctl_object_remove (dhcpctl_handle connection,
547                                       dhcpctl_handle h)
548 {
549         isc_result_t status;
550         omapi_object_t *message = (omapi_object_t *)0;
551         dhcpctl_remote_object_t *ro;
552
553         if (h -> type != dhcpctl_remote_type)
554                 return ISC_R_INVALIDARG;
555         ro = (dhcpctl_remote_object_t *)h;
556
557         status = omapi_message_new (&message, MDL);
558         if (status != ISC_R_SUCCESS) {
559                 omapi_object_dereference (&message, MDL);
560                 return status;
561         }
562         status = omapi_set_int_value (message, (omapi_object_t *)0,
563                                       "op", OMAPI_OP_DELETE);
564         if (status != ISC_R_SUCCESS) {
565                 omapi_object_dereference (&message, MDL);
566                 return status;
567         }
568
569         status = omapi_set_int_value (message, (omapi_object_t *)0, "handle",
570                                       (int)(ro -> remote_handle));
571         if (status != ISC_R_SUCCESS) {
572                 omapi_object_dereference (&message, MDL);
573                 return status;
574         }
575
576         status = omapi_set_object_value (message, (omapi_object_t *)0,
577                                          "notify-object", h);
578         if (status != ISC_R_SUCCESS) {
579                 omapi_object_dereference (&message, MDL);
580                 return status;
581         }
582
583         omapi_message_register (message);
584         status = omapi_protocol_send_message (connection -> outer,
585                                               (omapi_object_t *)0,
586                                               message, (omapi_object_t *)0);
587         omapi_object_dereference (&message, MDL);
588         return status;
589 }
590
591 isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *vp,
592                                               const char *file, int line)
593 {
594         return omapi_data_string_dereference (vp, file, line);
595 }