2 #define _WIN32_WINNT 0x0501
7 #include <msp/core/systemerror.h>
8 #include <msp/strings/format.h>
9 #include "sockaddr_private.h"
17 void parse_host_serv(const string &str, string &host, string &serv)
21 string::size_type bracket = str.find(']');
22 host = str.substr(1, bracket-1);
23 string::size_type colon = str.find(':', bracket);
24 if(colon!=string::npos)
25 serv = str.substr(colon+1);
29 string::size_type colon = str.find(':');
30 if(colon!=string::npos)
32 host = str.substr(0, colon);
33 serv = str.substr(colon+1);
46 SockAddr *resolve(const string &host, const string &serv, Family family)
48 const char *chost = (host.empty() ? 0 : host.c_str());
49 const char *cserv = (serv.empty() ? 0 : serv.c_str());
57 addrinfo hints = { flags, family_to_sys(family), 0, 0, 0, 0, 0, 0 };
60 int err = getaddrinfo(chost, cserv, &hints, &res);
64 sa.size = res->ai_addrlen;
65 const char *sptr = reinterpret_cast<const char *>(res->ai_addr);
66 char *dptr = reinterpret_cast<char *>(&sa.addr);
67 copy(sptr, sptr+res->ai_addrlen, dptr);
68 SockAddr *addr = SockAddr::new_from_sys(sa);
74 throw system_error("getaddrinfo", WSAGetLastError());
76 throw system_error("getaddrinfo", gai_strerror(err));
80 SockAddr *resolve(const string &str, Family family)
83 parse_host_serv(str, host, serv);
85 return resolve(host, serv, family);
93 thread.get_notify_pipe().signal_data_available.connect(sigc::mem_fun(this, &Resolver::task_done));
96 void Resolver::use_event_dispatcher(IO::EventDispatcher *ed)
99 event_disp->remove(thread.get_notify_pipe());
102 event_disp->add(thread.get_notify_pipe());
105 unsigned Resolver::resolve(const string &host, const string &serv, Family family)
108 task.tag = next_tag++;
111 task.family = family;
112 thread.add_task(task);
116 unsigned Resolver::resolve(const string &str, Family family)
119 parse_host_serv(str, host, serv);
121 return resolve(host, serv, family);
124 void Resolver::tick()
126 if(IO::poll(thread.get_notify_pipe(), IO::P_INPUT, Time::zero))
130 void Resolver::task_done()
133 thread.get_notify_pipe().read(buf, sizeof(buf));
135 while(Task *task = thread.get_complete_task())
138 signal_address_resolved.emit(task->tag, *task->addr);
140 signal_resolve_failed.emit(task->tag, *task->error);
141 thread.pop_complete_task();
146 Resolver::Task::Task():
154 Resolver::WorkerThread::WorkerThread():
162 Resolver::WorkerThread::~WorkerThread()
169 void Resolver::WorkerThread::add_task(const Task &t)
171 MutexLock lock(queue_mutex);
172 bool was_starved = (queue.empty() || queue.back().is_complete());
178 Resolver::Task *Resolver::WorkerThread::get_complete_task()
180 MutexLock lock(queue_mutex);
181 if(!queue.empty() && queue.front().is_complete())
182 return &queue.front();
187 void Resolver::WorkerThread::pop_complete_task()
189 MutexLock lock(queue_mutex);
190 if(!queue.empty() && queue.front().is_complete())
192 delete queue.front().addr;
193 delete queue.front().error;
198 void Resolver::WorkerThread::main()
209 MutexLock lock(queue_mutex);
210 for(list<Task>::iterator i=queue.begin(); (!task && i!=queue.end()); ++i)
211 if(!i->is_complete())
219 SockAddr *addr = Net::resolve(task->host, task->serv, task->family);
221 MutexLock lock(queue_mutex);
225 catch(const runtime_error &e)
227 MutexLock lock(queue_mutex);
228 task->error = new runtime_error(e);