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