} while (0)
#ifdef HAVE_PTHREAD_H
-static pthread_mutex_t autofree_context = PTHREAD_MUTEX_INITIALIZER;
# define PTHREAD_MUTEX_LOCK pthread_mutex_lock
# define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
#else
fr_thread_local_setup(char *, fr_inet_ntop_buffer); /* macro */
+typedef struct fr_talloc_link {
+ bool armed;
+ TALLOC_CTX *child;
+} fr_talloc_link_t;
+
/** Sets a signal handler using sigaction if available, else signal
*
* @param sig to set handler for.
return 0;
}
-/** Allocates a new talloc context from the root autofree context
+static int _fr_trigger_talloc_ctx_free(fr_talloc_link_t *trigger)
+{
+ if (trigger->armed) talloc_free(trigger->child);
+
+ return 0;
+}
+
+static int _fr_disarm_talloc_ctx_free(bool **armed)
+{
+ **armed = false;
+ return 0;
+}
+
+/** Link a parent and a child context, so the child is freed before the parent
*
- * This function is threadsafe, whereas using the NULL context is not.
+ * @note This is not thread safe. Do not free parent before threads are joined, do not call from a child thread.
+ * @note It's OK to free the child before threads are joined, but this will leak memory until the parent is freed.
*
- * @note The returned context must be freed by the caller.
- * @returns a new talloc context parented by the root autofree context.
+ * @param parent who's fate the child should share.
+ * @param child bound to parent's lifecycle.
+ * @return 0 on success -1 on failure.
*/
-TALLOC_CTX *fr_autofree_ctx(void)
+int fr_link_talloc_ctx_free(TALLOC_CTX *parent, TALLOC_CTX *child)
{
- static TALLOC_CTX *ctx = NULL, *child;
- PTHREAD_MUTEX_LOCK(&autofree_context);
- if (!ctx) {
- ctx = talloc_autofree_context();
+ fr_talloc_link_t *trigger;
+ bool **disarm;
+
+ trigger = talloc(parent, fr_talloc_link_t);
+ if (!trigger) return -1;
+
+ disarm = talloc(child, bool *);
+ if (!disarm) {
+ talloc_free(trigger);
+ return -1;
}
- child = talloc_new(ctx);
- PTHREAD_MUTEX_UNLOCK(&autofree_context);
+ trigger->child = child;
+ trigger->armed = true;
+ *disarm = &trigger->armed;
- return child;
+ talloc_set_destructor(trigger, _fr_trigger_talloc_ctx_free);
+ talloc_set_destructor(disarm, _fr_disarm_talloc_ctx_free);
+
+ return 0;
}
/*
* We assume the number is the bigendian representation of the
* IP address.
*/
- } else if (is_integer(value)) {
+ } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
out->ipaddr.ip4addr.s_addr = htonl(strtoul(value, NULL, 0));
} else if (!resolve) {
if (inet_pton(AF_INET, value, &(out->ipaddr.ip4addr.s_addr)) <= 0) {
*/
int fr_pton(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve)
{
- char const *p;
- int af = AF_INET;
-
- for (p = value; *p != '\0'; p++) {
- if ((*p == ':') ||
- (*p == '[') ||
- (*p == ']')) {
- af = AF_INET6;
- break;
- }
- }
-
- switch (af) {
- case AF_INET:
- return fr_pton4(out, value, inlen, resolve, true);
+ size_t len, i;
+ len = (inlen == 0) ? strlen(value) : inlen;
+ for (i = 0; i < len; i++) switch (value[i]) {
/*
- * If we found ':' or '[' or ']' in the above string, there's
- * no way this can be a hostname, so don't try to resolve.
+ * Chars illegal in domain names and IPv4 addresses.
+ * Must be v6 and cannot be a domain.
*/
- case AF_INET6:
+ case ':':
+ case '[':
+ case ']':
return fr_pton6(out, value, inlen, false, false);
+ /*
+ * Chars which don't really tell us anything
+ */
+ case '.':
+ case '/':
+ continue;
+
default:
- return -1;
+ /*
+ * Outside the range of IPv4 chars, must be a domain
+ * Use A record in preference to AAAA record.
+ */
+ if ((value[i] < '0') || (value[i] > '9')) {
+ if (!resolve) return -1;
+ return fr_pton4(out, value, inlen, true, true);
+ }
+ break;
}
+
+ /*
+ * All chars were in the IPv4 set [0-9/.], must be an IPv4
+ * address.
+ */
+ return fr_pton4(out, value, inlen, false, false);
}
/** Check if the IP address is equivalent to INADDR_ANY
addr->prefix = prefix;
}
-static char const *hextab = "0123456789abcdef";
+static char const hextab[] = "0123456789abcdef";
/** Convert hex strings to binary data
*
* @param bin Buffer to write output to.
- * @param hex input string.
* @param outlen length of output buffer (or length of input string / 2).
+ * @param hex input string.
+ * @param inlen length of the input string
* @return length of data written to buffer.
*/
-size_t fr_hex2bin(uint8_t *bin, char const *hex, size_t outlen)
+size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
{
size_t i;
+ size_t len;
char *c1, *c2;
- for (i = 0; i < outlen; i++) {
- if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
- !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
+ /*
+ * Smartly truncate output, caller should check number of bytes
+ * written.
+ */
+ len = inlen >> 1;
+ if (len > outlen) len = outlen;
+
+ for (i = 0; i < len; i++) {
+ if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), sizeof(hextab))) ||
+ !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), sizeof(hextab))))
break;
- bin[i] = ((c1-hextab)<<4) + (c2-hextab);
+ bin[i] = ((c1-hextab)<<4) + (c2-hextab);
}
return i;
memcpy(&s4, sa, sizeof(s4));
ipaddr->af = AF_INET;
+ ipaddr->prefix = 32;
ipaddr->ipaddr.ip4addr = s4.sin_addr;
if (port) *port = ntohs(s4.sin_port);
memcpy(&s6, sa, sizeof(s6));
ipaddr->af = AF_INET6;
+ ipaddr->prefix = 128;
ipaddr->ipaddr.ip6addr = s6.sin6_addr;
if (port) *port = ntohs(s6.sin6_port);
ipaddr->scope = s6.sin6_scope_id;