pike.git
/
lib
/
modules
/
Protocols.pmod
/
DNS.pmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1848:
} if (!m) { return 0; } array a = filter(m->an, `[], "mx"); array(string) b = column( a, "mx"); sort( column( a, "preference"), b); return b; }
-
}
+
-
#define
REMOVE_DELAY
120
-
#define GIVE_UP_DELAY (RETRIES * RETRY_DELAY + REMOVE_DELAY)*2
-
-
//
FIXME: Randomized source port
!
-
//! Asynchronous DNS client.
-
class async_client
-
{
-
inherit client;
-
inherit Stdio.UDP : udp;
-
async_client next_client;
-
+
//!
class Request(string domain, string req, function(string,mapping,mixed...:void) callback, array(mixed) args) { int retries; int timestamp = time();
-
+
//! Cancel the current request.
void cancel() { remove(this_object()); } }; mapping requests=([]);
-
protected
private
void remove(object(Request) r)
+
protected void remove(object(Request) r)
{ if(!r) return; sscanf(r->req,"%2c",int id); m_delete(requests,id);
-
r->callback(r->domain,0,@r->args);
+
r->callback
&& r->callback
(r->domain,0,@r->args);
destruct(r); }
-
+
}
-
+
#define REMOVE_DELAY 120
+
#define GIVE_UP_DELAY (RETRIES * RETRY_DELAY + REMOVE_DELAY)*2
+
+
// FIXME: Randomized source port!
+
//! Asynchronous DNS client.
+
class async_client
+
{
+
inherit client;
+
inherit Stdio.UDP : udp;
+
async_client next_client;
+
void retry(object(Request) r, void|int nsno) { if(!r) return; if (nsno >= sizeof(nameservers)) { if(r->retries++ > RETRIES) { call_out(remove,REMOVE_DELAY,r); return; } else { nsno = 0; } } send(nameservers[nsno],53,r->req); call_out(retry,RETRY_DELAY,r,nsno+1); }
-
+
//! Enqueue a new raw DNS request.
//!
-
void
do_query(string domain, int cl, int type,
+
//!
@returns
+
//! Returns a @[Request] object.
+
//!
+
//! @note
+
//! Pike versions prior to 8.0 did not return the @[Request] object.
+
Request
do_query(string domain, int cl, int type,
function(string,mapping,mixed...:void) callback, mixed ... args) { for(int e=next_client ? 100 : 256;e>=0;e--) { int lid = random(65536); if(!catch { requests[lid]++; }) { string req=low_mkquery(lid,domain,cl,type); object r = Request(domain, req, callback, args); requests[lid]=r; udp::send(nameservers[0],53,r->req); call_out(retry,RETRY_DELAY,r,1);
-
return;
+
return
r
;
} } /* We failed miserably to find a request id to use, * so we create a second UDP port to be able to have more * requests 'in the air'. /Hubbe */ if(!next_client) next_client=this_program(nameservers,domains);
-
next_client->do_query(domain, cl, type, callback, @args);
+
return
next_client->do_query(domain, cl, type, callback, @args);
} protected private void rec_data(mapping m) { mixed err; if (err = catch { if(m->port != 53 || !has_value(nameservers, m->ip)) return; sscanf(m->data,"%2c",int id); object r=requests[id]; if(!r) {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1953:
} m_delete(requests,id); r->callback(r->domain,decode_res(m->data),@r->args); destruct(r); }) { werror("DNS: Failed to read UDP packet. Connection refused?\n%s\n", describe_backtrace(err)); } }
-
protected private
void
generic_get(string d,
+
protected private
Request
generic_get(string d,
mapping answer, int multi, int all, int type, string field, string domain, function callback, mixed ... args) { if(!answer || !answer->an || !sizeof(answer->an)) { if(multi == -1 || multi >= sizeof(domains)) { // Either a request without multi (ip, or FQDN) or we have tried all // domains. callback(domain,0,@args); } else { // Multiple domain request. Try the next one...
-
do_query(domain+"."+domains[multi], C_IN, type,
+
return
do_query(domain+"."+domains[multi], C_IN, type,
generic_get, ++multi, all, type, field, domain, callback, @args); } } else { if (all) { callback(domain, answer->an, @args); } else { foreach(answer->an, array an) if(an[field]) { callback(domain, an[field], @args);
-
return;
+
return
UNDEFINED
;
} callback(domain,0,@args);
-
return;
+
} }
-
+
return UNDEFINED;
} //!
-
void
host_to_ip(string host, function callback, mixed ... args)
+
Request
host_to_ip(string host, function callback, mixed ... args)
{ if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) {
-
do_query(host, C_IN, T_A,
+
return
do_query(host, C_IN, T_A,
generic_get, 0, 0, T_A, "a", host, callback, @args ); } else {
-
do_query(host, C_IN, T_A,
+
return
do_query(host, C_IN, T_A,
generic_get, -1, 0, T_A, "a", host, callback, @args); } } //!
-
void
ip_to_host(string ip, function callback, mixed ... args)
+
Request
ip_to_host(string ip, function callback, mixed ... args)
{
-
do_query(arpa_from_ip(ip), C_IN, T_PTR,
+
return
do_query(arpa_from_ip(ip), C_IN, T_PTR,
generic_get, -1, 0, T_PTR, "ptr", ip, callback, @args); } //!
-
void
get_mx_all(string host, function callback, mixed ... args)
+
Request
get_mx_all(string host, function callback, mixed ... args)
{ if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) {
-
do_query(host, C_IN, T_MX,
+
return
do_query(host, C_IN, T_MX,
generic_get, 0, 1, T_MX, "mx", host, callback, @args); } else {
-
do_query(host, C_IN, T_MX,
+
return
do_query(host, C_IN, T_MX,
generic_get, -1, 1, T_MX, "mx", host, callback, @args); } } //!
-
void
get_mx(string host, function callback, mixed ... args)
+
Request
get_mx(string host, function callback, mixed ... args)
{
-
get_mx_all(host,
+
return
get_mx_all(host,
lambda(string domain, array(mapping) mx, function callback, mixed ... args) { array a; if (mx) { a = column(mx, "mx"); sort(column(mx, "preference"), a); } callback(a, @args); }, callback, @args); }
pike.git/lib/modules/Protocols.pmod/DNS.pmod:2121:
return 0; } } // FIXME: Reuse sockets? Acknowledge RETRIES? //! Asynchronous DNS client using TCP class async_tcp_client { inherit async_client;
-
class Request(string domain, string req,
+
//!
+
class Request
+
{
+
inherit ::this_program;
+
+
protected Stdio.File sock;
+
protected string writebuf="",readbuf="";
+
+
protected void create
(string domain, string req,
function(string,mapping,mixed...:void) callback, array(mixed) args) {
-
Stdio.File
sock;
-
string writebuf="",readbuf="";
-
-
void
create(
)
-
{
+
::create(domain,
req,
callback
,
args
)
;
sock=Stdio.File(); sock->async_connect(nameservers[0], 53, connectedcb); }
-
void
connectedcb
(
int ok
)
+
protected
void
close
()
{
-
+
sock && sock->close();
+
sock = UNDEFINED;
+
}
+
+
protected void connectedcb(int ok)
+
{
if (!ok) {callback(domain, 0, @args); return;} sock->set_nonblocking(readcb, writecb, closecb); writebuf=sprintf("%2H",req); writecb(); }
-
void readcb(mixed id,string data)
+
protected
void readcb(mixed id,string data)
{ readbuf+=data; if (sscanf(readbuf,"%2H",string ret)) { if (callback) callback(domain, decode_res(ret), @args); callback=0;
-
sock->
close();
+
close();
} }
-
void writecb()
+
protected
void writecb()
{ if (writebuf!="") writebuf=writebuf[sock->write(writebuf)..]; }
-
void closecb()
+
protected
void closecb()
{
-
sock->close
();
-
if (callback) callback(domain, 0, @args);
-
callback=0;
+
cancel
();
}
-
+
+
void cancel()
+
{
+
close();
+
::cancel();
}
-
+
}
//!
-
void
do_query(string domain, int cl, int type,
+
Request
do_query(string domain, int cl, int type,
function(string,mapping,mixed...:void) callback, mixed ... args) { string req=low_mkquery(random(65536),domain,cl,type);
-
Request(domain, req, callback, args);
+
return
Request(domain, req, callback, args);
} } //! Both a @[client] and a @[tcp_client]. class dual_client { inherit client : UDP; inherit tcp_client : TCP; //!
pike.git/lib/modules/Protocols.pmod/DNS.pmod:2208:
void check_truncation(string domain, mapping result, int cl, int type, function(string,mapping,mixed...:void) callback, mixed ... args) { if (!result || !result->tc) callback(domain,result,@args); else TCP::do_query(domain,cl,type,callback,@args); } //!
-
void
do_query(string domain, int cl, int type,
+
Request
do_query(string domain, int cl, int type,
function(string,mapping,mixed...:void) callback, mixed ... args) {
-
UDP::do_query(domain,cl,type,check_truncation,cl,type,callback,@args);
+
return
UDP::do_query(domain,cl,type,check_truncation,
+
cl,type,callback,@args);
} void create(mixed ... args) {::create(@args);} } async_client global_async_client; #define GAC(X) \
-
void
async_##X( string host, function callback, mixed ... args ) \
+
async_client.Request
async_##X( string host, function callback, mixed ... args ) \
{ \ if( !global_async_client ) \ global_async_client = async_client(); \
-
global_async_client->X(host,callback,@args);
\
+
return
global_async_client->X(host,callback,@args); \
} //! @ignore GAC(ip_to_host); //! @endignore //! @decl void async_ip_to_host(string ip, function cb, mixed ... cba) //! @ignore GAC(host_to_ip); //! @endignore