xref: /netbsd-src/external/mpl/dhcp/dist/dhcpctl/cltest2.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
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 
usage(char * s)49 static void usage (char *s) {
50 	fprintf (stderr,
51 		 "Usage: %s [-s <server ip>] [-p <port>]", s);
52 	exit (1);
53 }
54 
fail_on_error(isc_result_t status,const char * message)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 
main(argc,argv)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() */
wait_with_retry(dhcpctl_handle handle,struct timeval * timeout,int retries)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 */
print_object(char * msg,dhcpctl_handle handle)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 */
find_class(struct class ** c,const char * n,const char * f,int l)282 isc_result_t find_class (struct class **c, const char *n, const char *f, int l)
283 {
284 	return 0;
285 }
parse_allow_deny(struct option_cache ** oc,struct parse * cfile,int flag)286 int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag)
287 {
288 	return 0;
289 }
dhcp(struct packet * packet)290 void dhcp (struct packet *packet) { }
bootp(struct packet * packet)291 void bootp (struct packet *packet) { }
292 
293 #ifdef DHCPv6
dhcpv6(struct packet * packet)294 void dhcpv6(struct packet *packet) { }
295 
296 #ifdef DHCP4o6
dhcpv4o6_handler(omapi_object_t * h)297 isc_result_t dhcpv4o6_handler(omapi_object_t *h)
298 {
299 	return ISC_R_NOTIMPLEMENTED;
300 }
301 #endif /* DHCP4o6 */
302 #endif /* DHCPv6 */
303 
check_collection(struct packet * p,struct lease * l,struct collection * c)304 int check_collection (struct packet *p, struct lease *l, struct collection *c)
305 {
306 	return 0;
307 }
classify(struct packet * packet,struct class * class)308 void classify (struct packet *packet, struct class *class) { }
309 
dhcp_set_control_state(control_object_state_t oldstate,control_object_state_t newstate)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