#ifndef MSP_NET_RESOLVE_H_
#define MSP_NET_RESOLVE_H_
+#include <deque>
+#include <memory>
#include <string>
-#include "constants.h"
+#include <msp/core/mutex.h>
+#include <msp/core/semaphore.h>
+#include <msp/core/thread.h>
+#include <msp/io/eventdispatcher.h>
+#include <msp/io/pipe.h>
+#include "sockaddr.h"
namespace Msp {
namespace Net {
-class SockAddr;
-
/** Resolves host and service names into a socket address. If host is empty,
the loopback address will be used. If host is "*", the wildcard address will
be used. If service is empty, a socket address with a null service will be
with a numeric IPv6 address, it must be enclosed in brackets. */
SockAddr *resolve(const std::string &, Family = UNSPEC);
+
+/**
+An asynchronous name resolver. Blocking calls are performed in a thread and
+completion is notified with one of the two signals.
+*/
+class Resolver
+{
+private:
+ struct Task
+ {
+ unsigned tag = 0;
+ std::string host;
+ std::string serv;
+ Family family = UNSPEC;
+ std::unique_ptr<SockAddr> addr;
+ std::unique_ptr<std::runtime_error> error;
+
+ bool is_complete() const { return addr || error; }
+ };
+
+ class WorkerThread: public Thread
+ {
+ private:
+ std::deque<Task> queue;
+ Mutex queue_mutex;
+ Semaphore sem;
+ IO::Pipe notify_pipe;
+ bool done = false;
+
+ public:
+ WorkerThread();
+ ~WorkerThread();
+
+ void add_task(Task &&);
+ Task *get_complete_task();
+ void pop_complete_task();
+
+ IO::Pipe &get_notify_pipe() { return notify_pipe; }
+
+ private:
+ void main() override;
+ };
+
+public:
+ sigc::signal<void, unsigned, const SockAddr &> signal_address_resolved;
+ sigc::signal<void, unsigned, const std::exception &> signal_resolve_failed;
+
+private:
+ IO::EventDispatcher *event_disp = nullptr;
+ WorkerThread thread;
+ unsigned next_tag = 1;
+
+public:
+ Resolver();
+
+ /** Sets the event dispatcher to use. With no event dispatcher, tick() must
+ be called regularly to emit the completion signals. */
+ void use_event_dispatcher(IO::EventDispatcher *);
+
+ /** Resolves host and service names into a socket address. Semantics are
+ the same as the namespace-scope resolve function. */
+ unsigned resolve(const std::string &, const std::string &, Family = UNSPEC);
+
+ unsigned resolve(const std::string &, Family = UNSPEC);
+
+ /** Checks for any completed tasks and emits the appropriate singals. */
+ void tick();
+
+private:
+ void task_done();
+};
+
} // namespace Net
} // namespace Msp