1 #include "platform_api.h"
2 #include <msp/core/systemerror.h>
3 #include <msp/strings/format.h>
4 #include "sockaddr_private.h"
12 void parse_host_serv(const string &str, string &host, string &serv)
16 string::size_type bracket = str.find(']');
17 host = str.substr(1, bracket-1);
18 string::size_type colon = str.find(':', bracket);
19 if(colon!=string::npos)
20 serv = str.substr(colon+1);
24 string::size_type colon = str.find(':');
25 if(colon!=string::npos)
27 host = str.substr(0, colon);
28 serv = str.substr(colon+1);
41 SockAddr *resolve(const string &host, const string &serv, Family family)
43 const char *chost = (host.empty() ? 0 : host.c_str());
44 const char *cserv = (serv.empty() ? 0 : serv.c_str());
52 addrinfo hints = { flags, family_to_sys(family), 0, 0, 0, 0, 0, 0 };
55 int err = getaddrinfo(chost, cserv, &hints, &res);
59 sa.size = res->ai_addrlen;
60 const char *sptr = reinterpret_cast<const char *>(res->ai_addr);
61 char *dptr = reinterpret_cast<char *>(&sa.addr);
62 copy(sptr, sptr+res->ai_addrlen, dptr);
63 SockAddr *addr = SockAddr::new_from_sys(sa);
69 throw system_error("getaddrinfo", WSAGetLastError());
71 throw system_error("getaddrinfo", gai_strerror(err));
75 SockAddr *resolve(const string &str, Family family)
78 parse_host_serv(str, host, serv);
80 return resolve(host, serv, family);
86 thread.get_notify_pipe().signal_data_available.connect(sigc::mem_fun(this, &Resolver::task_done));
89 void Resolver::use_event_dispatcher(IO::EventDispatcher *ed)
92 event_disp->remove(thread.get_notify_pipe());
95 event_disp->add(thread.get_notify_pipe());
98 unsigned Resolver::resolve(const string &host, const string &serv, Family family)
101 task.tag = next_tag++;
104 task.family = family;
105 thread.add_task(task);
109 unsigned Resolver::resolve(const string &str, Family family)
112 parse_host_serv(str, host, serv);
114 return resolve(host, serv, family);
117 void Resolver::tick()
119 if(IO::poll(thread.get_notify_pipe(), IO::P_INPUT, Time::zero))
123 void Resolver::task_done()
126 thread.get_notify_pipe().read(buf, sizeof(buf));
128 while(Task *task = thread.get_complete_task())
131 signal_address_resolved.emit(task->tag, *task->addr);
134 if(signal_resolve_failed.empty())
136 RefPtr<runtime_error> err = task->error;
138 thread.pop_complete_task();
141 signal_resolve_failed.emit(task->tag, *task->error);
143 thread.pop_complete_task();
148 Resolver::WorkerThread::WorkerThread():
155 Resolver::WorkerThread::~WorkerThread()
162 void Resolver::WorkerThread::add_task(const Task &t)
164 MutexLock lock(queue_mutex);
165 bool was_starved = (queue.empty() || queue.back().is_complete());
171 Resolver::Task *Resolver::WorkerThread::get_complete_task()
173 MutexLock lock(queue_mutex);
174 if(!queue.empty() && queue.front().is_complete())
175 return &queue.front();
180 void Resolver::WorkerThread::pop_complete_task()
182 MutexLock lock(queue_mutex);
183 if(!queue.empty() && queue.front().is_complete())
185 delete queue.front().addr;
186 delete queue.front().error;
191 void Resolver::WorkerThread::main()
202 MutexLock lock(queue_mutex);
203 for(auto i=queue.begin(); (!task && i!=queue.end()); ++i)
204 if(!i->is_complete())
212 SockAddr *addr = Net::resolve(task->host, task->serv, task->family);
214 MutexLock lock(queue_mutex);
218 catch(const runtime_error &e)
220 MutexLock lock(queue_mutex);
221 task->error = new runtime_error(e);