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