]> git.tdb.fi Git - libs/net.git/blobdiff - source/net/resolve.h
Add a dynamic receiver class for more flexible packet handling
[libs/net.git] / source / net / resolve.h
index 256455fcb18febb08384fd7e6f50e17d35064310..3071b771f569aa57f196c41cc4f8f9520c715130 100644 (file)
 #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 "mspnet_api.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
 returned.  With the IP families, these are not very useful. */
-SockAddr *resolve(const std::string &, const std::string &, Family = UNSPEC);
+MSPNET_API SockAddr *resolve(const std::string &, const std::string &, Family = UNSPEC);
 
 /** And overload of resolve() that takes host and service as a single string,
 separated by a colon.  If the host part contains colons, such as is the case
 with a numeric IPv6 address, it must be enclosed in brackets. */
-SockAddr *resolve(const std::string &, Family = UNSPEC);
+MSPNET_API 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 MSPNET_API 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