Home | History | Annotate | Line # | Download | only in dhcpctl
      1  1.1  christos /*	$NetBSD: cltest2.c,v 1.2 2022/04/03 01:10:58 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* cltest2.c
      4  1.1  christos 
      5  1.1  christos    Example program that uses the dhcpctl library. */
      6  1.1  christos 
      7  1.1  christos /*
      8  1.1  christos  * Copyright (C) 2020-2022 Internet Systems Consortium, Inc. ("ISC")
      9  1.1  christos  *
     10  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
     11  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     12  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     13  1.1  christos  *
     14  1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     15  1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     16  1.1  christos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     17  1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     18  1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     19  1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     20  1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     21  1.1  christos  *
     22  1.1  christos  *   Internet Systems Consortium, Inc.
     23  1.1  christos  *   950 Charter Street
     24  1.1  christos  *   Redwood City, CA 94063
     25  1.1  christos  *   <info (at) isc.org>
     26  1.1  christos  *   https://www.isc.org/
     27  1.1  christos  *
     28  1.1  christos  * This software was contributed to Internet Systems Consortium
     29  1.1  christos  * by Brian Murrell.
     30  1.1  christos  */
     31  1.1  christos 
     32  1.1  christos #include <sys/cdefs.h>
     33  1.1  christos __RCSID("$NetBSD: cltest2.c,v 1.2 2022/04/03 01:10:58 christos Exp $");
     34  1.1  christos 
     35  1.1  christos #include "config.h"
     36  1.1  christos 
     37  1.1  christos #include <time.h>
     38  1.1  christos #include <sys/time.h>
     39  1.1  christos #include <stdio.h>
     40  1.1  christos #include <stdlib.h>
     41  1.1  christos #include <string.h>
     42  1.1  christos #include <stdarg.h>
     43  1.1  christos #include "omapip/result.h"
     44  1.1  christos #include "dhcpctl.h"
     45  1.1  christos #include "dhcpd.h"
     46  1.1  christos 
     47  1.1  christos int main (int, char **);
     48  1.1  christos 
     49  1.1  christos static void usage (char *s) {
     50  1.1  christos 	fprintf (stderr,
     51  1.1  christos 		 "Usage: %s [-s <server ip>] [-p <port>]", s);
     52  1.1  christos 	exit (1);
     53  1.1  christos }
     54  1.1  christos 
     55  1.1  christos static void fail_on_error(isc_result_t status, const char* message) {
     56  1.1  christos 	if (status != ISC_R_SUCCESS) {
     57  1.1  christos 		fprintf (stderr, "%s: %s\n",
     58  1.1  christos 			 message, isc_result_totext (status));
     59  1.1  christos 		exit (1);
     60  1.1  christos 	}
     61  1.1  christos }
     62  1.1  christos 
     63  1.1  christos isc_result_t wait_with_retry(dhcpctl_handle handle, struct timeval* timeout, int retries);
     64  1.1  christos 
     65  1.1  christos void print_object(char *msg, dhcpctl_handle handle);
     66  1.1  christos 
     67  1.1  christos /* Simple test program that exercises dhcpctl calls as follows:
     68  1.1  christos  *
     69  1.1  christos  * 1. Connect to the given server
     70  1.1  christos  * 2. Create a local host object with hostname "cltest2.host"
     71  1.1  christos  * 3. Attempt to open the remote host object
     72  1.1  christos  * 4. If the host does not exist, add a client id and create it
     73  1.1  christos  * 5. Disconnect
     74  1.1  christos  * 6. Reconnect
     75  1.1  christos  * 7. Refresh the host object
     76  1.1  christos  * 8. Disconnect
     77  1.1  christos  * 9. Time connect
     78  1.1  christos  * 10. Time connect retry
     79  1.1  christos  *
     80  1.1  christos  * Note that this program tests dhcpctl_timed_wait_for_completion() by calling
     81  1.1  christos  * it with extremely small timeouts.
     82  1.1  christos */
     83  1.1  christos 
     84  1.1  christos int main (argc, argv)
     85  1.1  christos 	int argc;
     86  1.1  christos 	char **argv;
     87  1.1  christos {
     88  1.1  christos 	isc_result_t status;
     89  1.1  christos 	dhcpctl_handle connection;
     90  1.1  christos 	dhcpctl_handle host;
     91  1.1  christos     char* ip_address = "127.0.0.1";
     92  1.1  christos     int port = 7911;
     93  1.1  christos     char* hostname = "cltest2.host";
     94  1.1  christos     struct timeval timeout;
     95  1.1  christos 	int i;
     96  1.1  christos 
     97  1.1  christos 	for (i = 1; i < argc; i++) {
     98  1.1  christos 		if (!strcmp (argv[i], "-s")) {
     99  1.1  christos             ip_address = argv[i];
    100  1.1  christos 		} else if (!strcmp (argv [i], "-p")) {
    101  1.1  christos             port=atoi(argv[i]);
    102  1.1  christos 		} else if (argv[i][0] == '-') {
    103  1.1  christos 			usage(argv[0]);
    104  1.1  christos 		}
    105  1.1  christos 	}
    106  1.1  christos 
    107  1.1  christos     /* Initialize dhcpctl */
    108  1.1  christos 	status = dhcpctl_initialize ();
    109  1.1  christos 	fail_on_error(status ,"can't initialize dhcpctl");
    110  1.1  christos 
    111  1.1  christos     /* Connect */
    112  1.1  christos 	connection = 0;
    113  1.1  christos 	status = dhcpctl_connect (&connection, ip_address, port, 0);
    114  1.1  christos 	fail_on_error(status ,"connect failed");
    115  1.1  christos 
    116  1.1  christos     /* Create the host object */
    117  1.1  christos 	host = 0;
    118  1.1  christos 	status = dhcpctl_new_object (&host, connection, "host");
    119  1.1  christos 	fail_on_error(status ,"new oject failed");
    120  1.1  christos 
    121  1.1  christos 	status = dhcpctl_set_string_value (host, hostname, "name");
    122  1.1  christos 	fail_on_error(status ,"cant set host name");
    123  1.1  christos 
    124  1.1  christos     /* Attempt to open the object */
    125  1.1  christos 	status = dhcpctl_open_object (host, connection, 0);
    126  1.1  christos     timeout.tv_sec = 0;
    127  1.1  christos     timeout.tv_usec = 20;
    128  1.1  christos     status = wait_with_retry(host, &timeout, 2);
    129  1.1  christos     switch (status) {
    130  1.1  christos         case ISC_R_NOTFOUND:
    131  1.1  christos             /* Host doesn't exist add it. We set an id so the create will be valid. */
    132  1.1  christos 	        status = dhcpctl_set_string_value (host, "abcdefg", "dhcp-client-identifier");
    133  1.1  christos 	        fail_on_error(status ,"can't set client id");
    134  1.1  christos 
    135  1.1  christos 		    status = dhcpctl_open_object (host, connection,
    136  1.1  christos 					                      DHCPCTL_CREATE | DHCPCTL_EXCL);
    137  1.1  christos 		    fail_on_error(status, "open(create) failed");
    138  1.1  christos 
    139  1.1  christos             status = wait_with_retry(host, &timeout, 2);
    140  1.1  christos 		    fail_on_error(status, "wait after open(create)");
    141  1.1  christos 
    142  1.1  christos             print_object("Host created", host);
    143  1.1  christos             break;
    144  1.1  christos 
    145  1.1  christos         case ISC_R_SUCCESS:
    146  1.1  christos             print_object("Host exists", host);
    147  1.1  christos             break;
    148  1.1  christos 
    149  1.1  christos         default:
    150  1.1  christos 	        fail_on_error(status, "initial open failed, waiting for completion");
    151  1.1  christos             break;
    152  1.1  christos     }
    153  1.1  christos 
    154  1.1  christos 	/* Now we'll test disconnect */
    155  1.1  christos 	status = dhcpctl_disconnect(&connection, 0);
    156  1.1  christos 	fail_on_error(status, "can't disconnect");
    157  1.1  christos 
    158  1.1  christos     /* Reconnect */
    159  1.1  christos 	status = dhcpctl_connect (&connection, ip_address, port, 0);
    160  1.1  christos 	fail_on_error(status ,"can't reconnect");
    161  1.1  christos 
    162  1.1  christos     /* Refresh the object */
    163  1.1  christos     status = dhcpctl_object_refresh (connection, host);
    164  1.1  christos     fail_on_error(status , "can't refresh");
    165  1.1  christos 
    166  1.1  christos     status = wait_with_retry(host, &timeout, 2);
    167  1.1  christos     fail_on_error(status , "wait after refresh failed");
    168  1.1  christos 
    169  1.1  christos     print_object("After reconnect/refresh", host);
    170  1.1  christos 
    171  1.1  christos 	/* Now we'll disconnect */
    172  1.1  christos 	status = dhcpctl_disconnect(&connection, 0);
    173  1.1  christos 	fail_on_error(status, "can't disconnect");
    174  1.1  christos 
    175  1.1  christos     /* Try a timed connect */
    176  1.1  christos     timeout.tv_sec = 0;
    177  1.1  christos     timeout.tv_usec = 1;
    178  1.1  christos 	status = dhcpctl_timed_connect (&connection, ip_address, port, 0, &timeout);
    179  1.1  christos 
    180  1.1  christos     /* Try again if we time out */
    181  1.1  christos     if (status == ISC_R_TIMEDOUT) {
    182  1.1  christos         printf ("Retry timed connect\n");
    183  1.1  christos         timeout.tv_sec = 10;
    184  1.1  christos 	    status = dhcpctl_timed_connect (&connection, ip_address, port, 0,
    185  1.1  christos                                         &timeout);
    186  1.1  christos     }
    187  1.1  christos 
    188  1.1  christos     fail_on_error(status ,"can't reconnect");
    189  1.1  christos 
    190  1.1  christos     /* Lastly we'll disconnect to clean up */
    191  1.1  christos 	status = dhcpctl_disconnect(&connection, 0);
    192  1.1  christos     fail_on_error(status ,"can't disconnect");
    193  1.1  christos 
    194  1.1  christos 	exit (0);
    195  1.1  christos }
    196  1.1  christos 
    197  1.1  christos /* Function to call and optionally retry dhcp_timed_wait_for_completion() */
    198  1.1  christos isc_result_t wait_with_retry(dhcpctl_handle handle, struct timeval* timeout,  int retries) {
    199  1.1  christos 	isc_result_t status;
    200  1.1  christos 	isc_result_t waitstatus;
    201  1.1  christos     struct timeval use_timeout;
    202  1.1  christos 
    203  1.1  christos     if (timeout) {
    204  1.1  christos         use_timeout.tv_sec = timeout->tv_sec;
    205  1.1  christos         use_timeout.tv_usec = timeout->tv_usec;
    206  1.1  christos     } else {
    207  1.1  christos         retries = 0;
    208  1.1  christos     }
    209  1.1  christos 
    210  1.1  christos     int tries = 0;
    211  1.1  christos     do {
    212  1.1  christos         if (tries++) {
    213  1.1  christos             printf ("wait retry #%d\n", tries);
    214  1.1  christos             /* Set the timeout value to 30 secs */
    215  1.1  christos             use_timeout.tv_sec = 30;
    216  1.1  christos             use_timeout.tv_usec = 0;
    217  1.1  christos         }
    218  1.1  christos 
    219  1.1  christos         // Call timed wait.
    220  1.1  christos 	    status = dhcpctl_timed_wait_for_completion (handle, &waitstatus,
    221  1.1  christos                                                     (timeout ? &use_timeout: 0));
    222  1.1  christos         if (status == ISC_R_SUCCESS) {
    223  1.1  christos             return(waitstatus);
    224  1.1  christos         }
    225  1.1  christos 
    226  1.1  christos         if (status != ISC_R_TIMEDOUT) {
    227  1.1  christos             fprintf (stderr, "timed wait failed: %s\n", isc_result_totext (status));
    228  1.1  christos             exit (1);
    229  1.1  christos         }
    230  1.1  christos    } while (--retries > 0);
    231  1.1  christos 
    232  1.1  christos     return (ISC_R_TIMEDOUT);
    233  1.1  christos }
    234  1.1  christos 
    235  1.1  christos /* Function to print out the values contained in an object. Largely
    236  1.1  christos  * stolen from omshell.c */
    237  1.1  christos void print_object(char* msg, dhcpctl_handle handle) {
    238  1.1  christos     dhcpctl_remote_object_t *r = (dhcpctl_remote_object_t *)handle;
    239  1.1  christos     omapi_generic_object_t *object = (omapi_generic_object_t *)(r->inner);
    240  1.1  christos     char hex_buf[4096];
    241  1.1  christos     int i;
    242  1.1  christos 
    243  1.1  christos     printf ("%s:\n",msg);
    244  1.1  christos     for (i = 0; i < object->nvalues; i++) {
    245  1.1  christos         omapi_value_t *v = object->values[i];
    246  1.1  christos 
    247  1.1  christos         if (!object->values[i])
    248  1.1  christos             continue;
    249  1.1  christos 
    250  1.1  christos         printf ("\t%.*s = ", (int)v->name->len, v->name->value);
    251  1.1  christos 
    252  1.1  christos         if (!v->value) {
    253  1.1  christos             printf ("<null>\n");
    254  1.1  christos             continue;
    255  1.1  christos         }
    256  1.1  christos 
    257  1.1  christos         switch (v->value->type) {
    258  1.1  christos         case omapi_datatype_int:
    259  1.1  christos             printf ("%d\n", v->value->u.integer);
    260  1.1  christos             break;
    261  1.1  christos 
    262  1.1  christos         case omapi_datatype_string:
    263  1.1  christos             printf ("\"%.*s\"\n", (int)v->value->u.buffer.len,
    264  1.1  christos                     v->value->u.buffer.value);
    265  1.1  christos             break;
    266  1.1  christos 
    267  1.1  christos         case omapi_datatype_data:
    268  1.1  christos             print_hex_or_string(v->value->u.buffer.len,
    269  1.1  christos 						        v->value->u.buffer.value,
    270  1.1  christos                                 sizeof(hex_buf), hex_buf);
    271  1.1  christos             printf("%s\n", hex_buf);
    272  1.1  christos             break;
    273  1.1  christos 
    274  1.1  christos         case omapi_datatype_object:
    275  1.1  christos             printf ("<obj>\n");
    276  1.1  christos             break;
    277  1.1  christos         }
    278  1.1  christos     }
    279  1.1  christos }
    280  1.1  christos 
    281  1.1  christos /* Dummy functions to appease linker */
    282  1.1  christos isc_result_t find_class (struct class **c, const char *n, const char *f, int l)
    283  1.1  christos {
    284  1.1  christos 	return 0;
    285  1.1  christos }
    286  1.1  christos int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag)
    287  1.1  christos {
    288  1.1  christos 	return 0;
    289  1.1  christos }
    290  1.1  christos void dhcp (struct packet *packet) { }
    291  1.1  christos void bootp (struct packet *packet) { }
    292  1.1  christos 
    293  1.1  christos #ifdef DHCPv6
    294  1.1  christos void dhcpv6(struct packet *packet) { }
    295  1.1  christos 
    296  1.1  christos #ifdef DHCP4o6
    297  1.1  christos isc_result_t dhcpv4o6_handler(omapi_object_t *h)
    298  1.1  christos {
    299  1.1  christos 	return ISC_R_NOTIMPLEMENTED;
    300  1.1  christos }
    301  1.1  christos #endif /* DHCP4o6 */
    302  1.1  christos #endif /* DHCPv6 */
    303  1.1  christos 
    304  1.1  christos int check_collection (struct packet *p, struct lease *l, struct collection *c)
    305  1.1  christos {
    306  1.1  christos 	return 0;
    307  1.1  christos }
    308  1.1  christos void classify (struct packet *packet, struct class *class) { }
    309  1.1  christos 
    310  1.1  christos isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
    311  1.1  christos 				     control_object_state_t newstate)
    312  1.1  christos {
    313  1.1  christos 	return ISC_R_SUCCESS;
    314  1.1  christos }
    315  1.1  christos 
    316