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);
88 thread.get_notify_pipe().signal_data_available.connect(sigc::mem_fun(this, &Resolver::task_done));
91 void Resolver::use_event_dispatcher(IO::EventDispatcher *ed)
94 event_disp->remove(thread.get_notify_pipe());
97 event_disp->add(thread.get_notify_pipe());
100 unsigned Resolver::resolve(const string &host, const string &serv, Family family)
103 task.tag = next_tag++;
106 task.family = family;
107 thread.add_task(task);
111 unsigned Resolver::resolve(const string &str, Family family)
114 parse_host_serv(str, host, serv);
116 return resolve(host, serv, family);
119 void Resolver::tick()
121 if(IO::poll(thread.get_notify_pipe(), IO::P_INPUT, Time::zero))
125 void Resolver::task_done()
128 thread.get_notify_pipe().read(buf, sizeof(buf));
130 while(Task *task = thread.get_complete_task())
133 signal_address_resolved.emit(task->tag, *task->addr);
135 signal_resolve_failed.emit(task->tag, *task->error);
136 thread.pop_complete_task();
141 Resolver::Task::Task():
149 Resolver::WorkerThread::WorkerThread():
157 Resolver::WorkerThread::~WorkerThread()
164 void Resolver::WorkerThread::add_task(const Task &t)
166 MutexLock lock(queue_mutex);
167 bool was_starved = (queue.empty() || queue.back().is_complete());
173 Resolver::Task *Resolver::WorkerThread::get_complete_task()
175 MutexLock lock(queue_mutex);
176 if(!queue.empty() && queue.front().is_complete())
177 return &queue.front();
182 void Resolver::WorkerThread::pop_complete_task()
184 MutexLock lock(queue_mutex);
185 if(!queue.empty() && queue.front().is_complete())
187 delete queue.front().addr;
188 delete queue.front().error;
193 void Resolver::WorkerThread::main()
204 MutexLock lock(queue_mutex);
205 for(list<Task>::iterator i=queue.begin(); (!task && i!=queue.end()); ++i)
206 if(!i->is_complete())
214 SockAddr *addr = Net::resolve(task->host, task->serv, task->family);
216 MutexLock lock(queue_mutex);
220 catch(const runtime_error &e)
222 MutexLock lock(queue_mutex);
223 task->error = new runtime_error(e);