The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 2604532ca9bcdeee528dc11559ec6eac7095f16e $
19  * @file kafka/base.c
20  * @brief Kafka global structures
21  *
22  * @copyright 2022 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23  */
24 
25 #include <freeradius-devel/kafka/base.h>
26 #include <freeradius-devel/server/cf_parse.h>
27 #include <freeradius-devel/server/tmpl.h>
28 #include <freeradius-devel/util/value.h>
29 #include <freeradius-devel/util/sbuff.h>
30 #include <freeradius-devel/util/size.h>
31 
32 typedef struct {
33  rd_kafka_conf_t *conf;
35 
36 typedef struct {
37  rd_kafka_topic_conf_t *conf;
39 
40 typedef struct {
41  fr_table_ptr_sorted_t *mapping; //!< Mapping table between string constant.
42 
43  size_t *mapping_len; //!< Length of the mapping tables
44 
45  bool empty_default; //!< Don't produce messages saying the default is missing.
46 
47  size_t size_scale; //!< Divide/multiply FR_TYPE_SIZE by this amount.
48 
49  char const *property; //!< Kafka configuration property.
50 
51  char const *string_sep; //!< Used for multi-value configuration items.
52  //!< Kafka uses ', ' or ';' seemingly at random.
54 
55 /** Destroy a kafka configuration handle
56  *
57  * @param[in] kc To destroy.
58  * @return 0
59  */
61 {
62  rd_kafka_conf_destroy(kc->conf);
63  return 0;
64 }
65 
66 static inline CC_HINT(always_inline)
68 {
69  CONF_DATA const *cd;
70  fr_kafka_conf_t *kc;
71 
72  cd = cf_data_find(cs, fr_kafka_conf_t, "conf");
73  if (cd) {
74  kc = cf_data_value(cd);
75  } else {
76  MEM(kc = talloc(NULL, fr_kafka_conf_t));
77  MEM(kc->conf = rd_kafka_conf_new());
78  talloc_set_destructor(kc, _kafka_conf_free);
79  cf_data_add(cs, kc, "conf", true);
80  }
81 
82  return kc;
83 }
84 
85 /** Destroy a kafka topic configuration handle
86  *
87  * @param[in] ktc To destroy.
88  * @return 0
89  */
91 {
92  rd_kafka_topic_conf_destroy(ktc->conf);
93  return 0;
94 }
95 
96 static inline CC_HINT(always_inline)
98 {
99  CONF_DATA const *cd;
101 
102  cd = cf_data_find(cs, fr_kafka_topic_conf_t, "conf");
103  if (cd) {
104  ktc = cf_data_value(cd);
105  } else {
106  MEM(ktc = talloc(NULL, fr_kafka_topic_conf_t));
107  MEM(ktc->conf = rd_kafka_topic_conf_new());
108  talloc_set_destructor(ktc, _kafka_topic_conf_free);
109  cf_data_add(cs, ktc, "conf", true);
110  }
111 
112  return ktc;
113 }
114 
115 /** Perform any conversions necessary to map kafka defaults to our values
116  *
117  * @param[out] out Where to write the pair.
118  * @param[in] parent being populated.
119  * @param[in] cs to allocate the pair in.
120  * @param[in] value to convert.
121  * @param[in] quote to use when allocing the pair.
122  * @param[in] rule UNUSED.
123  * @return
124  * - 0 on success.
125  * - -1 on failure.
126  */
127 static int kafka_config_dflt_single(CONF_PAIR **out, UNUSED void *parent, CONF_SECTION *cs, char const *value,
128  fr_token_t quote, conf_parser_t const *rule)
129 {
130  char tmp[sizeof("18446744073709551615b")];
131  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
132  fr_type_t type = rule->type;
133 
134  /*
135  * Apply any mappings available, but default back
136  * to the raw value if we don't have a match.
137  */
138  if (kctx->mapping) {
139  fr_table_ptr_sorted_t *mapping = kctx->mapping;
140  size_t mapping_len = *kctx->mapping_len;
141 
143  }
144  /*
145  * Convert time delta as an integer with ms precision
146  */
147  switch (type) {
148  case FR_TYPE_TIME_DELTA:
149  {
150  fr_sbuff_t value_elem = FR_SBUFF_IN(tmp, sizeof(tmp));
151  fr_time_delta_t delta;
152 
153  if (fr_time_delta_from_str(&delta, value, strlen(value), FR_TIME_RES_MSEC) < 0) {
154  cf_log_perr(cs, "Failed parsing default \"%s\"", value);
155  return -1;
156  }
157 
158  fr_time_delta_to_str(&value_elem, delta, FR_TIME_RES_SEC, true);
159  value = fr_sbuff_start(&value_elem);
160  }
161  break;
162 
163  case FR_TYPE_SIZE:
164  {
165  fr_sbuff_t value_elem = FR_SBUFF_IN(tmp, sizeof(tmp));
166  size_t size;
167 
168  if (fr_size_from_str(&size, &FR_SBUFF_IN(value, strlen(value))) < 0) {
169  cf_log_perr(cs, "Failed parsing default \"%s\"", value);
170  return -1;
171  }
172 
173  /*
174  * Some options are in kbytes *sigh*
175  */
176  if (kctx->size_scale) size *= kctx->size_scale;
177 
178  fr_size_to_str(&value_elem, size); /* reprint the size with an appropriate unit */
179  value = fr_sbuff_start(&value_elem);
180  }
181  break;
182 
183  default:
184  break;
185  }
186 
187  MEM(*out = cf_pair_alloc(cs, rule->name1, value, T_OP_EQ, T_BARE_WORD, quote));
188  cf_pair_mark_parsed(*out); /* Don't re-parse this */
189 
190  return 0;
191 }
192 
193 /** Return the default value from the kafka client library
194  *
195  * @param[out] out Where to write the pair.
196  * @param[in] parent being populated.
197  * @param[in] cs to allocate the pair in.
198  * @param[in] quote to use when allocing the pair.
199  * @param[in] rule UNUSED.
200  * @return
201  * - 0 on success.
202  * - -1 on failure.
203  */
204 static int kafka_config_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
205 {
206  char buff[1024];
207  size_t buff_len = sizeof(buff);
208  char const *value;
209 
210  fr_kafka_conf_t *kc;
211  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
212  rd_kafka_conf_res_t ret;
213 
214  kc = kafka_conf_from_cs(cs);
215  fr_assert(kc);
216 
217  if ((ret = rd_kafka_conf_get(kc->conf, kctx->property, buff, &buff_len)) != RD_KAFKA_CONF_OK) {
218  if (ret == RD_KAFKA_CONF_UNKNOWN) {
219  if (kctx->empty_default) return 0;
220 
221  cf_log_debug(cs, "No default available for \"%s\" - \"%s\"", rule->name1, kctx->property);
222  return 0; /* Not an error */
223  }
224 
225  cf_log_err(cs, "Failed retrieving kafka property \"%s\"", kctx->property);
226  return -1;
227  }
228 #if 0
229  cf_log_debug(cs, "Retrieved dflt \"%s\" for \"%s\" - \"%s\"", buff, rule->name1, kctx->property);
230 #endif
231  value = buff;
232 
233  /*
234  * If it's multi we need to break the string apart on the string separator
235  * and potentially unescape the separator.
236  */
237  if (fr_rule_multi(rule)) {
238  fr_sbuff_t value_in = FR_SBUFF_IN(value, buff_len);
239  char tmp[256];
240  fr_sbuff_t value_elem = FR_SBUFF_OUT(tmp, sizeof(tmp));
242  fr_sbuff_unescape_rules_t ue_rules = {
243  .name = __FUNCTION__,
244  .chr = '\\'
245  };
246  /*
247  * Convert escaped separators back
248  */
249  ue_rules.subs[(uint8_t)kctx->string_sep[0]] = kctx->string_sep[0];
250 
251  while (fr_sbuff_out_unescape_until(&value_elem, &value_in, SIZE_MAX, &tt, &ue_rules) > 0) {
252  if (kafka_config_dflt_single(out, parent, cs, fr_sbuff_start(&value_elem), quote, rule) < 0) return -1;
253 
254  /*
255  * Skip past the string separator
256  */
257  fr_sbuff_advance(&value_in, strlen(kctx->string_sep));
258 
259  /*
260  * Reset
261  */
262  fr_sbuff_set_to_start(&value_elem);
263  }
264  return 0;
265  }
266 
267  /*
268  * Parse a single value
269  */
270  if (kafka_config_dflt_single(out, parent, cs, value, quote, rule) < 0) return -1;
271 
272  return 0;
273 }
274 
275 /** Return the default value for a topic from the kafka client library
276  *
277  * @param[out] out Where to write the pair.
278  * @param[in] parent being populated.
279  * @param[in] cs to allocate the pair in.
280  * @param[in] quote to use when allocing the pair.
281  * @param[in] rule UNUSED.
282  * @return
283  * - 0 on success.
284  * - -1 on failure.
285  */
286 static int kafka_topic_config_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
287 {
288  char buff[1024];
289  size_t buff_len = sizeof(buff);
290  char const *value;
291 
293  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
294  rd_kafka_conf_res_t ret;
295 
296  ktc = kafka_topic_conf_from_cs(cs);
297  fr_assert(ktc);
298 
299  if ((ret = rd_kafka_topic_conf_get(ktc->conf, kctx->property, buff, &buff_len)) != RD_KAFKA_CONF_OK) {
300  if (ret == RD_KAFKA_CONF_UNKNOWN) {
301  if (kctx->empty_default) return 0;
302 
303  cf_log_debug(cs, "No default available for \"%s\" - \"%s\"", rule->name1, kctx->property);
304  return 0; /* Not an error */
305  }
306 
307  fr_assert(ret == RD_KAFKA_CONF_UNKNOWN);
308  cf_log_err(cs, "Failed retrieving kafka property '%s'", kctx->property);
309  return -1;
310  }
311 #if 0
312  cf_log_debug(cs, "Retrieved dflt \"%s\" for \"%s\" - \"%s\"", buff, rule->name1, kctx->property);
313 #endif
314  value = buff;
315 
316  /*
317  * Parse a single value
318  */
319  if (kafka_config_dflt_single(out, parent, cs, value, quote, rule) < 0) return -1;
320 
321  return 0;
322 }
323 
324 static int kafka_config_parse_single(char const **out, CONF_PAIR *cp, conf_parser_t const *rule)
325 {
327  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
328  fr_type_t type = rule->type;
329  static _Thread_local char buff[sizeof("18446744073709551615")];
330  static _Thread_local fr_sbuff_t sbuff;
331 
332  /*
333  * Map string values if possible, and if there's
334  * no match then just pass the original through.
335  *
336  * We count this as validation...
337  */
338  if (kctx->mapping) {
339  fr_table_ptr_sorted_t *mapping = kctx->mapping;
340  size_t mapping_len = *kctx->mapping_len;
341 
343  return 0;
344  } else if (fr_type_is_string(type)) {
345  *out = cf_pair_value(cp);
346  return 0;
347  }
348 
349  /*
350  * Parse as a box for basic validation
351  */
352  if (cf_pair_to_value_box(NULL, &vb, cp, rule) < 0) return -1;
353 
354  /*
355  * In kafka all the time deltas are in ms
356  * resolution, so we need to take the parsed value,
357  * scale it, and print it back to a string.
358  */
359  switch (type) {
360  case FR_TYPE_TIME_DELTA:
361  {
362  uint64_t delta;
363 
364  sbuff = FR_SBUFF_IN(buff, sizeof(buff));
365  delta = fr_time_delta_to_msec(vb.vb_time_delta);
366  if (fr_sbuff_in_sprintf(&sbuff, "%" PRIu64, delta) < 0) {
367  error:
368  fr_value_box_clear(&vb);
369  return -1;
370  }
371  *out = fr_sbuff_start(&sbuff);
372  }
373  break;
374 
375  case FR_TYPE_SIZE:
376  {
377  size_t size = vb.vb_size;
378 
379  sbuff = FR_SBUFF_IN(buff, sizeof(buff));
380 
381  /*
382  * Most options are in bytes, but some are in kilobytes
383  */
384  if (kctx->size_scale) size /= kctx->size_scale;
385 
386  /*
387  * Kafka doesn't want units...
388  */
389  if (fr_sbuff_in_sprintf(&sbuff, "%zu", size) < 0) goto error;
390  *out = fr_sbuff_start(&sbuff);
391  }
392  break;
393 
394  /*
395  * Ensure bool is always mapped to the string constants
396  * "true" or "false".
397  */
398  case FR_TYPE_BOOL:
399  *out = vb.vb_bool ? "true" : "false";
400  break;
401 
402  default:
403  *out = cf_pair_value(cp);
404  break;
405  }
406 
407  fr_value_box_clear(&vb);
408 
409  return 0;
410 }
411 
412 /** Translate config items directly to settings in a kafka config struct
413  *
414  * @param[in] ctx to allocate fr_kafka_conf_t in.
415  * @param[out] out Unused.
416  * @param[in] base Unused.
417  * @param[in] ci To parse.
418  * @param[in] rule describing how to parse the item.
419  * @return
420  * - 0 on success.
421  * - -1 on failure
422  */
423 static int kafka_config_parse(TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *base,
424  CONF_ITEM *ci, conf_parser_t const *rule)
425 {
426  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
427  CONF_ITEM *parent = cf_parent(ci);
429  CONF_PAIR *cp = cf_item_to_pair(ci);
430 
431  fr_kafka_conf_t *kc;
432  char const *value;
433 
435 
436  /*
437  * Multi rules require us to concat the values together before handing them off
438  */
439  if (fr_rule_multi(rule)) {
440  unsigned int i;
441  CONF_PAIR *cp_p;
442  size_t count;
443  char const **array;
444  fr_sbuff_t *agg;
445  fr_slen_t slen;
446 
447  FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, SIZE_MAX);
448 
449  count = cf_pair_count(cs, rule->name1);
450  if (count <= 1) goto do_single;
451 
452  MEM(array = talloc_array(ctx, char const *, count));
453  for (cp_p = cp, i = 0;
454  cp_p;
455  cp_p = cf_pair_find_next(cs, cp_p, rule->name1), i++) {
456  if (kafka_config_parse_single(&array[i], cp_p, rule) < 0) return -1;
457  cf_pair_mark_parsed(cp_p);
458  }
459 
460  slen = talloc_array_concat(agg, array, kctx->string_sep);
462  if (slen < 0) return -1;
463 
464  value = fr_sbuff_start(agg);
465  } else {
466  do_single:
467  if (kafka_config_parse_single(&value, cp, rule) < 0) return -1;
468  }
469 
470  {
471  char errstr[512];
472 
473  if (rd_kafka_conf_set(kc->conf, kctx->property,
474  value, errstr, sizeof(errstr)) != RD_KAFKA_CONF_OK) {
475  cf_log_perr(cp, "%s", errstr);
476  return -1;
477  }
478  }
479 
480  return 0;
481 }
482 
483 
484 /** Translate config items directly to settings in a kafka topic config struct
485  *
486  * @param[in] ctx to allocate fr_kafka_conf_t in.
487  * @param[out] out Unused.
488  * @param[in] base Unused.
489  * @param[in] ci To parse.
490  * @param[in] rule describing how to parse the item.
491  * @return
492  * - 0 on success.
493  * - -1 on failure
494  */
495 static int kafka_topic_config_parse(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *base,
496  CONF_ITEM *ci, conf_parser_t const *rule)
497 {
498  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
499  CONF_ITEM *parent = cf_parent(ci);
500  CONF_PAIR *cp = cf_item_to_pair(ci);
501 
503  char const *value;
504 
506  if (kafka_config_parse_single(&value, cp, rule) < 0) return -1;
507 
508  {
509  char errstr[512];
510 
511  if (rd_kafka_topic_conf_set(ktc->conf, kctx->property,
512  value, errstr, sizeof(errstr)) != RD_KAFKA_CONF_OK) {
513  cf_log_perr(cp, "%s", errstr);
514  return -1;
515  }
516  }
517 
518  return 0;
519 }
520 
521 #if 0
522 /** Configure a new topic for production or consumption
523  *
524  */
525 static int kafka_topic_new(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *base,
526  CONF_ITEM *ci, conf_parser_t const *rule)
527 {
528  fr_kafka_conf_ctx_t const *kctx = rule->uctx;
529  CONF_ITEM *parent = cf_parent(ci);
530  CONF_PAIR *cp = cf_item_to_pair(ci);
531 
533  char const *value;
534 
536 
537  rd_kafka_topic_new (rd_kafka_t *rk, const char *topic, rd_kafka_topic_conf_t *conf)
538 }
539 #endif
540 
543  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.oauthbearer.config", .empty_default = true }},
544 
546  .uctx = &(fr_kafka_conf_ctx_t){ .property = "enable.sasl.oauthbearer.unsecure.jwt" }},
547 
549 };
550 
552  /*
553  * Service principal
554  */
556  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.kerberos.service.name" }},
557 
558  /*
559  * Principal
560  */
562  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.kerberos.principal" }},
563 
564  /*
565  * knit cmd
566  */
568  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.kerberos.kinit.cmd" }},
569 
570  /*
571  * keytab
572  */
574  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.kerberos.kinit.keytab", .empty_default = true }},
575 
576  /*
577  * How long between key refreshes
578  */
580  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.kerberos.min.time.before.relogin" }},
581 
583 };
584 
586  /*
587  * SASL mechanism
588  */
590  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.mechanism" }},
591 
592  /*
593  * Static SASL username
594  */
596  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.username", .empty_default = true }},
597 
598  /*
599  * Static SASL password
600  */
602  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sasl.password", .empty_default = true }},
603 
605 
607 
609 };
610 
612  { L("false"), "none" },
613  { L("no"), "none" },
614  { L("true"), "https" },
615  { L("yes"), "https" }
616 };
618 
619 static conf_parser_t const kafka_tls_config[] = {
620  /*
621  * Cipher suite list in OpenSSL's format
622  */
624  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.cipher.suites", .empty_default = true }},
625 
626  /*
627  * Curves list in OpenSSL's format
628  */
630  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.curves.list", .empty_default = true }},
631 
632  /*
633  * Curves list in OpenSSL's format
634  */
636  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.sigalgs.list", .empty_default = true }},
637 
638  /*
639  * Sets the full path to a CA certificate (used to validate
640  * the certificate the server presents).
641  */
643  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.ca.location", .empty_default = true }},
644 
645  /*
646  * Location of the CRL file.
647  */
649  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.crl.location", .empty_default = true }},
650 
651  /*
652  * Sets the path to the public certificate file we present
653  * to the servers.
654  */
656  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.certificate.location", .empty_default = true }},
657 
658  /*
659  * Sets the path to the private key for our public
660  * certificate.
661  */
663  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.key.location", .empty_default = true }},
664 
665  /*
666  * Enable or disable certificate validation
667  */
669  .uctx = &(fr_kafka_conf_ctx_t){ .property = "enable.ssl.certificate.verification" }},
670 
672  .uctx = &(fr_kafka_conf_ctx_t){ .property = "ssl.endpoint.identification.algorithm",
673  .mapping = kafka_check_cert_cn_table,
674  .mapping_len = &kafka_check_cert_cn_table_len }},
676 };
677 
679  /*
680  * Socket timeout
681  */
683  .uctx = &(fr_kafka_conf_ctx_t){ .property = "socket.timeout.ms" }},
684 
685  /*
686  * Close broker connections after this period.
687  */
689  .uctx = &(fr_kafka_conf_ctx_t){ .property = "connections.max.idle.ms" }},
690 
691  /*
692  * Maximum requests in flight (per connection).
693  */
694  { FR_CONF_FUNC("max_requests_in_flight", FR_TYPE_UINT64, 0, kafka_config_parse, kafka_config_dflt),
695  .uctx = &(fr_kafka_conf_ctx_t){ .property = "max.in.flight.requests.per.connection" }},
696 
697  /*
698  * Socket send buffer.
699  */
701  .uctx = &(fr_kafka_conf_ctx_t){ .property = "socket.send.buffer.bytes" }},
702 
703  /*
704  * Socket recv buffer.
705  */
707  .uctx = &(fr_kafka_conf_ctx_t){ .property = "socket.receive.buffer.bytes" }},
708 
709  /*
710  * If true, send TCP keepalives
711  */
713  .uctx = &(fr_kafka_conf_ctx_t){ .property = "socket.keepalive.enable" }},
714 
715  /*
716  * If true, disable nagle algorithm
717  */
719  .uctx = &(fr_kafka_conf_ctx_t){ .property = "socket.nagle.disable" }},
720 
721  /*
722  * How long the DNS resolver cache is valid for
723  */
725  .uctx = &(fr_kafka_conf_ctx_t){ .property = "broker.address.ttl" }},
726 
727  /*
728  * Should we use A records, AAAA records or either
729  * when resolving broker addresses
730  */
731  { FR_CONF_FUNC("resolver_addr_family", FR_TYPE_STRING, 0, kafka_config_parse, kafka_config_dflt),
732  .uctx = &(fr_kafka_conf_ctx_t){ .property = "broker.address.family" }},
733 
734  /*
735  * How many failures before we reconnect the connection
736  */
737  { FR_CONF_FUNC("reconnection_failure_count", FR_TYPE_UINT32, 0, kafka_config_parse, kafka_config_dflt),
738  .uctx = &(fr_kafka_conf_ctx_t){ .property = "socket.max.fails" }},
739 
740  /*
741  * Initial time to wait before reconnecting.
742  */
743  { FR_CONF_FUNC("reconnection_delay_initial", FR_TYPE_TIME_DELTA, 0, kafka_config_parse, kafka_config_dflt),
744  .uctx = &(fr_kafka_conf_ctx_t){ .property = "reconnect.backoff.ms" }},
745 
746  /*
747  * Max time to wait before reconnecting.
748  */
749  { FR_CONF_FUNC("reconnection_delay_max", FR_TYPE_TIME_DELTA, 0, kafka_config_parse, kafka_config_dflt),
750  .uctx = &(fr_kafka_conf_ctx_t){ .property = "reconnect.backoff.max.ms" }},
751 
753 };
754 
756  /*
757  * Request the API version from connected brokers
758  */
760  .uctx = &(fr_kafka_conf_ctx_t){ .property = "api.version.request" }},
761 
762  /*
763  * How long to wait for a version response.
764  */
766  .uctx = &(fr_kafka_conf_ctx_t){ .property = "api.version.request.timeout.ms" }},
767 
768  /*
769  * How long to wait before retrying a version request.
770  */
772  .uctx = &(fr_kafka_conf_ctx_t){ .property = "api.version.fallback.ms" }},
773 
774  /*
775  * Default version to use if the version request fails.
776  */
778  .uctx = &(fr_kafka_conf_ctx_t){ .property = "broker.version.fallback" }},
779 
781 };
782 
784  /*
785  * Interval between attempts to refresh metadata from brokers
786  */
788  .uctx = &(fr_kafka_conf_ctx_t){ .property = "topic.metadata.refresh.interval.ms" }},
789 
790  /*
791  * Interval between attempts to refresh metadata from brokers
792  */
794  .uctx = &(fr_kafka_conf_ctx_t){ .property = "metadata.max.age.ms" }},
795 
796  /*
797  * Used when a topic loses its leader
798  */
799  { FR_CONF_FUNC("fast_refresh_interval", FR_TYPE_TIME_DELTA, 0, kafka_config_parse, kafka_config_dflt),
800  .uctx = &(fr_kafka_conf_ctx_t){ .property = "topic.metadata.refresh.fast.interval.ms" }},
801 
802  /*
803  * Used when a topic loses its leader to prevent spurious metadata changes
804  */
806  .uctx = &(fr_kafka_conf_ctx_t){ .property = "topic.metadata.propagation.max.ms" }},
807 
808  /*
809  * Use sparse metadata requests which use less bandwidth maps
810  */
812  .uctx = &(fr_kafka_conf_ctx_t){ .property = "topic.metadata.refresh.sparse" }},
813 
814  /*
815  * List of topics to ignore
816  */
818  .uctx = &(fr_kafka_conf_ctx_t){ .property = "topic.blacklist", .string_sep = ",", .empty_default = true }},
819 
821 };
822 
823 #define BASE_CONFIG \
824  { FR_CONF_FUNC("server", FR_TYPE_STRING, CONF_FLAG_REQUIRED | CONF_FLAG_MULTI, kafka_config_parse, kafka_config_dflt), \
825  .uctx = &(fr_kafka_conf_ctx_t){ .property = "metadata.broker.list", .string_sep = "," }}, \
826  { FR_CONF_FUNC("client_id", FR_TYPE_STRING, 0, kafka_config_parse, kafka_config_dflt), \
827  .uctx = &(fr_kafka_conf_ctx_t){ .property = "client.id" }}, \
828  { FR_CONF_FUNC("rack_id", FR_TYPE_STRING, 0, kafka_config_parse, kafka_config_dflt), \
829  .uctx = &(fr_kafka_conf_ctx_t){ .property = "client.rack" }}, \
830  { FR_CONF_FUNC("request_max_size", FR_TYPE_SIZE, 0, kafka_config_parse, kafka_config_dflt), \
831  .uctx = &(fr_kafka_conf_ctx_t){ .property = "message.max.bytes" }}, \
832  { FR_CONF_FUNC("request_copy_max_size", FR_TYPE_SIZE, 0, kafka_config_parse, kafka_config_dflt), \
833  .uctx = &(fr_kafka_conf_ctx_t){ .property = "message.copy.max.bytes" }}, \
834  { FR_CONF_FUNC("response_max_size", FR_TYPE_SIZE, 0, kafka_config_parse, kafka_config_dflt), \
835  .uctx = &(fr_kafka_conf_ctx_t){ .property = "receive.message.max.bytes" }}, \
836  { FR_CONF_FUNC("feature", FR_TYPE_STRING, CONF_FLAG_MULTI, kafka_config_parse, kafka_config_dflt), \
837  .uctx = &(fr_kafka_conf_ctx_t){ .property = "builtin.features", .string_sep = "," }}, \
838  { FR_CONF_FUNC("debug", FR_TYPE_STRING, CONF_FLAG_MULTI, kafka_config_parse, kafka_config_dflt), \
839  .uctx = &(fr_kafka_conf_ctx_t){ .property = "debug", .string_sep = "," }}, \
840  { FR_CONF_FUNC("plugin", FR_TYPE_STRING, CONF_FLAG_MULTI, kafka_config_parse, NULL), \
841  .uctx = &(fr_kafka_conf_ctx_t){ .property = "plugin.library.paths", .string_sep = ";" }}, \
842  { FR_CONF_SUBSECTION_GLOBAL("metadata", 0, kafka_metadata_config) }, \
843  { FR_CONF_SUBSECTION_GLOBAL("version", 0, kafka_version_config) }, \
844  { FR_CONF_SUBSECTION_GLOBAL("connection", 0, kafka_connection_config) }, \
845  { FR_CONF_SUBSECTION_GLOBAL("tls", 0, kafka_tls_config) }, \
846  { FR_CONF_SUBSECTION_GLOBAL("sasl", 0, kafka_sasl_config) }
847 
849  /*
850  * Group consumer is a member of
851  */
853  .uctx = &(fr_kafka_conf_ctx_t){ .property = "group.id" }},
854 
855  /*
856  * A unique identifier of the consumer instance provided by the end user
857  */
859  .uctx = &(fr_kafka_conf_ctx_t){ .property = "group.instance.id" }},
860 
861  /*
862  * Range or roundrobin
863  */
864  { FR_CONF_FUNC("partition_assignment_strategy", FR_TYPE_STRING, 0, kafka_config_parse, kafka_config_dflt),
865  .uctx = &(fr_kafka_conf_ctx_t){ .property = "partition.assignment.strategy" }},
866 
867  /*
868  * Client group session and failure detection timeout.
869  */
871  .uctx = &(fr_kafka_conf_ctx_t){ .property = "session.timeout.ms" }},
872 
873  /*
874  * Group session keepalive heartbeat interval.
875  */
877  .uctx = &(fr_kafka_conf_ctx_t){ .property = "heartbeat.interval.ms" }},
878 
879  /*
880  * How often to query for the current client group coordinator
881  */
882  { FR_CONF_FUNC("coordinator_query_interval", FR_TYPE_TIME_DELTA, 0, kafka_config_parse, kafka_config_dflt),
883  .uctx = &(fr_kafka_conf_ctx_t){ .property = "coordinator.query.interval.ms" }},
884 
885 
887 };
888 
890  /*
891  * How many messages we process at a time
892  *
893  * High numbers may starve the worker thread
894  */
895  { FR_CONF_FUNC("max_messages_per_cycle", FR_TYPE_UINT32, 0, kafka_config_parse, kafka_config_dflt),
896  .uctx = &(fr_kafka_conf_ctx_t){ .property = "consume.callback.max.messages" }},
897 
898  /*
899  * Action to take when there is no initial offset
900  * in offset store or the desired offset is out of range.
901  */
903  .uctx = &(fr_kafka_conf_ctx_t){ .property = "auto.offset.reset" }},
904 
906 };
907 
908 /*
909  * Allows topic configurations in the format:
910  *
911  * topic {
912  * <name> {
913  * request_required_acks = ...
914  * }
915  * }
916  *
917  */
920 
922 };
923 
925  BASE_CONFIG,
927 
928  /*
929  * Maximum allowed time between calls to consume messages.
930  */
932  .uctx = &(fr_kafka_conf_ctx_t){ .property = "max.poll.interval.ms" }},
933 
934  /*
935  * Toggle auto commit
936  */
938  .uctx = &(fr_kafka_conf_ctx_t){ .property = "enable_auto.commit" }},
939 
940  /*
941  * Auto commit interval
942  */
944  .uctx = &(fr_kafka_conf_ctx_t){ .property = "auto.commit.interval.ms" }},
945 
946  /*
947  * Automatically store offset of last message provided to application.
948  */
949  { FR_CONF_FUNC("auto_offset_store", FR_TYPE_BOOL, 0, kafka_config_parse, kafka_config_dflt),
950  .uctx = &(fr_kafka_conf_ctx_t){ .property = "enable.auto.offset.store" }},
951 
952  /*
953  * Minimum number of messages per topic+partition librdkafka tries to
954  * maintain in the local consumer queue.
955  */
956  { FR_CONF_FUNC("queued_messages_min", FR_TYPE_UINT64, 0, kafka_config_parse, kafka_config_dflt),
957  .uctx = &(fr_kafka_conf_ctx_t){ .property = "queued.min.messages" }},
958 
959  /*
960  * Maximum size of queued pre-fetched messages in the local consumer queue.
961  */
962  { FR_CONF_FUNC("queued_messages_max_size", FR_TYPE_SIZE, 0, kafka_config_parse, kafka_config_dflt),
963  .uctx = &(fr_kafka_conf_ctx_t){ .property = "queued.max.messages.kbytes", .size_scale = 1024 }},
964 
965  /*
966  * Maximum time the broker may wait to fill the Fetch response.
967  */
969  .uctx = &(fr_kafka_conf_ctx_t){ .property = "fetch.wait.max.ms" }},
970 
971  /*
972  * Initial maximum number of bytes per topic+partition to request when
973  * fetching messages from the broker.
974  */
975  { FR_CONF_FUNC("fetch_message_max_size", FR_TYPE_SIZE, 0, kafka_config_parse, kafka_config_dflt),
976  .uctx = &(fr_kafka_conf_ctx_t){ .property = "fetch.message.max.bytes" }},
977 
978  /*
979  * Initial maximum number of bytes per topic+partition to request when
980  * fetching messages from the broker.
981  */
982  { FR_CONF_FUNC("fetch_partition_max_size", FR_TYPE_SIZE, 0, kafka_config_parse, kafka_config_dflt),
983  .uctx = &(fr_kafka_conf_ctx_t){ .property = "max.partition.fetch.bytes" }},
984 
985  /*
986  * Maximum amount of data the broker shall return for a Fetch request.
987  */
989  .uctx = &(fr_kafka_conf_ctx_t){ .property = "fetch.max.bytes" }},
990 
991  /*
992  * Minimum number of bytes the broker responds with.
993  */
995  .uctx = &(fr_kafka_conf_ctx_t){ .property = "fetch.min.bytes" }},
996 
997  /*
998  * How long to postpone the next fetch request for a topic+partition
999  * in case of a fetch error.
1000  */
1002  .uctx = &(fr_kafka_conf_ctx_t){ .property = "fetch.error.backoff.ms" }},
1003 
1004  /*
1005  * Controls how to read messages written transactionally
1006  */
1008  .uctx = &(fr_kafka_conf_ctx_t){ .property = "isolation.level" }},
1009 
1010  /*
1011  * Verify CRC32 of consumed messages, ensuring no on-the-wire or
1012  * on-disk corruption to the messages occurred.
1013  */
1015  .uctx = &(fr_kafka_conf_ctx_t){ .property = "check.crcs" }},
1016 
1017  /*
1018  * Allow automatic topic creation on the broker when subscribing
1019  * to or assigning non-existent topics
1020  */
1021  { FR_CONF_FUNC("auto_create_topic", FR_TYPE_BOOL, 0, kafka_config_parse, kafka_config_dflt),
1022  .uctx = &(fr_kafka_conf_ctx_t){ .property = "allow.auto.create.topics" }},
1023 
1025 
1026  CONF_PARSER_TERMINATOR
1027 };
1028 
1030  /*
1031  * This field indicates the number of acknowledgements the leader
1032  * broker must receive from ISR brokers before responding to the request.
1033  */
1035  .uctx = &(fr_kafka_conf_ctx_t){ .property = "request.required.acks" }},
1036 
1037  /*
1038  * medium The ack timeout of the producer request in milliseconds
1039  */
1041  .uctx = &(fr_kafka_conf_ctx_t){ .property = "request.timeout.ms" }},
1042 
1043  /*
1044  * Local message timeout
1045  */
1047  .uctx = &(fr_kafka_conf_ctx_t){ .property = "message.timeout.ms" }},
1048 
1049  /*
1050  * Partitioning strategy
1051  */
1053  .uctx = &(fr_kafka_conf_ctx_t){ .property = "partitioner" }},
1054 
1055  /*
1056  * compression codec to use for compressing message sets.
1057  */
1059  .uctx = &(fr_kafka_conf_ctx_t){ .property = "compression.type" }},
1060 
1061  /*
1062  * compression level to use
1063  */
1065  .uctx = &(fr_kafka_conf_ctx_t){ .property = "compression.level" }},
1066 
1068 };
1069 
1070 /*
1071  * Allows topic configurations in the format:
1072  *
1073  * topic {
1074  * <name> {
1075  * request_required_acks = ...
1076  * }
1077  * }
1078  *
1079  */
1082 
1084 };
1085 
1087  BASE_CONFIG,
1088 
1089  /*
1090  * Enables the transactional producer
1091  */
1093  .uctx = &(fr_kafka_conf_ctx_t){ .property = "transactional.id", .empty_default = true }},
1094 
1095  /*
1096  * The maximum amount of time in milliseconds that the transaction
1097  * coordinator will wait for a transaction status update from the
1098  * producer before proactively aborting the ongoing transaction.
1099  */
1101  .uctx = &(fr_kafka_conf_ctx_t){ .property = "transaction.timeout.ms" }},
1102 
1103  /*
1104  * When set to true, the producer will ensure that messages are
1105  * successfully produced exactly once and in the original produce
1106  * order.
1107  */
1109  .uctx = &(fr_kafka_conf_ctx_t){ .property = "enable.idempotence" }},
1110 
1111  /*
1112  * When set to true, any error that could result in a gap in the
1113  * produced message series when a batch of messages fails.
1114  */
1115  { FR_CONF_FUNC("gapless_guarantee", FR_TYPE_BOOL, 0, kafka_config_parse, kafka_config_dflt),
1116  .uctx = &(fr_kafka_conf_ctx_t){ .property = "enable.gapless.guarantee" }},
1117 
1118  /*
1119  * Maximum number of messages allowed on the producer queue.
1120  * This queue is shared by all topics and partitions.
1121  */
1122  { FR_CONF_FUNC("queue_max_messages", FR_TYPE_UINT32, 0, kafka_config_parse, kafka_config_dflt),
1123  .uctx = &(fr_kafka_conf_ctx_t){ .property = "queue.buffering.max.messages" }},
1124 
1125  /*
1126  * Maximum total message size sum allowed on the producer queue.
1127  */
1129  .uctx = &(fr_kafka_conf_ctx_t){ .property = "queue.buffering.max.kbytes", .size_scale = 1024 }},
1130 
1131  /*
1132  * How long we wait to aggregate messages
1133  */
1135  .uctx = &(fr_kafka_conf_ctx_t){ .property = "queue.buffering.max.ms" }},
1136 
1137  /*
1138  * How many times we resend a message
1139  */
1140  { FR_CONF_FUNC("message_retry_max", FR_TYPE_UINT32, 0, kafka_config_parse, kafka_config_dflt),
1141  .uctx = &(fr_kafka_conf_ctx_t){ .property = "message.send.max.retries" }},
1142 
1143  /*
1144  * The backoff time in milliseconds before retrying a protocol request.
1145  */
1146  { FR_CONF_FUNC("message_retry_interval", FR_TYPE_TIME_DELTA, 0, kafka_config_parse, kafka_config_dflt),
1147  .uctx = &(fr_kafka_conf_ctx_t){ .property = "retry.backoff.ms" }},
1148 
1149  /*
1150  * The threshold of outstanding not yet transmitted broker requests
1151  * needed to backpressure the producer's message accumulator.
1152  */
1153  { FR_CONF_FUNC("backpressure_threshold", FR_TYPE_UINT32, 0, kafka_config_parse, kafka_config_dflt),
1154  .uctx = &(fr_kafka_conf_ctx_t){ .property = "queue.buffering.backpressure.threshold" }},
1155 
1156  /*
1157  * compression codec to use for compressing message sets.
1158  */
1160  .uctx = &(fr_kafka_conf_ctx_t){ .property = "compression.type" }},
1161 
1162  /*
1163  * Maximum size (in bytes) of all messages batched in one MessageSet
1164  */
1166  .uctx = &(fr_kafka_conf_ctx_t){ .property = "batch.size" }},
1167 
1168  /*
1169  * Delay in milliseconds to wait to assign new sticky partitions for each topic
1170  */
1171  { FR_CONF_FUNC("sticky_partition_delay", FR_TYPE_TIME_DELTA, 0, kafka_config_parse, kafka_config_dflt),
1172  .uctx = &(fr_kafka_conf_ctx_t){ .property = "sticky.partitioning.linger.ms" }},
1173 
1175 
1176  CONF_PARSER_TERMINATOR
1177 };
while(1)
Definition: acutest.h:856
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
int cf_pair_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, CONF_PAIR *cp, conf_parser_t const *rule)
Parses a CONF_PAIR into a boxed value.
Definition: cf_parse.c:126
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
void const * uctx
User data accessible by the cf_parse_t func.
Definition: cf_parse.h:586
#define FR_CONF_SUBSECTION_GLOBAL(_name, _flags, _subcs)
conf_parser_t entry which runs conf_parser_t entries for a subsection without any output
Definition: cf_parse.h:374
fr_type_t type
An fr_type_t value, controls the output type.
Definition: cf_parse.h:567
#define fr_rule_multi(_rule)
Definition: cf_parse.h:449
char const * name1
Name of the CONF_ITEM to parse.
Definition: cf_parse.h:564
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
Definition: cf_parse.h:420
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
Definition: cf_parse.h:410
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition: cf_parse.h:412
#define FR_CONF_FUNC(_name, _type, _flags, _func, _dflt_func)
conf_parser_t entry which doesn't fill in a pointer or offset, but relies on functions to record valu...
Definition: cf_parse.h:361
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
Internal data that is associated with a configuration section.
Definition: cf_priv.h:113
Common header for all CONF_* types.
Definition: cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
Count the number of times an attribute occurs in a parent section.
Definition: cf_util.c:1437
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
void cf_pair_mark_parsed(CONF_PAIR *cp)
Mark a pair as parsed.
Definition: cf_util.c:1318
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition: cf_util.c:1680
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:649
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition: cf_util.c:1370
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition: cf_util.c:1220
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_data_add(_cf, _data, _name, _free)
Definition: cf_util.h:231
#define cf_data_find(_cf, _type, _name)
Definition: cf_util.h:220
#define cf_parent(_cf)
Definition: cf_util.h:98
#define cf_log_perr(_cf, _fmt,...)
Definition: cf_util.h:272
#define cf_log_debug(_cf, _fmt,...)
Definition: cf_util.h:268
#define CF_IDENT_ANY
Definition: cf_util.h:78
Test enumeration values.
Definition: dict_test.h:92
static conf_parser_t const kafka_connection_config[]
Definition: base.c:678
static conf_parser_t const kafka_base_consumer_topics_config[]
Definition: base.c:918
static int kafka_topic_config_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
Return the default value for a topic from the kafka client library.
Definition: base.c:286
static size_t kafka_check_cert_cn_table_len
Definition: base.c:617
size_t size_scale
Divide/multiply FR_TYPE_SIZE by this amount.
Definition: base.c:47
static conf_parser_t const kafka_base_consumer_topic_config[]
Definition: base.c:889
rd_kafka_conf_t * conf
Definition: base.c:33
rd_kafka_topic_conf_t * conf
Definition: base.c:37
#define BASE_CONFIG
Definition: base.c:823
static fr_kafka_topic_conf_t * kafka_topic_conf_from_cs(CONF_SECTION *cs)
Definition: base.c:97
static int kafka_config_parse(TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
Translate config items directly to settings in a kafka config struct.
Definition: base.c:423
conf_parser_t const kafka_base_consumer_config[]
Definition: base.c:924
char const * property
Kafka configuration property.
Definition: base.c:49
static int _kafka_topic_conf_free(fr_kafka_topic_conf_t *ktc)
Destroy a kafka topic configuration handle.
Definition: base.c:90
static conf_parser_t const kafka_sasl_oauth_config[]
Definition: base.c:541
static fr_table_ptr_sorted_t kafka_check_cert_cn_table[]
Definition: base.c:611
static conf_parser_t const kafka_version_config[]
Definition: base.c:755
char const * string_sep
Used for multi-value configuration items.
Definition: base.c:51
static conf_parser_t const kafka_consumer_group_config[]
Definition: base.c:848
static conf_parser_t const kafka_tls_config[]
Definition: base.c:619
static int kafka_config_dflt(CONF_PAIR **out, void *parent, CONF_SECTION *cs, fr_token_t quote, conf_parser_t const *rule)
Return the default value from the kafka client library.
Definition: base.c:204
static conf_parser_t const kafka_base_producer_topics_config[]
Definition: base.c:1080
static int kafka_topic_config_parse(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
Translate config items directly to settings in a kafka topic config struct.
Definition: base.c:495
bool empty_default
Don't produce messages saying the default is missing.
Definition: base.c:45
conf_parser_t const kafka_base_producer_config[]
Definition: base.c:1086
static int _kafka_conf_free(fr_kafka_conf_t *kc)
Destroy a kafka configuration handle.
Definition: base.c:60
static conf_parser_t const kafka_metadata_config[]
Definition: base.c:783
size_t * mapping_len
Length of the mapping tables.
Definition: base.c:43
fr_table_ptr_sorted_t * mapping
Mapping table between string constant.
Definition: base.c:41
static conf_parser_t const kafka_sasl_kerberos_config[]
Definition: base.c:551
static conf_parser_t const kafka_base_producer_topic_config[]
Definition: base.c:1029
static int kafka_config_parse_single(char const **out, CONF_PAIR *cp, conf_parser_t const *rule)
Definition: base.c:324
static int kafka_config_dflt_single(CONF_PAIR **out, UNUSED void *parent, CONF_SECTION *cs, char const *value, fr_token_t quote, conf_parser_t const *rule)
Perform any conversions necessary to map kafka defaults to our values.
Definition: base.c:127
static fr_kafka_conf_t * kafka_conf_from_cs(CONF_SECTION *cs)
Definition: base.c:67
static conf_parser_t const kafka_sasl_config[]
Definition: base.c:585
talloc_free(reap)
size_t fr_sbuff_out_unescape_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
Definition: merged_model.c:177
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
@ FR_TYPE_INT8
8 Bit signed integer.
Definition: merged_model.c:103
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_INT16
16 Bit signed integer.
Definition: merged_model.c:104
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
Definition: merged_model.c:115
unsigned char uint8_t
Definition: merged_model.c:30
ssize_t fr_slen_t
Definition: merged_model.c:35
static size_t array[MY_ARRAY_SIZE]
static rs_t * conf
Definition: radsniff.c:53
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1554
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN(_start, _len_or_end)
char const * name
Name for rule set to aid we debugging.
Definition: sbuff.h:177
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define FR_SBUFF_OUT(_start, _len_or_end)
char subs[UINT8_MAX+1]
Special characters and their substitutions.
Definition: sbuff.h:180
#define FR_SBUFF_TERM(_str)
Initialise a terminal structure with a single string.
Definition: sbuff.h:155
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Set of terminal elements.
Definition: merged_model.c:161
Set of parsing rules for *unescape_until functions.
Definition: merged_model.c:163
fr_slen_t fr_size_from_str(size_t *out, fr_sbuff_t *in)
Parse a size string with optional unit.
Definition: size.c:40
fr_slen_t fr_size_to_str(fr_sbuff_t *out, size_t in)
Print a size string with unit.
Definition: size.c:155
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
return count
Definition: module.c:175
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
#define fr_table_str_by_str_value(_table, _str_value, _def)
Brute force search a sorted or ordered ptr table, assuming the pointers are strings.
Definition: table.h:106
An element in a lexicographically sorted array of name to ptr mappings.
Definition: table.h:61
fr_slen_t talloc_array_concat(fr_sbuff_t *out, char const *const *array, char const *sep)
Concat an array of strings (not NULL terminated), with a string separator.
Definition: talloc.c:802
fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
Create fr_time_delta_t from a string.
Definition: time.c:445
fr_slen_t fr_time_delta_to_str(fr_sbuff_t *out, fr_time_delta_t delta, fr_time_res_t res, bool is_unsigned)
Print fr_time_delta_t to a string with an appropriate suffix.
Definition: time.c:468
@ FR_TIME_RES_MSEC
Definition: time.h:58
@ FR_TIME_RES_SEC
Definition: time.h:50
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
Definition: time.h:635
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
enum fr_token fr_token_t
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_EQ
Definition: token.h:83
static fr_slen_t parent
Definition: pair.h:844
#define fr_type_is_string(_x)
Definition: types.h:327
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition: value.c:3672
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition: value.h:475
static size_t char ** out
Definition: value.h:984