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