108 lines
2.8 KiB
Go
108 lines
2.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"
|
|
)
|
|
|
|
// These channels are global so that all parts of the application
|
|
// can send queries (or even pick them up).
|
|
var (
|
|
// Request an async query by sending to this channel.
|
|
QueryRequest chan *Query
|
|
// Listen for replies to previously sent queries on this channel.
|
|
QueryReply chan *Query
|
|
)
|
|
|
|
// Query is used to communicate with the Query* functions.
|
|
type Query struct {
|
|
// The query message which is to be send.
|
|
Query *Msg
|
|
|
|
// Any reply message that came back from the wire.
|
|
Reply *Msg
|
|
|
|
// It is 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
|
|
|
|
// If there are any errors there Err is not nil
|
|
Err os.Error
|
|
}
|
|
|
|
// Initialize the QueryRequest and QueryReply channels. This
|
|
// is only required when async. queries are wanted.
|
|
func InitQueryChannels() {
|
|
QueryRequest = make(chan *Query)
|
|
QueryReply = make(chan *Query)
|
|
}
|
|
|
|
// QueryAndServeTCP listens for incoming requests on channel in and then calls f.
|
|
// The function f is executed in a seperate goroutine and performs the actual
|
|
// TCP query and should return the result on the QueryReply channel.
|
|
func QueryAndServeTCP(f func(*Conn, *Msg)) os.Error {
|
|
if f == nil {
|
|
return ErrHandle
|
|
}
|
|
if QueryReply == nil || QueryRequest == nil {
|
|
return ErrChan
|
|
}
|
|
query("tcp", f)
|
|
return nil
|
|
}
|
|
|
|
// QueryAndServeUDP listens for incoming requests on channel in and then calls f.
|
|
// The function f is executed in a seperate goroutine and performs the actual
|
|
// UDP query and should return the result on the QueryReply channel.
|
|
func QueryAndServeUDP(f func(*Conn, *Msg)) os.Error {
|
|
if f == nil {
|
|
return ErrHandle
|
|
}
|
|
if QueryReply == nil || QueryRequest == nil {
|
|
return ErrChan
|
|
}
|
|
query("udp", f)
|
|
return nil
|
|
}
|
|
|
|
func query(n string, f func(*Conn, *Msg)) {
|
|
for {
|
|
select {
|
|
case q := <-QueryRequest:
|
|
err := q.Conn.Dial(n)
|
|
if err != nil {
|
|
QueryReply <- &Query{Err: err}
|
|
}
|
|
go f(q.Conn, q.Query)
|
|
}
|
|
}
|
|
panic("not reached")
|
|
}
|
|
|
|
// SimpleQuery performs a query and waits for the reply before
|
|
// returning.
|
|
func SimpleQuery(n string, d *Conn, m *Msg) (*Msg, os.Error) {
|
|
err := d.Dial(n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
o, err := d.ExchangeMsg(m, false)
|
|
d.Close()
|
|
return o, err
|
|
}
|
|
|
|
// HandleQuery can be used as a default query handler. It
|
|
// fires of the querie, wait for a response and sends the
|
|
// response back on the QueryReply channel. HandleQuery closes d.
|
|
func HandleQuery(d *Conn, i *Msg) {
|
|
o, e := d.ExchangeMsg(i, false)
|
|
QueryReply <- &Query{Query: i, Reply: o, Conn: d, Err: e}
|
|
d.Close()
|
|
}
|