147 lines
3.8 KiB
Go
147 lines
3.8 KiB
Go
// Copyright 2011 Miek Gieben. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// DNS resolver client: see RFC 1035.
|
|
|
|
package dns
|
|
|
|
import (
|
|
"os"
|
|
"net"
|
|
)
|
|
|
|
// Query is used to communicate with the Query* functions.
|
|
type Query struct {
|
|
// The query message.
|
|
Msg *Msg
|
|
// A Conn. Its only required to fill out Conn.RemoteAddr.
|
|
// Optionally you may set Conn.Tsig if TSIG is required.
|
|
// The rest of the structure is filled by the Query functions.
|
|
Conn *Conn
|
|
// Any error when querying is returned in Err. The caller
|
|
// should just set this to nil.
|
|
Err os.Error
|
|
// Query time in here?
|
|
}
|
|
|
|
// QueryUDP handles one query. It reads an incoming request from
|
|
// the in channel. The function f is executed in a seperate
|
|
// goroutine and performs the actual UDP query.
|
|
func QueryUDP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
|
query("udp", in, out, f)
|
|
}
|
|
|
|
// QueryTCP handles one query. It reads an incoming request from
|
|
// the in channel. The function f is executed in a seperate
|
|
// goroutine and performas the actual TCP query.
|
|
func QueryTCP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
|
query("tcp", in, out, f)
|
|
}
|
|
|
|
// helper function.
|
|
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.LocalAddr, q.Conn.RemoteAddr)
|
|
if err != nil {
|
|
out <- Query{Err: err}
|
|
}
|
|
if n == "tcp" {
|
|
q.Conn.SetTCPConn(c.(*net.TCPConn), nil)
|
|
} else {
|
|
q.Conn.SetUDPConn(c.(*net.UDPConn), nil)
|
|
}
|
|
if f == nil {
|
|
go QueryDefault(q.Conn, q.Msg, out)
|
|
} else {
|
|
go f(q.Conn, q.Msg, out)
|
|
}
|
|
}
|
|
}
|
|
panic("not reached")
|
|
}
|
|
|
|
// Default Handler when none is given.
|
|
func QueryDefault(d *Conn, m *Msg, q chan Query) {
|
|
buf, ok := m.Pack()
|
|
if !ok {
|
|
q <- Query{nil, d, ErrPack}
|
|
}
|
|
ret, err := d.Exchange(buf, false)
|
|
if err != nil {
|
|
q <- Query{nil, d, err}
|
|
}
|
|
out := new(Msg)
|
|
if ok1 := out.Unpack(ret); !ok1 {
|
|
q <- Query{nil, d, ErrUnpack}
|
|
}
|
|
q <- Query{out, d, nil}
|
|
return
|
|
}
|
|
|
|
// Simple query function that waits for and returns the reply.
|
|
func QuerySimple(d *Conn, m *Msg) (*Msg, os.Error) {
|
|
buf, ok := m.Pack()
|
|
if !ok {
|
|
return nil, ErrPack
|
|
}
|
|
// Dialing should happen in the client
|
|
|
|
ret, err := d.Exchange(buf, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
o := new(Msg)
|
|
if ok := o.Unpack(ret); !ok {
|
|
return nil, ErrUnpack
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
// QueryAndServeTCP listens for incoming requests on channel in and
|
|
// then calls QueryTCP with f to the handle the request.
|
|
// It returns a channel on which the response is returned.
|
|
func QueryAndServeTCP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query {
|
|
out := make(chan Query)
|
|
go QueryTCP(in, out, f)
|
|
return out
|
|
}
|
|
|
|
// QueryAndServeUDP listens for incoming requests on channel in and
|
|
// then calls QueryUDP with f to the handle the request.
|
|
// It returns a channel on which the response is returned.
|
|
func QueryAndServeUDP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query {
|
|
out := make(chan Query)
|
|
go QueryUDP(in, out, f)
|
|
return out
|
|
}
|
|
|
|
/* // alg for querying a list of servers, not sure if we going to keep it
|
|
for i := 0; i < len(res.Servers); i++ {
|
|
var d *Conn
|
|
server := res.Servers[i] + ":" + port
|
|
t := time.Nanoseconds()
|
|
if res.Tcp {
|
|
d, err = Dial("tcp", "", server)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
} else {
|
|
d, err = Dial("udp", "", server)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
}
|
|
inb, err = d.Exchange(sending, false)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
in.Unpack(inb) // Discard error.
|
|
res.Rtt[server] = time.Nanoseconds() - t
|
|
d.Close()
|
|
break
|
|
}
|
|
*/
|