X-Git-Url: http://git.tdb.fi/?p=libs%2Fnet.git;a=blobdiff_plain;f=source%2Fnet%2Fresolve.cpp;h=9ec5395df99c5b2504965dbb998029d0933f7a30;hp=e8aad664d3cb5c722f032874352c60c15a5309e9;hb=HEAD;hpb=debe1004676d5431e571d9c4361072661dcc88c4 diff --git a/source/net/resolve.cpp b/source/net/resolve.cpp index e8aad66..9ec5395 100644 --- a/source/net/resolve.cpp +++ b/source/net/resolve.cpp @@ -1,32 +1,55 @@ -#ifdef WIN32 -#define _WIN32_WINNT 0x0501 -#include -#else -#include -#endif +#include "resolve.h" #include #include +#include "platform_api.h" #include "sockaddr_private.h" #include "socket.h" -#include "resolve.h" using namespace std; +namespace { + +void parse_host_serv(const string &str, string &host, string &serv) +{ + if(str[0]=='[') + { + string::size_type bracket = str.find(']'); + host = str.substr(1, bracket-1); + string::size_type colon = str.find(':', bracket); + if(colon!=string::npos) + serv = str.substr(colon+1); + } + else + { + string::size_type colon = str.find(':'); + if(colon!=string::npos) + { + host = str.substr(0, colon); + serv = str.substr(colon+1); + } + else + host = str; + } +} + +} + + namespace Msp { namespace Net { SockAddr *resolve(const string &host, const string &serv, Family family) { - const char *chost = (host.empty() ? 0 : host.c_str()); - const char *cserv = (serv.empty() ? 0 : serv.c_str()); - unsigned flags = 0; + const char *chost = (host.empty() ? nullptr : host.c_str()); + const char *cserv = (serv.empty() ? nullptr : serv.c_str()); + int flags = 0; if(host=="*") { flags = AI_PASSIVE; - chost = 0; + chost = nullptr; } - addrinfo hints = { flags, family_to_sys(family), 0, 0, 0, 0, 0, 0 }; + addrinfo hints = { flags, family_to_sys(family), 0, 0, 0, nullptr, nullptr, nullptr }; addrinfo *res; int err = getaddrinfo(chost, cserv, &hints, &res); @@ -42,7 +65,7 @@ SockAddr *resolve(const string &host, const string &serv, Family family) return addr; } else -#ifdef WIN32 +#ifdef _WIN32 throw system_error("getaddrinfo", WSAGetLastError()); #else throw system_error("getaddrinfo", gai_strerror(err)); @@ -52,39 +75,152 @@ SockAddr *resolve(const string &host, const string &serv, Family family) SockAddr *resolve(const string &str, Family family) { string host, serv; - if(str[0]=='[') + parse_host_serv(str, host, serv); + + return resolve(host, serv, family); +} + + +Resolver::Resolver() +{ + thread.get_notify_pipe().signal_data_available.connect(sigc::mem_fun(this, &Resolver::task_done)); +} + +void Resolver::use_event_dispatcher(IO::EventDispatcher *ed) +{ + if(event_disp) + event_disp->remove(thread.get_notify_pipe()); + event_disp = ed; + if(event_disp) + event_disp->add(thread.get_notify_pipe()); +} + +unsigned Resolver::resolve(const string &host, const string &serv, Family family) +{ + Task task; + task.tag = next_tag++; + task.host = host; + task.serv = serv; + task.family = family; + thread.add_task(move(task)); + return task.tag; +} + +unsigned Resolver::resolve(const string &str, Family family) +{ + string host, serv; + parse_host_serv(str, host, serv); + + return resolve(host, serv, family); +} + +void Resolver::tick() +{ + if(IO::poll(thread.get_notify_pipe(), IO::P_INPUT, Time::zero)) + task_done(); +} + +void Resolver::task_done() +{ + char buf[64]; + thread.get_notify_pipe().read(buf, sizeof(buf)); + + while(Task *task = thread.get_complete_task()) { - unsigned bracket = str.find(']'); - host = str.substr(1, bracket-1); - unsigned colon = str.find(':', bracket); - if(colon!=string::npos) - serv = str.substr(colon+1); + if(task->addr) + signal_address_resolved.emit(task->tag, *task->addr); + else if(task->error) + { + if(signal_resolve_failed.empty()) + { + unique_ptr err = move(task->error); + thread.pop_complete_task(); + throw *err; + } + signal_resolve_failed.emit(task->tag, *task->error); + } + thread.pop_complete_task(); } +} + + +Resolver::WorkerThread::WorkerThread(): + Thread("Resolver"), + sem(1) +{ + launch(); +} + +Resolver::WorkerThread::~WorkerThread() +{ + done = true; + sem.signal(); + join(); +} + +void Resolver::WorkerThread::add_task(Task &&t) +{ + MutexLock lock(queue_mutex); + bool was_starved = (queue.empty() || queue.back().is_complete()); + queue.push_back(move(t)); + if(was_starved) + sem.signal(); +} + +Resolver::Task *Resolver::WorkerThread::get_complete_task() +{ + MutexLock lock(queue_mutex); + if(!queue.empty() && queue.front().is_complete()) + return &queue.front(); else + return nullptr; +} + +void Resolver::WorkerThread::pop_complete_task() +{ + MutexLock lock(queue_mutex); + if(!queue.empty() && queue.front().is_complete()) + queue.pop_front(); +} + +void Resolver::WorkerThread::main() +{ + bool wait = true; + while(!done) { - unsigned colon = str.find(':'); - if(colon!=string::npos) + if(wait) + sem.wait(); + wait = false; + + Task *task = nullptr; { - host = str.substr(0, colon); - serv = str.substr(colon+1); + MutexLock lock(queue_mutex); + for(auto i=queue.begin(); (!task && i!=queue.end()); ++i) + if(!i->is_complete()) + task = &*i; + } + + if(task) + { + try + { + unique_ptr addr(Net::resolve(task->host, task->serv, task->family)); + { + MutexLock lock(queue_mutex); + task->addr = move(addr); + } + } + catch(const runtime_error &e) + { + MutexLock lock(queue_mutex); + task->error = make_unique(e); + } + notify_pipe.put(1); } else - host = str; + wait = true; } - - return resolve(host, serv, family); } - /*sockaddr sa; - unsigned size = fill_sockaddr(sa); - char hst[128]; - char srv[128]; - int err = getnameinfo(&sa, size, hst, 128, srv, 128, 0); - if(err==0) - { - host = hst; - serv = srv; - }*/ - } // namespace Net } // namespace Msp