complete rewrite the resolver side

make it mirror the server side and thus
async and concurrent
This commit is contained in:
Miek Gieben 2011-03-28 10:01:10 +02:00
parent b4ee9829bc
commit 135772de9f
6 changed files with 67 additions and 14 deletions

4
TODO
View File

@ -1,12 +1,12 @@
Guidelines for the API: Guidelines for the API:
o symmetrical, client side should be mirrored in the server o symmetrical, client side should be mirrored in the server
o clean, small API o clean, small API
o fast data structures (rb-tree, when they come available) o fast data structures (rb-tree, when they come available)
o api-use should be self documenting o api-use should be self documenting
o multiple queries in api
o make questions fqdns -- add last dot o make questions fqdns -- add last dot
o zone structure -- only as rb-tree o zone structure -- only as rb-tree or other radix tree
o compression (only ownernames?) o compression (only ownernames?)
o Key2DS, also for offline keys -- need to parse them ofcourse o Key2DS, also for offline keys -- need to parse them ofcourse

View File

@ -89,10 +89,10 @@ Flags:
m.MsgHdr.RecursionDesired = *rd m.MsgHdr.RecursionDesired = *rd
m.Question = make([]dns.Question, 1) m.Question = make([]dns.Question, 1)
if *dnssec || *nsid { if *dnssec || *nsid {
opt := new(dns.RR_OPT) opt := new(dns.RR_OPT)
opt.SetDo() opt.SetDo()
opt.SetVersion(0) opt.SetVersion(0)
opt.SetUDPSize(dns.DefaultMsgSize) opt.SetUDPSize(dns.DefaultMsgSize)
if *nsid { if *nsid {
opt.SetNsid("") opt.SetNsid("")
} }
@ -129,7 +129,7 @@ func shortMsg(in *dns.Msg) *dns.Msg {
for i := 0; i < len(in.Extra); i++ { for i := 0; i < len(in.Extra); i++ {
in.Extra[i] = shortRR(in.Extra[i]) in.Extra[i] = shortRR(in.Extra[i])
} }
return in return in
} }
func shortRR(r dns.RR) dns.RR { func shortRR(r dns.RR) dns.RR {
@ -138,8 +138,8 @@ func shortRR(r dns.RR) dns.RR {
t.PublicKey = "( ... )" t.PublicKey = "( ... )"
case *dns.RR_RRSIG: case *dns.RR_RRSIG:
t.Signature = "( ... )" t.Signature = "( ... )"
case *dns.RR_NSEC3: case *dns.RR_NSEC3:
t.Salt = "-" // nobody cares t.Salt = "-" // nobody cares
} }
return r return r
} }

5
dns.go
View File

@ -86,7 +86,11 @@ type Conn struct {
// The remote port number of the connection. // The remote port number of the connection.
Port int Port int
// Remove server (for resolver)
RemoteAddr string
// If TSIG is used, this holds all the information. // If TSIG is used, this holds all the information.
// If unused is must be nil.
Tsig *Tsig Tsig *Tsig
// Timeout in sec before giving up on a connection. // Timeout in sec before giving up on a connection.
@ -366,7 +370,6 @@ func (d *Conn) Exchange(request []byte, nosend bool) (reply []byte, err os.Error
return nil, err return nil, err
} }
} }
// Layer violation to save memory. Its okay then...
reply = d.NewBuffer() reply = d.NewBuffer()
n, err = d.Read(reply) n, err = d.Read(reply)
if err != nil { if err != nil {

1
msg.go
View File

@ -44,6 +44,7 @@ var (
ErrSigGen os.Error = &Error{Error: "bad signature generation"} ErrSigGen os.Error = &Error{Error: "bad signature generation"}
ErrAuth os.Error = &Error{Error: "bad authentication"} ErrAuth os.Error = &Error{Error: "bad authentication"}
ErrXfrSoa os.Error = &Error{Error: "no SOA seen"} ErrXfrSoa os.Error = &Error{Error: "no SOA seen"}
ErrHandle os.Error = &Error{Error: "the handle is nill"}
) )
// A manually-unpacked version of (id, bits). // A manually-unpacked version of (id, bits).

View File

@ -8,9 +8,58 @@ package dns
import ( import (
"os" "os"
"net"
"time" "time"
) )
type Query struct {
Msg *Msg
Conn *Conn
Err os.Error
}
// A query implementation that is asyn. and concurrent. Is also
// completely mirrors the server side implementation
func QueryTCP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
query("tcp", in, out, f)
}
func QueryUDP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
query("udp", in, out, f)
}
func query(n string, in, out chan Query, f func(*Conn, *Msg, chan Query)) {
for {
select {
case q := <-in:
c, err := net.Dial(n, "", q.Conn.RemoteAddr)
if err != nil {
//out <- nil
}
if n == "tcp" {
q.Conn.SetTCPConn(c.(*net.TCPConn), nil)
} else {
q.Conn.SetUDPConn(c.(*net.UDPConn), nil)
}
go f(q.Conn, q.Msg, out)
}
}
panic("not reached")
}
func QueryAndServeTCP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query {
out := make(chan Query)
go QueryTCP(in, out, f)
return out
}
func QueryAndServeUDP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query {
out := make(chan Query)
go QueryUDP(in, out, f)
return out
}
type Resolver struct { type Resolver struct {
Servers []string // servers to use Servers []string // servers to use
Search []string // suffixes to append to local name (not implemented) Search []string // suffixes to append to local name (not implemented)
@ -47,7 +96,7 @@ func (res *Resolver) QueryTsig(q *Msg, tsig *Tsig) (d *Msg, err os.Error) {
} }
for i := 0; i < len(res.Servers); i++ { for i := 0; i < len(res.Servers); i++ {
var d *Conn var d *Conn
server := res.Servers[i] + ":" + port server := res.Servers[i] + ":" + port
t := time.Nanoseconds() t := time.Nanoseconds()
if res.Tcp { if res.Tcp {
@ -68,7 +117,7 @@ func (res *Resolver) QueryTsig(q *Msg, tsig *Tsig) (d *Msg, err os.Error) {
} }
in.Unpack(inb) // Discard error. in.Unpack(inb) // Discard error.
res.Rtt[server] = time.Nanoseconds() - t res.Rtt[server] = time.Nanoseconds() - t
d.Close() d.Close()
break break
} }
if err != nil { if err != nil {
@ -102,7 +151,7 @@ func (res *Resolver) XfrTsig(q *Msg, t *Tsig, m chan Xfr) {
Server: Server:
for i := 0; i < len(res.Servers); i++ { for i := 0; i < len(res.Servers); i++ {
server := res.Servers[i] + ":" + port server := res.Servers[i] + ":" + port
d, err := Dial("tcp", "", server) d, err := Dial("tcp", "", server)
if err != nil { if err != nil {
continue Server continue Server
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// DNS server implementation // DNS server implementation.
package dns package dns
@ -67,7 +67,7 @@ func HandleTCP(l *net.TCPListener, f func(*Conn, *Msg)) os.Error {
// connections. The function f may not be nil. // connections. The function f may not be nil.
func ListenAndServeTCP(addr string, f func(*Conn, *Msg)) os.Error { func ListenAndServeTCP(addr string, f func(*Conn, *Msg)) os.Error {
if f == nil { if f == nil {
return &Error{Error: "The handle function may not be nil"} return ErrHandle
} }
a, err := net.ResolveTCPAddr(addr) a, err := net.ResolveTCPAddr(addr)
if err != nil { if err != nil {