]> git.mxchange.org Git - simgear.git/blob - simgear/io/HostLookup.cxx
Ick, further fixes for Linux/MSVC
[simgear.git] / simgear / io / HostLookup.cxx
1 #include "HostLookup.hxx"
2
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <netdb.h>
6
7 #include <map>
8
9 #include <simgear/threads/SGThread.hxx>
10
11 using std::string;
12
13 namespace simgear
14 {
15
16 class Resolver : public SGThread
17 {
18 public:
19     Resolver()
20     {
21         // take lock when resolver starts,
22         // won't release until it's actually running, and waiting on the
23         // condition. Otherwise we get a race when starting.
24         _lock.lock();
25     }
26     
27         virtual void run()
28         {        
29                 while (true) {
30                         _cond.wait(_lock); // wait until there's something to lookup
31                 
32                 // find the first un-resolved entry in the cache
33                         HostCache::iterator it;
34                         for (it = _cache.begin(); it != _cache.end(); ++it) {
35                                 if (!it->second->resolved()) {
36                                         break;
37                                 }
38                         }
39                         
40                         if (it == _cache.end()) {
41                 continue;
42                         }
43                         
44                         string host = it->first;
45         // don't hold any locks while looking up
46                         _lock.unlock();
47                 
48                 // start the actual lookup - may take a long period of time!
49                 // (eg, one, five or sixty seconds)
50             struct addrinfo hints;
51             bzero(&hints, sizeof(struct addrinfo));
52             hints.ai_family = PF_UNSPEC;
53             
54             struct addrinfo *results;
55             
56                         int result = getaddrinfo(host.c_str(), NULL, &hints, &results);
57                         _lock.lock(); // take the lock back before going any further
58                                     
59                         if (result == 0) {
60                             _cache[host]->resolve(IPAddress(results->ai_addr, results->ai_addrlen));
61                 freeaddrinfo(results);                
62                         } else if (result == EAGAIN) {
63                             
64                         } else {
65                 const char* errMsg = gai_strerror(result);
66                                 // bad lookup, remove from cache? or set as failed?
67                 _cache[host]->fail();
68                         }
69                 } // of thread loop
70                 
71                 _lock.unlock();
72         }
73         
74         void addLookup(HostLookup* l)
75         {
76                 _lock.lock();
77                 _cache[l->host()] = l;
78                 _cond.signal();
79                 _lock.unlock();
80         }
81         
82         HostLookup* lookup(const string& host)
83         {
84                 _lock.lock();
85                 HostCache::iterator it = _cache.find(host);
86                 HostLookup* result = it->second;
87                 _lock.unlock();
88                 return result;
89         }
90 private:
91         SGMutex _lock;
92         SGPthreadCond _cond;
93         
94         typedef std::map<string, HostLookup*> HostCache;
95         HostCache _cache;
96 };
97
98 Resolver* static_resolve = NULL;
99
100 HostLookup* HostLookup::lookup(const string& host)
101 {
102     if (!static_resolve) {
103         static_resolve = new Resolver;
104         static_resolve->start();
105     }
106     
107         HostLookup* l = static_resolve->lookup(host);
108         if (l) {
109                 return l;
110         }
111         
112         l = new HostLookup(host);
113     SGReferenced::get(l);
114         static_resolve->addLookup(l);
115         return l;
116 }
117
118 HostLookup::HostLookup(const std::string& h) :
119         _host(h),
120         _resolved(false)
121 {
122 }
123
124 void HostLookup::resolve(const IPAddress& addr)
125 {    
126     _failed = false;
127     _address = addr;
128     _age.stamp();
129     _resolved = true;
130 }
131
132 void HostLookup::fail()
133 {
134     _failed = true;
135     _resolved = false;
136     _age.stamp();
137 }
138
139 } // of namespace