Currently, when a DNS lookup is initiated from a particular socket, an onDNS handler is installed in the socket. However, if a second query is initiated before the first finishes, that can overwrite the original onDNS handler. This creates a race condition on a per-socket basis.
There are three steps to a solution for this problem:
Document the race condition and provide a workaround (create a socket for each DNS lookup)
Provide a mechanism for escalating function pointer/void* pairs to full C++11 functors (including lambdas, etc.)
Provide a DNS lookup API that does not require a socket.
C Function escalation mechanism
It is common practice to provide the DNS callback with a void* user-supplied callback.
This could be used to supply a object/function pair, though this does not account for virtual inheritance. The Function API could provide a convenient abstraction for this problem, allowing a C function pointer with a void * context object to escalate to a full C++11 call, including lambdas, etc.
Providing this abstraction requires a three class-static API functions provided by the Function class:
get_reference() obtains a void * pointer to the target functor and increment a the reference count
call_from_void() Translates a void * back to a FunctionInterface * and calls it
call_from_void_dec() Exactly the same as call_from_void(), except that it also decrements the reference count.
DNS lookup API
The DNS lookup API currently uses the Socket instance as a proxy for discovering the stack in use. This is unnecessary and makes the API more cumbersome. In single-stack environments, resolve() can be a free function. In multi-stack environments, it can be:
a free/static function that iterates through stacks until a match is found
a free/static function that takes either a stack index or a stack ID
a function bound to each network interface
a function bound to the socket, that requires an open socket (the current status-quo)
Option 1) seems to be the least cumbersome option.
Currently, when a DNS lookup is initiated from a particular socket, an onDNS handler is installed in the socket. However, if a second query is initiated before the first finishes, that can overwrite the original onDNS handler. This creates a race condition on a per-socket basis.
There are three steps to a solution for this problem:
void*
pairs to full C++11 functors (including lambdas, etc.)C Function escalation mechanism
It is common practice to provide the DNS callback with a
void*
user-supplied callback.This could be used to supply a object/function pair, though this does not account for virtual inheritance. The
Function
API could provide a convenient abstraction for this problem, allowing a C function pointer with avoid *
context object to escalate to a full C++11 call, including lambdas, etc.Providing this abstraction requires a three class-static API functions provided by the
Function
class:get_reference()
obtains avoid *
pointer to the target functor and increment a the reference countcall_from_void()
Translates avoid *
back to aFunctionInterface *
and calls itcall_from_void_dec()
Exactly the same ascall_from_void()
, except that it also decrements the reference count.DNS lookup API
The DNS lookup API currently uses the
Socket
instance as a proxy for discovering the stack in use. This is unnecessary and makes the API more cumbersome. In single-stack environments,resolve()
can be a free function. In multi-stack environments, it can be:Option 1) seems to be the least cumbersome option.
cc @bogdanm @adbridge @autopulated @0xc0170