pike.git / lib / modules / Protocols.pmod / DNS.pmod

version» Context lines:

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