00001
00002
00003
00004
00005
00006
00007
#include "wvresolver.h"
00008
#include "wvloopback.h"
00009
#include "wvaddr.h"
00010
#include "wvtcp.h"
00011
#include <sys/types.h>
00012
#include <signal.h>
00013
#include <time.h>
00014
00015
#ifdef _WIN32
00016
#define WVRESOLVER_SKIP_FORK
00017
typedef int pid_t;
00018
#define kill(a,b)
00019
#define waitpid(a,b,c) (0)
00020
#define alarm(a)
00021
#else
00022
#include "wvautoconf.h"
00023
#include "wvfork.h"
00024
#include <netdb.h>
00025
#include <sys/wait.h>
00026
#endif
00027
00028
class WvResolverHost
00029 {
00030
public:
00031
WvString name;
00032
WvIPAddr *addr;
00033 WvIPAddrList addrlist;
00034
bool done, negative;
00035 pid_t pid;
00036
WvLoopback *loop;
00037 time_t last_tried;
00038
00039 WvResolverHost(
WvStringParm _name) : name(_name)
00040 { init(); addr = NULL; }
00041 ~WvResolverHost()
00042 {
00043
if (loop)
delete loop;
00044
if (pid && pid != -1)
00045 {
00046 kill(pid, SIGKILL);
00047 waitpid(pid, NULL, 0);
00048 }
00049 }
00050
protected:
00051 WvResolverHost()
00052 { init(); }
00053
void init()
00054 { done = negative =
false;
00055 pid = 0; loop = NULL; last_tried = time(NULL); }
00056 };
00057
00058
class WvResolverAddr :
public WvResolverHost
00059 {
00060
public:
00061 WvResolverAddr(
WvIPAddr *_addr)
00062 { addr = _addr; }
00063 };
00064
00065
00066
int WvResolver::numresolvers = 0;
00067 WvResolverHostDict *WvResolver::hostmap = NULL;
00068 WvResolverAddrDict *WvResolver::addrmap = NULL;
00069
00070
00071
00072
00073 static void namelookup(
const char *name,
WvLoopback *loop)
00074 {
00075
struct hostent *he;
00076
00077
00078 alarm(60);
00079
00080
for (;;)
00081 {
00082 he = gethostbyname(name);
00083
if (he)
00084 {
00085
char **addr = he->h_addr_list;
00086
while (*addr != NULL)
00087 {
00088 loop->
print(
"%s ",
WvIPAddr((
unsigned char *)(*addr)));
00089 addr++;
00090 }
00091 loop->
print(
"\n");
00092 alarm(0);
00093
return;
00094 }
00095
00096
00097
00098
if (h_errno != TRY_AGAIN)
00099 {
00100 alarm(0);
00101
return;
00102 }
00103 }
00104 }
00105
00106
00107 WvResolver::WvResolver()
00108 {
00109 numresolvers++;
00110
if (!hostmap)
00111 hostmap =
new WvResolverHostDict(10);
00112
if (!addrmap)
00113 addrmap =
new WvResolverAddrDict(10);
00114 }
00115
00116
00117 WvResolver::~WvResolver()
00118 {
00119 numresolvers--;
00120
if (numresolvers <= 0 && hostmap && addrmap)
00121 {
00122
delete hostmap;
00123
delete addrmap;
00124 hostmap = NULL;
00125 addrmap = NULL;
00126 }
00127 }
00128
00129
00130
00131
00132 int WvResolver::findaddr(
int msec_timeout,
WvStringParm name,
00133
WvIPAddr const **addr,
00134 WvIPAddrList *addrlist)
00135 {
00136 WvResolverHost *host;
00137 time_t now = time(NULL);
00138
int res = 0;
00139
00140 host = (*hostmap)[name];
00141
00142
if (host)
00143 {
00144
00145
if ((host->done && host->last_tried + 60*5 < now)
00146 || (!host->done && host->last_tried + 60 < now))
00147 {
00148
00149 hostmap->remove(host);
00150 host = NULL;
00151 }
00152
else if (host->done)
00153 {
00154
00155
00156
if (addr)
00157 *addr = host->addr;
00158
if (addrlist)
00159 {
00160 WvIPAddrList::Iter i(host->addrlist);
00161
for (i.rewind(); i.next(); )
00162 {
00163 addrlist->append(i.ptr(),
false);
00164 res++;
00165 }
00166 }
00167
else
00168 res = 1;
00169
return res;
00170 }
00171
else if (host->negative)
00172 {
00173
00174
00175
return 0;
00176 }
00177
00178
00179
00180 }
00181
00182
if (!host)
00183 {
00184
00185
00186 host =
new WvResolverHost(name);
00187 hostmap->add(host,
true);
00188
00189 host->loop =
new WvLoopback();
00190
00191
#ifdef WVRESOLVER_SKIP_FORK
00192
00193
namelookup(name, host->loop);
00194
#else
00195
00196
00197
00198 host->pid =
wvfork(host->loop->getrfd(), host->loop->getwfd());
00199
00200
if (!host->pid)
00201 {
00202
00203 host->loop->noread();
00204
namelookup(name, host->loop);
00205 _exit(1);
00206 }
00207
#endif
00208
00209
00210 host->loop->nowrite();
00211 }
00212
00213
#ifndef WVRESOLVER_SKIP_FORK
00214
00215
00216
00217
do
00218 {
00219
if (waitpid(host->pid, NULL, WNOHANG) == host->pid)
00220 host->pid = 0;
00221
00222
if (!host->loop->select(msec_timeout < 0 ? 100 : msec_timeout,
00223
true,
false))
00224 {
00225
if (host->pid)
00226 {
00227
if (msec_timeout >= 0)
00228
return -1;
00229 }
00230
else
00231 {
00232
00233
delete host->loop;
00234 host->loop = NULL;
00235 host->negative =
true;
00236
return 0;
00237 }
00238 }
00239
else
00240
break;
00241 }
while (host->pid && msec_timeout < 0);
00242
#endif
00243
00244
00245
char *line;
00246
00247
do
00248 {
00249 line = host->loop->getline(-1);
00250 }
while (!line && host->loop->isok());
00251
00252
if (line && line[0] != 0)
00253 {
00254 res = 1;
00255
WvIPAddr *resolvedaddr;
00256
char *p;
00257 p = strtok(line,
" \n");
00258 resolvedaddr =
new WvIPAddr(p);
00259 host->addr = resolvedaddr;
00260 host->addrlist.append(resolvedaddr,
true);
00261
if (addr)
00262 *addr = host->addr;
00263
if (addrlist)
00264 addrlist->append(host->addr,
false);
00265
do
00266 {
00267 p = strtok(NULL,
" \n");
00268
if (p)
00269 {
00270 res++;
00271 resolvedaddr =
new WvIPAddr(p);
00272 host->addrlist.append(resolvedaddr,
true);
00273
if (addrlist)
00274 addrlist->append(resolvedaddr,
false);
00275 }
00276 }
while (p);
00277 host->done =
true;
00278 }
00279
else
00280 host->negative =
true;
00281
00282
if (host->pid && waitpid(host->pid, NULL, 0) == host->pid)
00283 host->pid = 0;
00284
delete host->loop;
00285 host->loop = NULL;
00286
00287
00288
return host->negative ? 0 : res;
00289 }
00290
00291 void WvResolver::clearhost(
WvStringParm hostname)
00292 {
00293 WvResolverHost *host = (*hostmap)[
hostname];
00294
if (host)
00295 hostmap->remove(host);
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 bool WvResolver::pre_select(
WvStringParm hostname,
00308 WvStream::SelectInfo &si)
00309 {
00310 WvResolverHost *host = (*hostmap)[
hostname];
00311
00312
if (host)
00313 {
00314
if (host->loop)
00315
return host->loop->xpre_select(si,
00316 WvStream::SelectRequest(
true,
false,
false));
00317
else
00318
return true;
00319 }
00320
else
00321
return false;
00322 }