From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/libs/network/connect/resolve.c | 211 +++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/libs/network/connect/resolve.c (limited to 'src/libs/network/connect/resolve.c') diff --git a/src/libs/network/connect/resolve.c b/src/libs/network/connect/resolve.c new file mode 100644 index 0000000..646e437 --- /dev/null +++ b/src/libs/network/connect/resolve.c @@ -0,0 +1,211 @@ +/* + * Copyright 2006 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define RESOLVE_INTERNAL +#include "resolve.h" + +#include +#include +#include + +#define DEBUG_RESOLVE_REF +#ifdef DEBUG_RESOLVE_REF +# include "types.h" +# include "libs/log.h" +# include +#endif + +static ResolveState * +ResolveState_new(void) { + return (ResolveState *) malloc(sizeof (ResolveState)); +} + +static void +ResolveState_free(ResolveState *resolveState) { + free(resolveState); +} + +static void +ResolveState_delete(ResolveState *resolveState) { + assert(resolveState->callbackID == CallbackID_invalid); + ResolveState_free(resolveState); +} + +void +ResolveState_incRef(ResolveState *resolveState) { + assert(resolveState->refCount < REFCOUNT_MAX); + resolveState->refCount++; +#ifdef DEBUG_RESOLVE_REF + log_add(log_Debug, "ResolveState %08" PRIxPTR ": ref++ (%d)", + (uintptr_t) resolveState, resolveState->refCount); +#endif +} + +bool +ResolveState_decRef(ResolveState *resolveState) { + assert(resolveState->refCount > 0); + resolveState->refCount--; +#ifdef DEBUG_RESOLVE_REF + log_add(log_Debug, "ResolveState %08" PRIxPTR ": ref-- (%d)", + (uintptr_t) resolveState, resolveState->refCount); +#endif + if (resolveState->refCount == 0) { + ResolveState_delete(resolveState); + return true; + } + return false; +} + +void +ResolveState_setExtra(ResolveState *resolveState, void *extra) { + resolveState->extra = extra; +} + +void * +ResolveState_getExtra(ResolveState *resolveState) { + return resolveState->extra; +} + +static void +doResolveCallback(ResolveState *resolveState) { + ResolveState_incRef(resolveState); + (*resolveState->callback)(resolveState, resolveState->result); + { + bool released = ResolveState_decRef(resolveState); + assert(released); + (void) released; // In case assert() evaluates to nothing. + } +} + +static void +doResolveErrorCallback(ResolveState *resolveState) { + ResolveState_incRef(resolveState); + resolveState->errorCallback(resolveState, &resolveState->error); + { + bool released = ResolveState_decRef(resolveState); + assert(released); + (void) released; // In case assert() evaluates to nothing. + } +} + +static void +resolveCallback(ResolveState *resolveState) { + resolveState->callbackID = CallbackID_invalid; + if (resolveState->error.gaiRes == 0) { + // Successful lookup. + doResolveCallback(resolveState); + } else { + // Lookup failed. + doResolveErrorCallback(resolveState); + } +} + +// Function that does getaddrinfo() and calls the callback function when +// the result is available. +// TODO: actually make this function asynchronous. Right now it just calls +// getaddrinfo() (which blocks) and then schedules the callback. +ResolveState * +getaddrinfoAsync(const char *node, const char *service, + const struct addrinfo *hints, ResolveFlags *flags, + ResolveCallback callback, ResolveErrorCallback errorCallback, + ResolveCallbackArg extra) { + ResolveState *resolveState; + + resolveState = ResolveState_new(); + resolveState->refCount = 1; +#ifdef DEBUG_RESOLVE_REF + log_add(log_Debug, "ResolveState %08" PRIxPTR ": ref=1 (%d)", + (uintptr_t) resolveState, resolveState->refCount); +#endif + resolveState->state = Resolve_resolving; + resolveState->flags = *flags; + resolveState->callback = callback; + resolveState->errorCallback = errorCallback; + resolveState->extra = extra; + resolveState->result = NULL; + + resolveState->error.gaiRes = + getaddrinfo(node, service, hints, &resolveState->result); + resolveState->error.err = errno; + + resolveState->callbackID = Callback_add( + (CallbackFunction) resolveCallback, (CallbackArg) resolveState); + + return resolveState; +} + +void +Resolve_close(ResolveState *resolveState) { + if (resolveState->callbackID != CallbackID_invalid) { + Callback_remove(resolveState->callbackID); + resolveState->callbackID = CallbackID_invalid; + } + resolveState->state = Resolve_closed; + ResolveState_decRef(resolveState); +} + +// Split an addrinfo list into two separate lists, one with structures with +// the specified value for the ai_family field, the other with the other +// structures. The order of entries in the resulting lists will remain +// the same as in the original list. +// info - the original list +// family - the family for the first list +// selected - pointer to where the list of selected structures should be +// stored +// selectedEnd - pointer to where the end of 'selected' should be stored +// rest - pointer to where the list of not-selected structures should be +// stored +// restEnd - pointer to where the end of 'rest' should be stored +// +// Yes, it is allowed to modify the ai_next field of addrinfo structures. +// Or at least, it's not disallowed by RFC 3493, and the following +// text from that RFC seems to suggest it should be possible: +// ] The freeaddrinfo() function must support the freeing of arbitrary +// ] sublists of an addrinfo list originally returned by getaddrinfo(). +void +splitAddrInfoOnFamily(struct addrinfo *info, int family, + struct addrinfo **selected, struct addrinfo ***selectedEnd, + struct addrinfo **rest, struct addrinfo ***restEnd) { + struct addrinfo *selectedFirst; + struct addrinfo **selectedNext; + struct addrinfo *restFirst; + struct addrinfo **restNext; + + selectedNext = &selectedFirst; + restNext = &restFirst; + while (info != NULL) { + if (info->ai_family == family) { + *selectedNext = info; + selectedNext = &(*selectedNext)->ai_next; + } else { + *restNext = info; + restNext = &(*restNext)->ai_next; + } + info = info->ai_next; + } + *selectedNext = NULL; + *restNext = NULL; + + // Fill in the result parameters. + *selected = selectedFirst; + *selectedEnd = selectedNext; + *rest = restFirst; + *restEnd = restNext; +} + + -- cgit v1.2.3