dns/resolver.go
2011-03-30 14:54:43 +02:00

94 lines
2.1 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"
)
// Request a query by sending to this channel.
var QueryRequest chan Query // *Query
// Listen for replies on this channel.
var QueryReply chan Query
// Query is used to communicate with the Query* functions.
type Query struct {
// The query message.
Query *Msg
// The reply message.
Reply *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
//
Err os.Error
}
// Initialize the QueryRequest and QueryReply
// channels.
func QueryInitChannels() {
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.
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.
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")
}
// Simple query function that waits for and returns the reply.
func QuerySimple(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
}