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