<commit_before>package driver

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
)

const (
	//MountTimeout timeout before killing a mount try in seconds
	MountTimeout = 30
)

type gvfsVolume struct {
	url         string
	password    string
	mountpoint  string
	connections int
}

type gvfsDriver struct {
	sync.RWMutex
	root    string
	env     []string
	volumes map[string]*gvfsVolume
}

func newGVfsDriver(root string, dbus string) *gvfsDriver {
	d := &gvfsDriver{
		root:    root,
		env:     make([]string, 1), //os.Environ(), ///TODO maybe not init to empty ?
		volumes: make(map[string]*gvfsVolume),
	}
	if dbus == "" {
		// start needed dbus like (eval `dbus-launch --sh-syntax`) and get env variable
		result, err := exec.Command("dbus-launch", "--sh-syntax").CombinedOutput() //DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbus-JHGXLpeJ6A,guid=25ab632502ebccd43cd403bc58388fab';\n ...
		if err != nil {
			panic(err)
		}
		env := string(result)
		log.Debugf("dbus-launch --sh-syntax -> \n%s", env)
		reDBus := regexp.MustCompile("DBUS_SESSION_BUS_ADDRESS='(.*?)';")
		//rePID := regexp.MustCompile("DBUS_SESSION_BUS_PID=(.*?);")
		matchDBuse := reDBus.FindStringSubmatch(env)
		//matchPID := rePID.FindStringSubmatch(env)
		dbus = matchDBuse[1]
		//TODO plan to kill this add closing ?
	}
	d.env[0] = fmt.Sprintf("DBUS_SESSION_BUS_ADDRESS=%s", dbus)
	err := d.startFuseDeamon()
	if err != nil {
		panic(err) //Something went wrong
	}
	return d
}

func setEnv(cmd string, env []string) *exec.Cmd {
	c := exec.Command("sh", "-c", cmd)
	//c := exec.Command(strings.Split(cmd, " ")) //TODO better
	c.Env = env
	return c
}

// start deamon in context of this gvfs drive with custome env
func (d gvfsDriver) startCmd(cmd string) error {
	log.Debugf(cmd)
	return setEnv(cmd, d.env).Start()
}

// run deamon in context of this gvfs drive with custome env
func (d gvfsDriver) runCmd(cmd string) error {
	log.Debugf(cmd)
	return setEnv(cmd, d.env).Run()
}

func (d gvfsDriver) startFuseDeamon() error {
	//TODO check needed gvfsd + gvfsd-ftp Maybe allready on dbus ?
	// Normaly gvfsd-fuse block such so this like crash but global ?

	fi, err := os.Lstat(d.root)
	if os.IsNotExist(err) {
		if err := os.MkdirAll(d.root, 0755); err != nil {
			return err
		}
	} else if err != nil {
		return err
	}
	if fi != nil && !fi.IsDir() {
		return fmt.Errorf("%v already exist and it's not a directory", d.root)
	}

	err = d.startCmd("/usr/lib/gvfs/gvfsd --no-fuse") //Start global deamon
	if err != nil {
		return err
	}
	///usr/lib/gvfs/gvfsd-fuse /var/lib/docker-volumes/gvfs -f -o big_writes,use_ino,allow_other,default_permissions,auto_cache,umask=0022
	err = d.startCmd(fmt.Sprintf("/usr/lib/gvfs/gvfsd-fuse %s -f -o big_writes,use_ino,allow_other,auto_cache,umask=0022", d.root)) //Start ftp handler
	if err != nil {
		return err
	}
	//TODO try to start other handler
	return nil
}

func urlToMountPoint(root string, urlString string) (string, error) {
	//Done ftp://sapk@10.8.0.7 -> ftp:host=10.8.0.7,user=sapk
	//TODO ftp://sapk@10.8.0.7:42 -> ftp:host=10.8.0.7,user=sapk,port=4242 ???
	//TODO ftp://10.8.0.7 -> ftp:host=10.8.0.7
	//TODO ftp://sapk.fr -> ftp:host=sapk.fr
	//TODO other sheme
	u, err := url.Parse(urlString)
	if err != nil {
		return "", err
	}
	name := u.Scheme + ":host=" + u.Host
	if u.User != nil { //TODO test it
		name += ",user=" + u.User.Username()
	}
	return filepath.Join(root, name), nil
}

func (d gvfsDriver) Create(r volume.Request) volume.Response {
	log.Debugf("Entering Create: name: %s, options %v", r.Name, r.Options)
	d.Lock()
	defer d.Unlock()

	if r.Options == nil || r.Options["url"] == "" {
		return volume.Response{Err: "url option required"}
	}

	m, err := urlToMountPoint(d.root, r.Options["url"])
	if err != nil {
		return volume.Response{Err: err.Error()}
	}
	v := &gvfsVolume{
		url:         r.Options["url"],
		password:    r.Options["password"], //TODO maybe error if not defined
		mountpoint:  m,
		connections: 0,
	}

	d.volumes[r.Name] = v
	log.Debugf("Volume Created: %v", v)
	return volume.Response{}
}

func (d gvfsDriver) Remove(r volume.Request) volume.Response {
	log.Debugf("Entering Remove: name: %s, options %v", r.Name, r.Options)
	d.Lock()
	defer d.Unlock()
	v, ok := d.volumes[r.Name]

	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}
	if v.connections == 0 {
		delete(d.volumes, r.Name)
		return volume.Response{}
	}
	return volume.Response{Err: fmt.Sprintf("volume %s is currently used by a container", r.Name)}
}

func (d gvfsDriver) List(r volume.Request) volume.Response {
	log.Debugf("Entering List: name: %s, options %v", r.Name, r.Options)

	d.Lock()
	defer d.Unlock()

	var vols []*volume.Volume
	for name, v := range d.volumes {
		vols = append(vols, &volume.Volume{Name: name, Mountpoint: v.mountpoint})
	}
	return volume.Response{Volumes: vols}
}

func (d gvfsDriver) Get(r volume.Request) volume.Response {
	log.Debugf("Entering Get: name: %s", r.Name)
	d.Lock()
	defer d.Unlock()

	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}

	return volume.Response{Volume: &volume.Volume{Name: r.Name, Mountpoint: v.mountpoint}}
}

func (d gvfsDriver) Path(r volume.Request) volume.Response {
	log.Debugf("Entering Path: name: %s, options %v", r.Name)

	d.RLock()
	defer d.RUnlock()
	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}
	return volume.Response{Mountpoint: v.mountpoint}
}

func (d gvfsDriver) Mount(r volume.MountRequest) volume.Response {
	//Execute gvfs-mount $params and check before for necessity to create mountpoint
	//TODO manage allready mountpoint allready exist before ? maybe init to +1 ?
	log.Debugf("Entering Mount: %v", r)
	d.Lock()
	defer d.Unlock()

	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}

	if v.connections > 0 {
		v.connections++
		return volume.Response{Mountpoint: v.mountpoint}
	}

	cmd := fmt.Sprintf("gvfs-mount %s", v.url)
	if v.password != "" {
		p := setEnv(cmd, d.env)
		inStd, err := p.StdinPipe()
		if err != nil { //Get a input buffer
			return volume.Response{Err: err.Error()}
		}
		/*
			outStd, err := p.StdoutPipe()
			if err != nil {
				return volume.Response{Err: err.Error()}
			}
			outErr, err := p.StderrPipe()
			if err != nil {
				return volume.Response{Err: err.Error()}
			}
			rOut := bufio.NewReader(outStd)
			rErr := bufio.NewReader(outErr)
			//*/
		//*
		var out bytes.Buffer
		p.Stdout = &out
		var outErr bytes.Buffer
		p.Stderr = &outErr
		//*/

		if err := p.Start(); err != nil {
			return volume.Response{Err: err.Error()}
		}
		inStd.Write([]byte(v.password + "\n")) //Send password to process + Send return line

		// wait or timeout
		donec := make(chan error, 1)
		go func() {
			donec <- p.Wait() //Process finish
		}()
		select {
		case <-donec:
			//sOut := readerToString(rOut)
			//sErr := readerToString(rErr)
			sOut := out.String()
			sErr := out.String()
			log.Debugf("Password send and command %s return", cmd)
			log.Debugf("out : %s", sOut)
			log.Debugf("outErr : %s", sErr)
			//TODO handle erros : mount point allready exist "Error mounting location: Location is already mounted"
			// Error mounting location: Could not connect to 10.8.0.7: No route to host
			/*
				tmp, err := p.CombinedOutput()
				if err != nil {
					return volume.Response{Err: err.Error()}
				}
				if strings.Contains(string(tmp), "Location is already mounted") {
			*/
			if strings.Contains(sOut, "Location is already mounted") || strings.Contains(sErr, "Location is already mounted") {
				log.Debugf("mountpoint '%s' seems to be allready mounted by a other process before this driver, nb connections :%d", v.mountpoint, v.connections)
			}
			break
		case <-time.After(MountTimeout * time.Second):
			//sOut := readerToString(rOut)
			//sErr := readerToString(rErr)
			sOut := out.String()
			sErr := out.String()
			p.Process.Kill()
			log.Debugf("out : %s", sOut)
			log.Debugf("outErr : %s", sErr)
			return volume.Response{Err: fmt.Sprintf("The command %s timeout", cmd)}
		}
	} else {
		if err := d.runCmd(cmd); err != nil {
			return volume.Response{Err: err.Error()}
		}
	}

	return volume.Response{Mountpoint: v.mountpoint}
}

func readerToString(buf io.Reader) string {
	b := new(bytes.Buffer)
	b.ReadFrom(buf)
	return b.String()
}

/*
// Ugly hack, this is bufio.ScanLines with ? added as an other delimiter :D
//http://stackoverflow.com/questions/27322722/interact-with-external-application-from-within-code-golang
func passScanner(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\n'); i >= 0 {
		// We have a full newline-terminated line.
		fmt.Printf("nn\n")
		return i + 1, data[0:i], nil
	}
	if i := bytes.IndexByte(data, ':'); i >= 0 {
		// We have a full ?-terminated line.
		return i + 1, data[0:i], nil
	}
	// If we're at EOF, we have a final, non-terminated line. Return it.
	if atEOF {
		return len(data), data, nil
	}
	// Request more data.
	return 0, nil, nil
}

//TODO
//TODO use channel to analyze string iterative
func read(buf io.Reader, stop chan bool) {
	scanner := bufio.NewScanner(buf)
	//scanner.Split(bufio.ScanLines)
	scanner.Split(passScanner)
	for scanner.Scan() {
		fmt.Println("Performed Scan")
		fmt.Println(scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}
	stop <- true
}
*/
//TODO monitor for unmount to remount ?
func (d gvfsDriver) Unmount(r volume.UnmountRequest) volume.Response {
	//Execute gvfs-mount -u $params
	log.Debugf("Entering Unmount: %v", r)

	d.Lock()
	defer d.Unlock()
	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}
	if v.connections <= 1 {
		cmd := fmt.Sprintf("gvfs-mount -u %s", v.url)
		if err := d.runCmd(cmd); err != nil {
			return volume.Response{Err: err.Error()}
		}
		v.connections = 0
	} else {
		v.connections--
	}

	return volume.Response{}
}

func (d gvfsDriver) Capabilities(r volume.Request) volume.Response {
	log.Debugf("Entering Capabilities: %v", r)
	return volume.Response{
		Capabilities: volume.Capability{
			Scope: "local",
		},
	}
}
<commit_msg>Cleaning<commit_after>package driver

import (
	"bytes"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
)

const (
	//MountTimeout timeout before killing a mount try in seconds
	MountTimeout = 30
)

type gvfsVolume struct {
	url         string
	password    string
	mountpoint  string
	connections int
}

type gvfsDriver struct {
	sync.RWMutex
	root    string
	env     []string
	volumes map[string]*gvfsVolume
}

func newGVfsDriver(root string, dbus string) *gvfsDriver {
	d := &gvfsDriver{
		root:    root,
		env:     make([]string, 1),
		volumes: make(map[string]*gvfsVolume),
	}
	if dbus == "" {
		// start needed dbus like (eval `dbus-launch --sh-syntax`) and get env variable
		result, err := exec.Command("dbus-launch", "--sh-syntax").CombinedOutput() //DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbus-JHGXLpeJ6A,guid=25ab632502ebccd43cd403bc58388fab';\n ...
		if err != nil {
			panic(err)
		}
		env := string(result)
		log.Debugf("dbus-launch --sh-syntax -> \n%s", env)
		reDBus := regexp.MustCompile("DBUS_SESSION_BUS_ADDRESS='(.*?)';")
		//rePID := regexp.MustCompile("DBUS_SESSION_BUS_PID=(.*?);")
		matchDBuse := reDBus.FindStringSubmatch(env)
		//matchPID := rePID.FindStringSubmatch(env)
		dbus = matchDBuse[1]
		//TODO plan to kill this add closing ?
	}
	d.env[0] = fmt.Sprintf("DBUS_SESSION_BUS_ADDRESS=%s", dbus)
	err := d.startFuseDeamon()
	if err != nil {
		panic(err) //Something went wrong
	}
	return d
}

func setEnv(cmd string, env []string) *exec.Cmd {
	c := exec.Command("sh", "-c", cmd)
	//c := exec.Command(strings.Split(cmd, " ")) //TODO better
	c.Env = env
	return c
}

// start deamon in context of this gvfs drive with custome env
func (d gvfsDriver) startCmd(cmd string) error {
	log.Debugf(cmd)
	return setEnv(cmd, d.env).Start()
}

// run deamon in context of this gvfs drive with custome env
func (d gvfsDriver) runCmd(cmd string) error {
	log.Debugf(cmd)
	return setEnv(cmd, d.env).Run()
}

func (d gvfsDriver) startFuseDeamon() error {
	//TODO check needed gvfsd + gvfsd-ftp Maybe allready on dbus ?
	// Normaly gvfsd-fuse block such so this like crash but global ?

	fi, err := os.Lstat(d.root)
	if os.IsNotExist(err) {
		if err := os.MkdirAll(d.root, 0755); err != nil {
			return err
		}
	} else if err != nil {
		return err
	}
	if fi != nil && !fi.IsDir() {
		return fmt.Errorf("%v already exist and it's not a directory", d.root)
	}

	err = d.startCmd("/usr/lib/gvfs/gvfsd --no-fuse") //Start global deamon
	if err != nil {
		return err
	}

	err = d.startCmd(fmt.Sprintf("/usr/lib/gvfs/gvfsd-fuse %s -f -o big_writes,use_ino,allow_other,auto_cache,umask=0022", d.root)) //Start ftp handler
	if err != nil {
		return err
	}
	//TODO try to start other handler
	return nil
}

func urlToMountPoint(root string, urlString string) (string, error) {
	//Done ftp://sapk@10.8.0.7 -> ftp:host=10.8.0.7,user=sapk
	//Done ftp://10.8.0.7 -> ftp:host=10.8.0.7
	//Done ftp://sapk.fr -> ftp:host=sapk.fr
	//TODO ftp://sapk@10.8.0.7:42 -> ftp:host=10.8.0.7,user=sapk,port=4242 ???
	// ftp://10.8.0.7 -> ftp:host=10.8.0.7
	// ftp://sapk.fr -> ftp:host=sapk.fr
	//TODO other sheme
	u, err := url.Parse(urlString)
	if err != nil {
		return "", err
	}
	name := u.Scheme + ":host=" + u.Host
	if u.User != nil { //TODO test it
		name += ",user=" + u.User.Username()
	}
	return filepath.Join(root, name), nil
}

func (d gvfsDriver) Create(r volume.Request) volume.Response {
	log.Debugf("Entering Create: name: %s, options %v", r.Name, r.Options)
	d.Lock()
	defer d.Unlock()

	if r.Options == nil || r.Options["url"] == "" {
		return volume.Response{Err: "url option required"}
	}

	m, err := urlToMountPoint(d.root, r.Options["url"])
	if err != nil {
		return volume.Response{Err: err.Error()}
	}
	v := &gvfsVolume{
		url:         r.Options["url"],
		password:    r.Options["password"],
		mountpoint:  m,
		connections: 0,
	}

	d.volumes[r.Name] = v
	log.Debugf("Volume Created: %v", v)
	return volume.Response{}
}

func (d gvfsDriver) Remove(r volume.Request) volume.Response {
	log.Debugf("Entering Remove: name: %s, options %v", r.Name, r.Options)
	d.Lock()
	defer d.Unlock()
	v, ok := d.volumes[r.Name]

	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}
	if v.connections == 0 {
		delete(d.volumes, r.Name)
		return volume.Response{}
	}
	return volume.Response{Err: fmt.Sprintf("volume %s is currently used by a container", r.Name)}
}

func (d gvfsDriver) List(r volume.Request) volume.Response {
	log.Debugf("Entering List: name: %s, options %v", r.Name, r.Options)

	d.Lock()
	defer d.Unlock()

	var vols []*volume.Volume
	for name, v := range d.volumes {
		vols = append(vols, &volume.Volume{Name: name, Mountpoint: v.mountpoint})
	}
	return volume.Response{Volumes: vols}
}

func (d gvfsDriver) Get(r volume.Request) volume.Response {
	log.Debugf("Entering Get: name: %s", r.Name)
	d.Lock()
	defer d.Unlock()

	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}

	return volume.Response{Volume: &volume.Volume{Name: r.Name, Mountpoint: v.mountpoint}}
}

func (d gvfsDriver) Path(r volume.Request) volume.Response {
	log.Debugf("Entering Path: name: %s, options %v", r.Name)

	d.RLock()
	defer d.RUnlock()
	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}
	return volume.Response{Mountpoint: v.mountpoint}
}

func (d gvfsDriver) Mount(r volume.MountRequest) volume.Response {
	log.Debugf("Entering Mount: %v", r)
	d.Lock()
	defer d.Unlock()

	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}

	if v.connections > 0 {
		v.connections++
		return volume.Response{Mountpoint: v.mountpoint}
	}

	cmd := fmt.Sprintf("gvfs-mount %s", v.url)
	if v.password != "" {
		p := setEnv(cmd, d.env)
		inStd, err := p.StdinPipe()
		if err != nil { //Get a input buffer
			return volume.Response{Err: err.Error()}
		}
		var outStd bytes.Buffer
		p.Stdout = &outStd
		var errStd bytes.Buffer
		p.Stderr = &errStd

		if err := p.Start(); err != nil {
			return volume.Response{Err: err.Error()}
		}
		inStd.Write([]byte(v.password + "\n")) //Send password to process + Send return line

		// wait or timeout
		donec := make(chan error, 1)
		go func() {
			donec <- p.Wait() //Process finish
		}()
		select {
		case <-time.After(MountTimeout * time.Second):
			sOut := outStd.String()
			sErr := errStd.String()
			p.Process.Kill()
			log.Debugf("out : %s", sOut)
			log.Debugf("outErr : %s", sErr)
			return volume.Response{Err: fmt.Sprintf("The command %s timeout", cmd)}
		case <-donec:
			sOut := outStd.String()
			sErr := errStd.String()
			log.Debugf("Password send and command %s return", cmd)
			log.Debugf("out : %s", sOut)
			log.Debugf("outErr : %s", sErr)
			// handle erros like : "Error mounting location: Location is already mounted" or Error mounting location: Could not connect to 10.8.0.7: No route to host
			if strings.Contains(sErr, "Error mounting location") {
				return volume.Response{Err: fmt.Sprintf("Error mounting location : %s", sErr)}
				//log.Debugf("mountpoint '%s' seems to be allready mounted by a other process before this driver, nb connections :%d", v.mountpoint, v.connections)
			}
			break
		}
	} else {
		if err := d.runCmd(cmd); err != nil {
			return volume.Response{Err: err.Error()}
		}
	}

	return volume.Response{Mountpoint: v.mountpoint}
}

//TODO Monitor for unmount to remount ?
func (d gvfsDriver) Unmount(r volume.UnmountRequest) volume.Response {
	//Execute gvfs-mount -u $params
	log.Debugf("Entering Unmount: %v", r)

	d.Lock()
	defer d.Unlock()
	v, ok := d.volumes[r.Name]
	if !ok {
		return volume.Response{Err: fmt.Sprintf("volume %s not found", r.Name)}
	}
	if v.connections <= 1 {
		cmd := fmt.Sprintf("gvfs-mount -u %s", v.url)
		if err := d.runCmd(cmd); err != nil {
			return volume.Response{Err: err.Error()}
		}
		v.connections = 0
	} else {
		v.connections--
	}

	return volume.Response{}
}

func (d gvfsDriver) Capabilities(r volume.Request) volume.Response {
	log.Debugf("Entering Capabilities: %v", r)
	return volume.Response{
		Capabilities: volume.Capability{
			Scope: "local",
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"net"
	"net/url"
	"os"
	"runtime"
	"strings"
	"time"

	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
)

type host struct {
	name     string
	protocol string
	endpoint string
	addrs    []string
	resps    []resp
}

type resp struct {
	id   int
	seq  int
	code int
	sent time.Time
	recv time.Time
	dur  time.Duration
	to   string
	from string
	body string
}

var hosts []host

// readHosts reads in hosts from filename and populates hosts []host.
func readHosts() {
	f, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		hosts = append(hosts, host{name: scanner.Text()})
	}
	if err := scanner.Err(); err != nil {
		log.Printf("error reading hosts from %s:%s\n", filename, err)
	}
}

var filename string

func init() {
	// Check for '-f' flag for host file
	flag.StringVar(&filename, "f", "hosts", "File with hosts and urls to check.")
	flag.Parse()
}

// TODO: parse h.name{}'s for urls, set host.protocol and host.endpoint. net/url.Parse seems like a good fit.
func (h *host) unpackUrls() error {
	var isUrl bool
	// loop over host name
	for i := 0; i < len(h.name)-1; i++ {
		if string(h.name[i]) == ":" {
			isUrl = true
			break
		}
	}
	if isUrl {
		url, err := url.Parse(h.name)
		h.protocol = url.Scheme
		h.endpoint = url.Path
		h.name = url.Host
		return err
	}
	return nil
}

func (h *host) htoi() error {
	if len(h.addrs) == 0 {
		addrs, err := net.LookupHost(h.name)
		for _, i := range addrs {
			// Skip if address is ipv6.
			if strings.Contains(i, ":") {
				continue
			}
			h.addrs = append(h.addrs, i)
		}
		return err
	}
	return nil
}

func (h *host) ping() {
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		log.Println("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		log.Println("not supported on", runtime.GOOS)
		return
	}

	c, err := icmp.ListenPacket("udp4", "0.0.0.0")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	s := fmt.Sprintf("Ranger-Chooch-%s", h.name)
	var to net.IP
	var from string
	var sent, recv time.Time

	// TODO: icmp echo forever
	for i := 0; i < 1; i++ {
		wm := icmp.Message{
			Type: ipv4.ICMPTypeEcho, Code: 0,
			/* Using ID was from the example from golang.org, and /sbin/ping uses its PID as ICMP's ID.
			 * Maybe there's a reason for this, and we should keep ID as our PID.
			 */
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: i & 0xffff,
				Data: []byte(s),
			},
		}
		wb, err := wm.Marshal(nil)
		if err != nil {
			log.Fatal(err)
		}

		// Cowardly taking the first address.
		to = net.ParseIP(h.addrs[0])

		if _, err := c.WriteTo(wb, &net.UDPAddr{IP: to}); err != nil {
			log.Fatal(err)
		}
		sent = time.Now()
	}

	rb := make([]byte, 1500)
	// TODO: icmp echoreply forever
	for i := 0; i < 1; i++ {
		n, peer, err := c.ReadFrom(rb)
		if err != nil {
			log.Fatal(err)
		}
		recv = time.Now()
		rm, err := icmp.ParseMessage(1, rb[:n])
		if err != nil {
			log.Fatal(err)
		}

		from, _, _ = net.SplitHostPort(peer.String())
		if h.addrs[0] != from {
			log.Printf("got echo reply from %s; want %s", from, to)
		}
		if rm.Type != ipv4.ICMPTypeEchoReply {
			log.Printf("received something other than ping: %d", rm.Type)
			continue
		}

		body := string(rm.Body.(*icmp.Echo).Data)
		if s != body {
			log.Printf("got echo reply body %s; want %s", body, s)
		}
		seq := rm.Body.(*icmp.Echo).Seq
		id := rm.Body.(*icmp.Echo).ID
		dur := sent.Sub(recv)
		h.addResp(id, seq, rm.Code, sent, recv, dur, to.String(), from, body)
		time.Sleep(time.Second)

	}
}

func (h *host) addResp(id, seq, code int, sent, recv time.Time, dur time.Duration, to, from, body string) {
	r := resp{
		id:   id,
		seq:  seq,
		code: code,
		sent: sent,
		recv: recv,
		dur:  dur,
		to:   to,
		from: from,
		body: body,
	}
	h.resps = append(h.resps, r)
}

func main() {
	// if an entry is a url, send a GET request
	// if an entry is a hostname, send an ICMP ping
}
<commit_msg>Replace completed TODO with doc comment<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"net"
	"net/url"
	"os"
	"runtime"
	"strings"
	"time"

	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
)

type host struct {
	name     string
	protocol string
	endpoint string
	addrs    []string
	resps    []resp
}

type resp struct {
	id   int
	seq  int
	code int
	sent time.Time
	recv time.Time
	dur  time.Duration
	to   string
	from string
	body string
}

var hosts []host

// readHosts reads in hosts from filename and populates hosts []host.
func readHosts() {
	f, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		hosts = append(hosts, host{name: scanner.Text()})
	}
	if err := scanner.Err(); err != nil {
		log.Printf("error reading hosts from %s:%s\n", filename, err)
	}
}

var filename string

func init() {
	// Check for '-f' flag for host file
	flag.StringVar(&filename, "f", "hosts", "File with hosts and urls to check.")
	flag.Parse()
}

// unpackURLs parses h.name{}'s for urls, and sets h.protocol h.endpoint.
func (h *host) unpackUrls() error {
	var isUrl bool
	// loop over host name
	for i := 0; i < len(h.name)-1; i++ {
		if string(h.name[i]) == ":" {
			isUrl = true
			break
		}
	}
	if isUrl {
		url, err := url.Parse(h.name)
		h.protocol = url.Scheme
		h.endpoint = url.Path
		h.name = url.Host
		return err
	}
	return nil
}

func (h *host) htoi() error {
	if len(h.addrs) == 0 {
		addrs, err := net.LookupHost(h.name)
		for _, i := range addrs {
			// Skip if address is ipv6.
			if strings.Contains(i, ":") {
				continue
			}
			h.addrs = append(h.addrs, i)
		}
		return err
	}
	return nil
}

func (h *host) ping() {
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		log.Println("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		log.Println("not supported on", runtime.GOOS)
		return
	}

	c, err := icmp.ListenPacket("udp4", "0.0.0.0")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	s := fmt.Sprintf("Ranger-Chooch-%s", h.name)
	var to net.IP
	var from string
	var sent, recv time.Time

	// TODO: icmp echo forever
	for i := 0; i < 1; i++ {
		wm := icmp.Message{
			Type: ipv4.ICMPTypeEcho, Code: 0,
			/* Using ID was from the example from golang.org, and /sbin/ping uses its PID as ICMP's ID.
			 * Maybe there's a reason for this, and we should keep ID as our PID.
			 */
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: i & 0xffff,
				Data: []byte(s),
			},
		}
		wb, err := wm.Marshal(nil)
		if err != nil {
			log.Fatal(err)
		}

		// Cowardly taking the first address.
		to = net.ParseIP(h.addrs[0])

		if _, err := c.WriteTo(wb, &net.UDPAddr{IP: to}); err != nil {
			log.Fatal(err)
		}
		sent = time.Now()
	}

	rb := make([]byte, 1500)
	// TODO: icmp echoreply forever
	for i := 0; i < 1; i++ {
		n, peer, err := c.ReadFrom(rb)
		if err != nil {
			log.Fatal(err)
		}
		recv = time.Now()
		rm, err := icmp.ParseMessage(1, rb[:n])
		if err != nil {
			log.Fatal(err)
		}

		from, _, _ = net.SplitHostPort(peer.String())
		if h.addrs[0] != from {
			log.Printf("got echo reply from %s; want %s", from, to)
		}
		if rm.Type != ipv4.ICMPTypeEchoReply {
			log.Printf("received something other than ping: %d", rm.Type)
			continue
		}

		body := string(rm.Body.(*icmp.Echo).Data)
		if s != body {
			log.Printf("got echo reply body %s; want %s", body, s)
		}
		seq := rm.Body.(*icmp.Echo).Seq
		id := rm.Body.(*icmp.Echo).ID
		dur := sent.Sub(recv)
		h.addResp(id, seq, rm.Code, sent, recv, dur, to.String(), from, body)
		time.Sleep(time.Second)

	}
}

func (h *host) addResp(id, seq, code int, sent, recv time.Time, dur time.Duration, to, from, body string) {
	r := resp{
		id:   id,
		seq:  seq,
		code: code,
		sent: sent,
		recv: recv,
		dur:  dur,
		to:   to,
		from: from,
		body: body,
	}
	h.resps = append(h.resps, r)
}

func main() {
	// if an entry is a url, send a GET request
	// if an entry is a hostname, send an ICMP ping
}
<|endoftext|>


<commit_before>package chords

import "strconv"

type Chord struct {
	Name string
	Pos  [][6]int
}

func (c Chord) String() string {
	s := ""

	for i := 5; i >= 0; i-- {
		s += "\n  -"
		for _, pos := range c.Pos {
			note := pos[i]
			if note == -1 {
				s += "-X--"
			} else {
				n := strconv.Itoa(note)
				if len(n) == 1 {
					s += "-" + n + "--"
				} else {
					s += n + "--"
				}
			}
		}
	}

	return s + "\n"
}

func Major7th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "maj7",
		Pos: [][6]int{
			// X R 2 1 2 X
			{-1, index1, index1 + 2, index1 + 1, index1 + 2, -1},
			// X X R 2 2 2
			{-1, -1, index2, index2 + 2, index2 + 2, index2 + 2},
			// R X 1 1 0 X
			{index0, -1, index0 + 1, index0 + 1, index0, -1},
			// X R X 1 2 0
			{-1, index1, -1, index1 + 1, index1 + 2, index1},
		},
	}
}

func Major6th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "maj6",
		Pos: [][6]int{
			// X R 2 1 2 X
			{-1, index1, index1 + 2, index1 + 1, index1 + 2, -1},
			// X X R 2 0 2
			{-1, -1, index2, index2 + 2, index2, index2 + 2},
			// R X -1 1 0 X
			{index0, -1, index0 - 1, index0 + 1, index0, -1},
			// X R X -1 2 0
			{-1, index1, -1, index1 - 1, index1 + 2, index1},
		},
	}
}

func Minor7th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min7",
		Pos: [][6]int{
			// X R 2 0 1 X
			{-1, index1, index1 + 2, index1, index1 + 1, index1},
			// X X R 2 1 1
			{-1, -1, index2, index2 + 2, index2 + 1, index2 + 1},
			// R X 0 0 0 X
			{index0, -1, index0, index0, index0, -1},
			// X R X 0 1 0
			{-1, index1, -1, index1, index1 + 1, index1},
		},
	}
}

func Minor6th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min6",
		Pos: [][6]int{
			// X R 2 -1 1 X
			{-1, index1, index1 + 2, index1 - 1, index1 + 1, -1},
			// X X R 2 0 1
			{-1, -1, index2, index2 + 2, index2, index2 + 1},
			// R X -1 0 0 X
			{index0, -1, index0 - 1, index0, index0, -1},
			// X R X -1 1 0
			{-1, index1, -1, index1 - 1, index1 + 1, index1},
		},
	}
}

func Minor9th(root Note) Chord {
	index1, index2 := fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min9",
		Pos: [][6]int{
			// X R -2 0 0 X
			{-1, index1, index1 - 2, index1, index1, -1},
			// X X R -2 1 0
			{-1, -1, index2, index2 - 2, index2 + 1, index2},
		},
	}
}

func Minor11th(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "min11",
		Pos: [][6]int{
			// R X 0 0 -2 X
			{index0, -1, index0, index0, index0 - 2, -1},
			// X R X 0 1 -2
			{-1, index1, -1, index1, index1 + 1, index1 - 2},
		},
	}
}

func Dominant7th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "7",
		Pos: [][6]int{
			// X R 2 0 2 X
			{-1, index1, index1 + 2, index1, index1 + 2, -1},
			// X X R 2 1 2
			{-1, -1, index2, index2 + 2, index2 + 1, index2 + 2},
			// R X 0 1 0 X
			{index0, -1, index0, index0 + 1, index0, -1},
			// X R X 0 2 0
			{-1, index1, -1, index1, index1 + 2, index1},
		},
	}
}

func Dominant9th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "9",
		Pos: [][6]int{
			// X R -1 0 0 X
			{-1, index1, index1 - 1, index1, index1, -1},
			// X X R -1 1 0
			{-1, -1, index2, index2 - 1, index2 + 1, index2},
			// R X 0 -1 -3 X
			{index0, -1, index0, index0 - 1, index0 - 3, -1},
			// X R X 0 0 -3
			{-1, index1, -1, index1, index1, index1 - 3},
		},
	}
}

func Dominant13th(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "13",
		Pos: [][6]int{
			// X R -1 0 0 2
			{-1, index1, index1 - 1, index1, index1, index1 + 2},
			// X R X 0 2 2
			{-1, index1, -1, index1, index1 + 2, index1 + 2},
			// R X 0 1 2 X
			{index0, -1, index0, index0 + 1, index0 + 2, -1},
		},
	}
}

func Minor7thFlat5(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min7(b5)",
		Pos: [][6]int{
			// X R 1 0 1 0 X
			{-1, index1, index1 + 1, index1, index1 + 1, -1},
			// X X R 1 1 1 1
			{-1, -1, index2, index2 + 1, index2 + 1, index2 + 1},
			// R X 0 0 -1 X
			{index0, -1, index0, index0, index0 - 1, -1},
			// X R X 0 1 -1
			{-1, index1, -1, index1, index1 + 1, index1 - 1},
		},
	}
}

var Variants = []func(Note) Chord{
	Major7th,
	Major6th,
	Minor7th,
	Minor6th,
	Minor9th,
	Minor11th,
	Dominant7th,
	Dominant9th,
	Dominant13th,
	Minor7thFlat5,
}
<commit_msg>Add more chords<commit_after>package chords

import "strconv"

type Chord struct {
	Name string
	Pos  [][6]int
}

func (c Chord) String() string {
	s := ""

	for i := 5; i >= 0; i-- {
		s += "\n  -"
		for _, pos := range c.Pos {
			note := pos[i]
			if note == -1 {
				s += "-X--"
			} else {
				n := strconv.Itoa(note)
				if len(n) == 1 {
					s += "-" + n + "--"
				} else {
					s += n + "--"
				}
			}
		}
	}

	return s + "\n"
}

func Major7th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "maj7",
		Pos: [][6]int{
			// X R 2 1 2 X
			{-1, index1, index1 + 2, index1 + 1, index1 + 2, -1},
			// X X R 2 2 2
			{-1, -1, index2, index2 + 2, index2 + 2, index2 + 2},
			// R X 1 1 0 X
			{index0, -1, index0 + 1, index0 + 1, index0, -1},
			// X R X 1 2 0
			{-1, index1, -1, index1 + 1, index1 + 2, index1},
		},
	}
}

func Major6th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "maj6",
		Pos: [][6]int{
			// X R 2 1 2 X
			{-1, index1, index1 + 2, index1 + 1, index1 + 2, -1},
			// X X R 2 0 2
			{-1, -1, index2, index2 + 2, index2, index2 + 2},
			// R X -1 1 0 X
			{index0, -1, index0 - 1, index0 + 1, index0, -1},
			// X R X -1 2 0
			{-1, index1, -1, index1 - 1, index1 + 2, index1},
		},
	}
}

func Minor7th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min7",
		Pos: [][6]int{
			// X R 2 0 1 X
			{-1, index1, index1 + 2, index1, index1 + 1, index1},
			// X X R 2 1 1
			{-1, -1, index2, index2 + 2, index2 + 1, index2 + 1},
			// R X 0 0 0 X
			{index0, -1, index0, index0, index0, -1},
			// X R X 0 1 0
			{-1, index1, -1, index1, index1 + 1, index1},
		},
	}
}

func Minor6th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min6",
		Pos: [][6]int{
			// X R 2 -1 1 X
			{-1, index1, index1 + 2, index1 - 1, index1 + 1, -1},
			// X X R 2 0 1
			{-1, -1, index2, index2 + 2, index2, index2 + 1},
			// R X -1 0 0 X
			{index0, -1, index0 - 1, index0, index0, -1},
			// X R X -1 1 0
			{-1, index1, -1, index1 - 1, index1 + 1, index1},
		},
	}
}

func Minor9th(root Note) Chord {
	index1, index2 := fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min9",
		Pos: [][6]int{
			// X R -2 0 0 X
			{-1, index1, index1 - 2, index1, index1, -1},
			// X X R -2 1 0
			{-1, -1, index2, index2 - 2, index2 + 1, index2},
		},
	}
}

func Minor11th(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "min11",
		Pos: [][6]int{
			// R X 0 0 -2 X
			{index0, -1, index0, index0, index0 - 2, -1},
			// X R X 0 1 -2
			{-1, index1, -1, index1, index1 + 1, index1 - 2},
		},
	}
}

func Dominant7th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "7",
		Pos: [][6]int{
			// X R 2 0 2 X
			{-1, index1, index1 + 2, index1, index1 + 2, -1},
			// X X R 2 1 2
			{-1, -1, index2, index2 + 2, index2 + 1, index2 + 2},
			// R X 0 1 0 X
			{index0, -1, index0, index0 + 1, index0, -1},
			// X R X 0 2 0
			{-1, index1, -1, index1, index1 + 2, index1},
		},
	}
}

func Dominant9th(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "9",
		Pos: [][6]int{
			// X R -1 0 0 X
			{-1, index1, index1 - 1, index1, index1, -1},
			// X X R -1 1 0
			{-1, -1, index2, index2 - 1, index2 + 1, index2},
			// R X 0 -1 -3 X
			{index0, -1, index0, index0 - 1, index0 - 3, -1},
			// X R X 0 0 -3
			{-1, index1, -1, index1, index1, index1 - 3},
		},
	}
}

func Dominant13th(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "13",
		Pos: [][6]int{
			// X R -1 0 0 2
			{-1, index1, index1 - 1, index1, index1, index1 + 2},
			// X R X 0 2 2
			{-1, index1, -1, index1, index1 + 2, index1 + 2},
			// R X 0 1 2 X
			{index0, -1, index0, index0 + 1, index0 + 2, -1},
		},
	}
}

func Minor7thFlat5(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "min7(b5)",
		Pos: [][6]int{
			// X R 1 0 1 0 X
			{-1, index1, index1 + 1, index1, index1 + 1, -1},
			// X X R 1 1 1 1
			{-1, -1, index2, index2 + 1, index2 + 1, index2 + 1},
			// R X 0 0 -1 X
			{index0, -1, index0, index0, index0 - 1, -1},
			// X R X 0 1 -1
			{-1, index1, -1, index1, index1 + 1, index1 - 1},
		},
	}
}

func Diminished(root Note) Chord {
	index0, index1, index2 := fret(root, 0), fret(root, 1), fret(root, 2)

	return Chord{
		Name: string(root) + "dim7",
		Pos: [][6]int{
			// X R 1 -1 1 X
			{-1, index1, index1 + 1, index1 - 1, index1 + 1, -1},
			// X X R 1 0 1
			{-1, -1, index2, index2 + 1, index2, index2 + 1},
			// R X -1 0 -1 X
			{index0, -1, index0 - 1, index0, index0 - 1, -1},
			// X R X -1 1 -1
			{-1, index1, -1, index1 - 1, index1 + 1, index1 - 1},
		},
	}
}

func Dominant7thFlat5(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7(b5)",
		Pos: [][6]int{
			// R X 0 1 -1 X
			{index0, -1, index0, index0 + 1, index0 - 1, -1},
			// X R X 0 2 -1
			{-1, index1, -1, index1, index1 + 2, index1 - 1},
		},
	}
}

func Dominant7thSharp9(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7(#9)",
		Pos: [][6]int{
			// RX X 0 1 0 3
			{-1, -1, index0, index0 + 1, index0, index0 + 3},
			// X R -1 0 1 X
			{-1, index1, index1 - 1, index1, index1 + 1, -1},
		},
	}
}

func Dominant7thFlat13(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7(b13)",
		Pos: [][6]int{
			// R X 0 1 1 X
			{index0, -1, index0, index0 + 1, index0 + 1, -1},
			// X R X 0 2 1
			{-1, index1, -1, index1, index1 + 2, index1 + 1},
		},
	}
}

func Dominant7thFlat9Flat13(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7(b9,b13)",
		Pos: [][6]int{
			// R X 0 1 1 1
			{index0, -1, index0, index0 + 1, index0 + 1, index0 + 1},
			// X R -1 0 -1 1
			{-1, index1, index1 - 1, index1, index1 - 1, index1 + 1},
		},
	}
}

func Dominant7thFlat5Flat9(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7b5(b9)",
		Pos: [][6]int{
			// RX X 0 1 -1 1
			{-1, -1, index0, index0 + 1, index0 - 1, index0 + 1},
			// X R -1 0 -1 -1
			{-1, index1, index1 - 1, index1, index1 - 1, index1 - 1},
		},
	}
}

func Dominant7thFlat5Sharp9(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7b5(#9)",
		Pos: [][6]int{
			// RX X 0 1 -1 3
			{-1, -1, index0, index0 + 1, index0 - 1, index0 + 3},
			// X R -1 0 1 -1
			{-1, index1, index1 - 1, index1, index1 + 1, index1 - 1},
		},
	}
}

func Dominant7thSharp5Flat9(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7#5(b9)",
		Pos: [][6]int{
			// RX X 0 1 1 1
			{-1, -1, index0, index0 + 1, index0 + 1, index0 + 1},
			// X R -1 0 -1 1
			{-1, index1, index1 - 1, index1, index1 - 1, index1 + 1},
		},
	}
}

func Dominant7thSharp5Sharp9(root Note) Chord {
	index0, index1 := fret(root, 0), fret(root, 1)

	return Chord{
		Name: string(root) + "7#5(#9)",
		Pos: [][6]int{
			// RX X 0 1 1 3
			{-1, -1, index0, index0 + 1, index0 + 1, index0 + 3},
			// X R -1 0 1 1
			{-1, index1, index1 - 1, index1, index1 + 1, index1 + 1},
		},
	}
}

var Variants = []func(Note) Chord{
	Major7th,
	Major6th,
	Minor7th,
	Minor6th,
	Minor9th,
	Minor11th,
	Dominant7th,
	Dominant9th,
	Dominant13th,
	Minor7thFlat5,
	Diminished,
	Dominant7thFlat5,
	Dominant7thSharp9,
	Dominant7thFlat13,
	Dominant7thFlat9Flat13,
	Dominant7thFlat5Flat9,
	Dominant7thFlat5Sharp9,
	Dominant7thSharp5Flat9,
	Dominant7thSharp5Sharp9,
}
<|endoftext|>


<commit_before>package jwt

import "crypto/subtle"

// For a type to be a Claims object, it must just have a Valid method that determines
// if the token is invalid for any supported reason
type Claims interface {
	Valid() error
}

// Structured version of Claims Section, as referenced at
// https://tools.ietf.org/html/rfc7519#section-4.1
type StandardClaims struct {
	Audience  string `json:"aud,omitempty"`
	ExpiresAt int64  `json:"exp,omitempty"`
	Id        string `json:"jti,omitempty"`
	IssuedAt  int64  `json:"iat,omitempty"`
	Issuer    string `json:"iss,omitempty"`
	NotBefore int64  `json:"nbf,omitempty"`
	Subject   string `json:"sub,omitempty"`
}

// Validates time based claims "exp, iat, nbf".
// There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still
// be considered a valid claim.
func (c StandardClaims) Valid() error {
	vErr := new(ValidationError)
	now := TimeFunc().Unix()

	// The claims below are optional, by default, so if they are set to the
	// default value in Go, let's not fail the verification for them.
	if c.VerifyExpiresAt(now, false) == false {
		vErr.err = "Token is expired"
		vErr.Errors |= ValidationErrorExpired
	}

	if c.VerifyIssuedAt(now, false) == false {
		vErr.err = "Token used before issued, clock skew issue?"
		vErr.Errors |= ValidationErrorIssuedAt
	}

	if c.VerifyNotBefore(now, false) == false {
		vErr.err = "Token is not valid yet"
		vErr.Errors |= ValidationErrorNotValidYet
	}

	if vErr.valid() {
		return nil
	}

	return vErr
}

// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
	return verifyAud(c.Audience, cmp, req)
}

// Compares the exp claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
	return verifyExp(c.ExpiresAt, cmp, req)
}

// Compares the iat claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
	return verifyIat(c.IssuedAt, cmp, req)
}

// Compares the iss claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
	return verifyIss(c.Issuer, cmp, req)
}

// Compares the nbf claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
	return verifyNbf(c.NotBefore, cmp, req)
}

type MapClaim map[string]interface{}

// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyAudience(cmp string, req bool) bool {
	aud, _ := m["aud"].(string)
	return verifyAud(aud, cmp, req)
}

// Compares the exp claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyExpiresAt(cmp int64, req bool) bool {
	exp, _ := m["exp"].(float64)
	return verifyExp(int64(exp), cmp, req)
}

// Compares the iat claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyIssuedAt(cmp int64, req bool) bool {
	iat, _ := m["iat"].(float64)
	return verifyIat(int64(iat), cmp, req)
}

// Compares the iss claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyIssuer(cmp string, req bool) bool {
	iss, _ := m["iss"].(string)
	return verifyIss(iss, cmp, req)
}

// Compares the nbf claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyNotBefore(cmp int64, req bool) bool {
	nbf, _ := m["nbf"].(float64)
	return verifyNbf(int64(nbf), cmp, req)
}

// Validates time based claims "exp, iat, nbf".
// There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still
// be considered a valid claim.
func (m MapClaim) Valid() error {
	vErr := new(ValidationError)
	now := TimeFunc().Unix()

	if m.VerifyExpiresAt(now, false) == false {
		vErr.err = "Token is expired"
		vErr.Errors |= ValidationErrorExpired
	}

	if m.VerifyIssuedAt(now, false) == false {
		vErr.err = "Token used before issued, clock skew issue?"
		vErr.Errors |= ValidationErrorIssuedAt
	}

	if m.VerifyNotBefore(now, false) == false {
		vErr.err = "Token is not valid yet"
		vErr.Errors |= ValidationErrorNotValidYet
	}

	if vErr.valid() {
		return nil
	}

	return vErr
}

func verifyAud(aud string, cmp string, required bool) bool {
	if aud == "" {
		return !required
	}
	if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
		return true
	} else {
		return false
	}
}

func verifyExp(exp int64, now int64, required bool) bool {
	if exp == 0 {
		return !required
	}
	return now <= exp
}

func verifyIat(iat int64, now int64, required bool) bool {
	if iat == 0 {
		return !required
	}
	return now >= iat
}

func verifyIss(iss string, cmp string, required bool) bool {
	if iss == "" {
		return !required
	}
	if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
		return true
	} else {
		return false
	}
}

func verifyNbf(nbf int64, now int64, required bool) bool {
	if nbf == 0 {
		return !required
	}
	return now >= nbf
}
<commit_msg>Adding Leeway.<commit_after>package jwt

import (
	"crypto/subtle"
	"time"
)

// Leeway is the amount of clock skew that is allowed for the verification claims around time
var Leeway = time.Duration(30) * time.Second

// Claims represents what the interface that a object but implement to be a valid set of claims about a JWT
type Claims interface {
	Valid() error
}

// StandardClaims is a structured version of the Claims Section, as referenced at
// https://tools.ietf.org/html/rfc7519#section-4.1
type StandardClaims struct {
	Audience  string `json:"aud,omitempty"`
	ExpiresAt int64  `json:"exp,omitempty"`
	Id        string `json:"jti,omitempty"`
	IssuedAt  int64  `json:"iat,omitempty"`
	Issuer    string `json:"iss,omitempty"`
	NotBefore int64  `json:"nbf,omitempty"`
	Subject   string `json:"sub,omitempty"`
}

// Valid checks the time based claims "exp, iat, nbf".
// It uses the exposed variable Leeway to account for clock-skew, by default 30 seconds of skew is allowed.
// As well, if any of the above claims are missing from the token, it will still be considered a valid claim.
func (c StandardClaims) Valid() error {
	vErr := new(ValidationError)
	now := TimeFunc().Unix()

	// The claims below are optional, by default, so if they are set to the
	// default value in Go, let's not fail the verification for them.
	if c.VerifyExpiresAt(now, false) == false {
		vErr.err = "Token is expired"
		vErr.Errors |= ValidationErrorExpired
	}

	if c.VerifyIssuedAt(now, false) == false {
		vErr.err = "Token used before issued, clock skew issue?"
		vErr.Errors |= ValidationErrorIssuedAt
	}

	if c.VerifyNotBefore(now, false) == false {
		vErr.err = "Token is not valid yet"
		vErr.Errors |= ValidationErrorNotValidYet
	}

	if vErr.valid() {
		return nil
	}

	return vErr
}

// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
	return verifyAud(c.Audience, cmp, req)
}

// Compares the exp claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
	return verifyExp(c.ExpiresAt, cmp, req)
}

// Compares the iat claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
	return verifyIat(c.IssuedAt, cmp, req)
}

// Compares the iss claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
	return verifyIss(c.Issuer, cmp, req)
}

// Compares the nbf claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
	return verifyNbf(c.NotBefore, cmp, req)
}

type MapClaim map[string]interface{}

// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyAudience(cmp string, req bool) bool {
	aud, _ := m["aud"].(string)
	return verifyAud(aud, cmp, req)
}

// Compares the exp claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyExpiresAt(cmp int64, req bool) bool {
	exp, _ := m["exp"].(float64)
	return verifyExp(int64(exp), cmp, req)
}

// Compares the iat claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyIssuedAt(cmp int64, req bool) bool {
	iat, _ := m["iat"].(float64)
	return verifyIat(int64(iat), cmp, req)
}

// Compares the iss claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyIssuer(cmp string, req bool) bool {
	iss, _ := m["iss"].(string)
	return verifyIss(iss, cmp, req)
}

// Compares the nbf claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaim) VerifyNotBefore(cmp int64, req bool) bool {
	nbf, _ := m["nbf"].(float64)
	return verifyNbf(int64(nbf), cmp, req)
}

// Validates time based claims "exp, iat, nbf".
// There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still
// be considered a valid claim.
func (m MapClaim) Valid() error {
	vErr := new(ValidationError)
	now := TimeFunc().Unix()

	if m.VerifyExpiresAt(now, false) == false {
		vErr.err = "Token is expired"
		vErr.Errors |= ValidationErrorExpired
	}

	if m.VerifyIssuedAt(now, false) == false {
		vErr.err = "Token used before issued, clock skew issue?"
		vErr.Errors |= ValidationErrorIssuedAt
	}

	if m.VerifyNotBefore(now, false) == false {
		vErr.err = "Token is not valid yet"
		vErr.Errors |= ValidationErrorNotValidYet
	}

	if vErr.valid() {
		return nil
	}

	return vErr
}

func verifyAud(aud string, cmp string, required bool) bool {
	if aud == "" {
		return !required
	}
	if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
		return true
	} else {
		return false
	}
}

func verifyExp(exp int64, now int64, required bool) bool {
	if exp == 0 {
		return !required
	}
	return now-int64(Leeway.Seconds()) <= exp
}

func verifyIat(iat int64, now int64, required bool) bool {
	if iat == 0 {
		return !required
	}
	return now+int64(Leeway.Seconds()) >= iat
}

func verifyIss(iss string, cmp string, required bool) bool {
	if iss == "" {
		return !required
	}
	if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
		return true
	} else {
		return false
	}
}

func verifyNbf(nbf int64, now int64, required bool) bool {
	if nbf == 0 {
		return !required
	}
	return now+int64(Leeway.Seconds()) >= nbf
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	//"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"
	//"honnef.co/go/js/console"
	//"reflect"
	"strings"
)

type ViewImpl struct {
	tag      string
	id       string
	classes  []string
	children []*ViewImpl
	text     string
	builders []builder
	event    []*eventHandler
}

type option func(*ViewImpl) *ViewImpl

func Event(name EventName, fn EventFunc) option {
	return func(self *ViewImpl) *ViewImpl {
		self.event = append(self.event, &eventHandler{
			name: name,
			fn:   fn,
		})
		return self
	}
}

func Class(cl CssClass) option {
	return func(self *ViewImpl) *ViewImpl {
		self.classes = append(self.classes, cl.ClassName())
		return self
	}
}

func Text(str string) option {
	return func(self *ViewImpl) *ViewImpl {
		self.text = str
		return self
	}
}

func Id(id HtmlId) option {
	return func(self *ViewImpl) *ViewImpl {
		if id == nil {
			panic("should not be calling Id() on a nil HtmlId")
		}
		self.id = id.Id()
		return self
	}
}

func ModelId(m ModelName) option {
	return func(self *ViewImpl) *ViewImpl {
		self.id = HtmlIdFromModel(self.tag, m).Id()
		return self
	}
}

func addBuilder(b builder) option {
	return func(self *ViewImpl) *ViewImpl {
		self.builders = append(self.builders, b)
		return self
	}
}

func CssExistence(c CssClass, b BooleanAttribute) option {
	return addBuilder(cssExistenceBuilder(c, b))
}

func PropEqual(n propName, b BooleanAttribute) option {
	return addBuilder(propBuilder(n, b, nil))
}

func HtmlAttrEqual(h htmlAttrName, attr Attribute) option {
	return addBuilder(htmlAttrBuilder(h, attr, nil))
}

func TextEqual(attr Attribute) option {
	return addBuilder(textAttrBuilder(attr, nil))
}

//HtmlIdFromModel returns an HtmlId object from the given modelname and
//tagname.  Resulting id is unique to the modelname and tag, but not
//between tags with the same name.
func HtmlIdFromModel(tag string, m ModelName) HtmlId {
	id := fmt.Sprintf("%s-%s", strings.ToLower(tag), m.Id())
	return NewHtmlId(tag, id)
}

func (p *ViewImpl) Build() NarrowDom {
	id := ""
	classes := ""
	if p.id != "" {
		id = fmt.Sprintf(" id='%s'", p.id)
	}

	if p.classes != nil {
		classes = fmt.Sprintf(" class='%s'", strings.Join(p.classes, " "))
	}
	var t string
	if p.text == "" {
		t = fmt.Sprintf("<%s%s%s/>", p.tag, id, classes)
	} else {
		t = fmt.Sprintf("<%s%s%s>%s</%s>", p.tag, id, classes, p.text, p.tag)
	}
	parsed := jquery.ParseHTML(t)
	var nDom NarrowDom
	if TestMode {
		nDom = newTestOps()
	} else {
		nDom = wrap(jquery.NewJQuery(parsed[0]))
	}

	for _, child := range p.children {
		built := child.Build()
		nDom.Append(built)
	}

	if p.builders != nil {
		for _, b := range p.builders {
			if b == nil {
				panic("found a nil builder in tree construction!")
			}
			b.build(nDom)
		}
	}

	if p.event != nil {
		for _, h := range p.event {
			//we have the object now, assign to j
			h.t = nDom
			h.register()
		}
	}
	return nDom
}

func IMG(obj ...interface{}) *ViewImpl {
	return tag("img", obj...)
}

func FORM(obj ...interface{}) *ViewImpl {
	return tag("form", obj...)
}

func DIV(obj ...interface{}) *ViewImpl {
	return tag("div", obj...)
}

func INPUT(obj ...interface{}) *ViewImpl {
	return tag("input", obj...)
}

func TEXTAREA(obj ...interface{}) *ViewImpl {
	return tag("textarea", obj...)
}

func LABEL(obj ...interface{}) *ViewImpl {
	return tag("label", obj...)
}

func A(obj ...interface{}) *ViewImpl {
	return tag("a", obj...)
}

func SPAN(obj ...interface{}) *ViewImpl {
	return tag("span", obj...)
}

func H1(obj ...interface{}) *ViewImpl {
	return tag("h1", obj...)
}

func H2(obj ...interface{}) *ViewImpl {
	return tag("h2", obj...)
}

func H3(obj ...interface{}) *ViewImpl {
	return tag("h3", obj...)
}

func H4(obj ...interface{}) *ViewImpl {
	return tag("h4", obj...)
}

func H5(obj ...interface{}) *ViewImpl {
	return tag("h5", obj...)
}

func H6(obj ...interface{}) *ViewImpl {
	return tag("h6", obj...)
}

func HR(obj ...interface{}) *ViewImpl {
	return tag("hr", obj...)
}

func LI(obj ...interface{}) *ViewImpl {
	return tag("li", obj...)
}

func UL(obj ...interface{}) *ViewImpl {
	return tag("ul", obj...)
}
func OL(obj ...interface{}) *ViewImpl {
	return tag("ol", obj...)
}
func BUTTON(obj ...interface{}) *ViewImpl {
	return tag("button", obj...)
}

func tag(tagName string, obj ...interface{}) *ViewImpl {
	p := &ViewImpl{tag: tagName}

	for i := 0; i < len(obj); i++ {
		if obj[i] == nil {
			panic("cant use a nil value in view construction")
		}
		opt, ok := obj[i].(option)
		if ok {
			opt(p)
			continue
		}
		v, ok := obj[i].(*ViewImpl)
		if ok {
			p.children = append(p.children, v)
			continue
		}
		panic(fmt.Sprintf("unable to understand type of parameter: %v (%T %d) to %s", obj[i], obj[i], i, tagName))
	}
	return p
}
<commit_msg>adding simple html attr bound to constant<commit_after>package client

import (
	"fmt"
	//"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"
	//"honnef.co/go/js/console"
	//"reflect"
	"strings"
)

type ViewImpl struct {
	tag      string
	id       string
	classes  []string
	children []*ViewImpl
	text     string
	builders []builder
	event    []*eventHandler
}

type option func(*ViewImpl) *ViewImpl

func Event(name EventName, fn EventFunc) option {
	return func(self *ViewImpl) *ViewImpl {
		self.event = append(self.event, &eventHandler{
			name: name,
			fn:   fn,
		})
		return self
	}
}

func Class(cl CssClass) option {
	return func(self *ViewImpl) *ViewImpl {
		self.classes = append(self.classes, cl.ClassName())
		return self
	}
}

func Text(str string) option {
	return func(self *ViewImpl) *ViewImpl {
		self.text = str
		return self
	}
}

func IdConstant(id string) option {
	return func(self *ViewImpl) *ViewImpl {
		if id == "" {
			panic("should not be calling IdConstant() with an empty id")
		}
		self.id = id
		return self
	}
}

func Id(id HtmlId) option {
	return func(self *ViewImpl) *ViewImpl {
		if id == nil {
			panic("should not be calling Id() on a nil HtmlId")
		}
		self.id = id.Id()
		return self
	}
}

func ModelId(m ModelName) option {
	return func(self *ViewImpl) *ViewImpl {
		self.id = HtmlIdFromModel(self.tag, m).Id()
		return self
	}
}

func addBuilder(b builder) option {
	return func(self *ViewImpl) *ViewImpl {
		self.builders = append(self.builders, b)
		return self
	}
}

func CssExistence(c CssClass, b BooleanAttribute) option {
	return addBuilder(cssExistenceBuilder(c, b))
}

func PropEqual(n propName, b BooleanAttribute) option {
	return addBuilder(propBuilder(n, b, nil))
}

func HtmlAttrEqual(h htmlAttrName, attr Attribute) option {
	return addBuilder(htmlAttrBuilder(h, attr, nil))
}

func HtmlAttrConstant(h htmlAttrName, str string) option {
	attr := NewStringSimple(str)
	return addBuilder(htmlAttrBuilder(h, attr, nil))
}

func TextEqual(attr Attribute) option {
	return addBuilder(textAttrBuilder(attr, nil))
}

//HtmlIdFromModel returns an HtmlId object from the given modelname and
//tagname.  Resulting id is unique to the modelname and tag, but not
//between tags with the same name.
func HtmlIdFromModel(tag string, m ModelName) HtmlId {
	id := fmt.Sprintf("%s-%s", strings.ToLower(tag), m.Id())
	return NewHtmlId(tag, id)
}

func (p *ViewImpl) Build() NarrowDom {
	id := ""
	classes := ""
	if p.id != "" {
		id = fmt.Sprintf(" id='%s'", p.id)
	}

	if p.classes != nil {
		classes = fmt.Sprintf(" class='%s'", strings.Join(p.classes, " "))
	}
	var t string
	if p.text == "" {
		t = fmt.Sprintf("<%s%s%s/>", p.tag, id, classes)
	} else {
		t = fmt.Sprintf("<%s%s%s>%s</%s>", p.tag, id, classes, p.text, p.tag)
	}
	parsed := jquery.ParseHTML(t)
	var nDom NarrowDom
	if TestMode {
		nDom = newTestOps()
	} else {
		nDom = wrap(jquery.NewJQuery(parsed[0]))
	}

	for _, child := range p.children {
		built := child.Build()
		nDom.Append(built)
	}

	if p.builders != nil {
		for _, b := range p.builders {
			if b == nil {
				panic("found a nil builder in tree construction!")
			}
			b.build(nDom)
		}
	}

	if p.event != nil {
		for _, h := range p.event {
			//we have the object now, assign to j
			h.t = nDom
			h.register()
		}
	}
	return nDom
}

func IMG(obj ...interface{}) *ViewImpl {
	return tag("img", obj...)
}

func FORM(obj ...interface{}) *ViewImpl {
	return tag("form", obj...)
}

func DIV(obj ...interface{}) *ViewImpl {
	return tag("div", obj...)
}

func INPUT(obj ...interface{}) *ViewImpl {
	return tag("input", obj...)
}

func TEXTAREA(obj ...interface{}) *ViewImpl {
	return tag("textarea", obj...)
}

func LABEL(obj ...interface{}) *ViewImpl {
	return tag("label", obj...)
}

func A(obj ...interface{}) *ViewImpl {
	return tag("a", obj...)
}

func SPAN(obj ...interface{}) *ViewImpl {
	return tag("span", obj...)
}

func H1(obj ...interface{}) *ViewImpl {
	return tag("h1", obj...)
}

func H2(obj ...interface{}) *ViewImpl {
	return tag("h2", obj...)
}

func H3(obj ...interface{}) *ViewImpl {
	return tag("h3", obj...)
}

func H4(obj ...interface{}) *ViewImpl {
	return tag("h4", obj...)
}

func H5(obj ...interface{}) *ViewImpl {
	return tag("h5", obj...)
}

func H6(obj ...interface{}) *ViewImpl {
	return tag("h6", obj...)
}

func HR(obj ...interface{}) *ViewImpl {
	return tag("hr", obj...)
}

func LI(obj ...interface{}) *ViewImpl {
	return tag("li", obj...)
}

func UL(obj ...interface{}) *ViewImpl {
	return tag("ul", obj...)
}
func OL(obj ...interface{}) *ViewImpl {
	return tag("ol", obj...)
}
func BUTTON(obj ...interface{}) *ViewImpl {
	return tag("button", obj...)
}

func tag(tagName string, obj ...interface{}) *ViewImpl {
	p := &ViewImpl{tag: tagName}

	for i := 0; i < len(obj); i++ {
		if obj[i] == nil {
			panic("cant use a nil value in view construction")
		}
		opt, ok := obj[i].(option)
		if ok {
			opt(p)
			continue
		}
		v, ok := obj[i].(*ViewImpl)
		if ok {
			p.children = append(p.children, v)
			continue
		}
		panic(fmt.Sprintf("unable to understand type of parameter: %v (%T %d) to %s", obj[i], obj[i], i, tagName))
	}
	return p
}
<|endoftext|>


<commit_before>package dns

import (
	"strconv"
	"testing"
	"time"
)

func TestClientSync(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	// And now with plain Exchange().
	r, err = Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

func TestClientSyncBadId(t *testing.T) {
	HandleFunc("miek.nl.", HelloServerBadId)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	if _, _, err := c.Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
	// And now with plain Exchange().
	if _, err := Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
}

func TestClientEDNS0(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeDNSKEY)

	m.SetEdns0(2048, true)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

// Validates the transmission and parsing of local EDNS0 options.
func TestClientEDNS0Local(t *testing.T) {

	optStr1 := "1979:0x0707"
	optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"

	handler := func(w ResponseWriter, req *Msg) {
		m := new(Msg)
		m.SetReply(req)

		m.Extra = make([]RR, 1, 2)
		m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}

		// If the local options are what we expect, then reflect them back.
		ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
		ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
		if ec1 == optStr1 && ec2 == optStr2 {
			m.Extra = append(m.Extra, req.Extra[0])
		}

		w.WriteMsg(m)
	}

	HandleFunc("miek.nl.", handler)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)

	// Add two local edns options to the query.
	ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
	ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
	o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
	m.Extra = append(m.Extra, o)

	c := new(Client)
	r, _, e := c.Exchange(m, addrstr)
	if e != nil {
		t.Logf("failed to exchange: %s", e.Error())
		t.Fail()
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Log("failed to get a valid answer")
		t.Fail()
		t.Logf("%v\n", r)
	}

	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello local edns" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns")
		t.Fail()
	}

	// Validate the local options in the reply.
	got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
	if got != optStr1 {
		t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
		t.Fail()
		t.Logf("%v\n", r)
	}

	got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
	if got != optStr2 {
		t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
		t.Fail()
		t.Logf("%v\n", r)
	}
}

func TestSingleSingleInflight(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeDNSKEY)

	c := new(Client)
	c.SingleInflight = true
	nr := 10
	ch := make(chan time.Duration)
	for i := 0; i < nr; i++ {
		go func() {
			_, rtt, _ := c.Exchange(m, addrstr)
			ch <- rtt
		}()
	}
	i := 0
	var first time.Duration
	// With inflight *all* rtt are identical, and by doing actual lookups
	// the changes that this is a coincidence is small.
Loop:
	for {
		select {
		case rtt := <-ch:
			if i == 0 {
				first = rtt
			} else {
				if first != rtt {
					t.Errorf("all rtts should be equal.  got %d want %d", rtt, first)
				}
			}
			i++
			if i == 10 {
				break Loop
			}
		}
	}
}

// ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG.
func ExampleUpdateLeaseTSIG(t *testing.T) {
	m := new(Msg)
	m.SetUpdate("t.local.ip6.io.")
	rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
	rrs := make([]RR, 1)
	rrs[0] = rr
	m.Insert(rrs)

	leaseRr := new(OPT)
	leaseRr.Hdr.Name = "."
	leaseRr.Hdr.Rrtype = TypeOPT
	e := new(EDNS0_UL)
	e.Code = EDNS0UL
	e.Lease = 120
	leaseRr.Option = append(leaseRr.Option, e)
	m.Extra = append(m.Extra, leaseRr)

	c := new(Client)
	m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
	c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}

	_, _, err := c.Exchange(m, "127.0.0.1:53")
	if err != nil {
		t.Error(err)
	}
}

func TestClientConn(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	// This uses TCP just to make it slightly different than TestClientSync
	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	cn, err := Dial("tcp", addrstr)
	if err != nil {
		t.Errorf("failed to dial %s: %v", addrstr, err)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	r, err := cn.ReadMsg()
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	h := new(Header)
	buf, err := cn.ReadMsgHeader(h)
	if buf == nil {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	if int(h.Bits&0xF) != RcodeSuccess {
		t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r)
	}
	if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 {
		t.Errorf("expected to have question and additional in response; got something else: %+v", h)
	}
	if err = r.Unpack(buf); err != nil {
		t.Errorf("unable to unpack message fully: %v", err)
	}

}
<commit_msg>Rename TestSingleSingleInflight to TestSingleInflight and some cosmetic changes<commit_after>package dns

import (
	"strconv"
	"testing"
	"time"
)

func TestClientSync(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	// And now with plain Exchange().
	r, err = Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

func TestClientSyncBadId(t *testing.T) {
	HandleFunc("miek.nl.", HelloServerBadId)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	if _, _, err := c.Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
	// And now with plain Exchange().
	if _, err := Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
}

func TestClientEDNS0(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeDNSKEY)

	m.SetEdns0(2048, true)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

// Validates the transmission and parsing of local EDNS0 options.
func TestClientEDNS0Local(t *testing.T) {

	optStr1 := "1979:0x0707"
	optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"

	handler := func(w ResponseWriter, req *Msg) {
		m := new(Msg)
		m.SetReply(req)

		m.Extra = make([]RR, 1, 2)
		m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}

		// If the local options are what we expect, then reflect them back.
		ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
		ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
		if ec1 == optStr1 && ec2 == optStr2 {
			m.Extra = append(m.Extra, req.Extra[0])
		}

		w.WriteMsg(m)
	}

	HandleFunc("miek.nl.", handler)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)

	// Add two local edns options to the query.
	ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
	ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
	o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
	m.Extra = append(m.Extra, o)

	c := new(Client)
	r, _, e := c.Exchange(m, addrstr)
	if e != nil {
		t.Logf("failed to exchange: %s", e.Error())
		t.Fail()
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Log("failed to get a valid answer")
		t.Fail()
		t.Logf("%v\n", r)
	}

	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello local edns" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns")
		t.Fail()
	}

	// Validate the local options in the reply.
	got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
	if got != optStr1 {
		t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
		t.Fail()
		t.Logf("%v\n", r)
	}

	got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
	if got != optStr2 {
		t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
		t.Fail()
		t.Logf("%v\n", r)
	}
}

func TestSingleInflight(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeDNSKEY)

	c := new(Client)
	c.SingleInflight = true
	nr := 10
	ch := make(chan time.Duration)
	for i := 0; i < nr; i++ {
		go func() {
			_, rtt, _ := c.Exchange(m, addrstr)
			ch <- rtt
		}()
	}
	i := 0
	var first time.Duration
	// With inflight *all* rtt are identical, and by doing actual lookups
	// the chances that this is a coincidence is small.
Loop:
	for {
		select {
		case rtt := <-ch:
			if i == 0 {
				first = rtt
			} else {
				if first != rtt {
					t.Errorf("all rtts should be equal, got %d want %d", rtt, first)
				}
			}
			i++
			if i == 10 {
				break Loop
			}
		}
	}
}

// ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG.
func ExampleUpdateLeaseTSIG(t *testing.T) {
	m := new(Msg)
	m.SetUpdate("t.local.ip6.io.")
	rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
	rrs := make([]RR, 1)
	rrs[0] = rr
	m.Insert(rrs)

	leaseRr := new(OPT)
	leaseRr.Hdr.Name = "."
	leaseRr.Hdr.Rrtype = TypeOPT
	e := new(EDNS0_UL)
	e.Code = EDNS0UL
	e.Lease = 120
	leaseRr.Option = append(leaseRr.Option, e)
	m.Extra = append(m.Extra, leaseRr)

	c := new(Client)
	m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
	c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}

	_, _, err := c.Exchange(m, "127.0.0.1:53")
	if err != nil {
		t.Error(err)
	}
}

func TestClientConn(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	// This uses TCP just to make it slightly different than TestClientSync
	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	cn, err := Dial("tcp", addrstr)
	if err != nil {
		t.Errorf("failed to dial %s: %v", addrstr, err)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	r, err := cn.ReadMsg()
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	h := new(Header)
	buf, err := cn.ReadMsgHeader(h)
	if buf == nil {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	if int(h.Bits&0xF) != RcodeSuccess {
		t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r)
	}
	if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 {
		t.Errorf("expected to have question and additional in response; got something else: %+v", h)
	}
	if err = r.Unpack(buf); err != nil {
		t.Errorf("unable to unpack message fully: %v", err)
	}

}
<|endoftext|>


<commit_before>package dns

import (
	"strconv"
	"testing"
	"time"
)

func TestClientSync(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	// And now with plain Exchange().
	r, err = Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

func TestClientSyncBadId(t *testing.T) {
	HandleFunc("miek.nl.", HelloServerBadId)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	if _, _, err := c.Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
	// And now with plain Exchange().
	if _, err := Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
}

func TestClientEDNS0(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeDNSKEY)

	m.SetEdns0(2048, true)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

// Validates the transmission and parsing of local EDNS0 options.
func TestClientEDNS0Local(t *testing.T) {
	optStr1 := "1979:0x0707"
	optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"

	handler := func(w ResponseWriter, req *Msg) {
		m := new(Msg)
		m.SetReply(req)

		m.Extra = make([]RR, 1, 2)
		m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}

		// If the local options are what we expect, then reflect them back.
		ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
		ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
		if ec1 == optStr1 && ec2 == optStr2 {
			m.Extra = append(m.Extra, req.Extra[0])
		}

		w.WriteMsg(m)
	}

	HandleFunc("miek.nl.", handler)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)

	// Add two local edns options to the query.
	ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
	ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
	o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
	m.Extra = append(m.Extra, o)

	c := new(Client)
	r, _, e := c.Exchange(m, addrstr)
	if e != nil {
		t.Logf("failed to exchange: %s", e.Error())
		t.Fail()
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Log("failed to get a valid answer")
		t.Fail()
		t.Logf("%v\n", r)
	}

	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello local edns" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns")
		t.Fail()
	}

	// Validate the local options in the reply.
	got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
	if got != optStr1 {
		t.Logf("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
		t.Fail()
		t.Logf("%v\n", r)
	}

	got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
	if got != optStr2 {
		t.Logf("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
		t.Fail()
		t.Logf("%v\n", r)
	}
}

// ExampleTsigSecret_updateLeaseTSIG shows how to update a lease signed with TSIG.
func ExampleTsigSecret_updateLeaseTSIG() {
	m := new(Msg)
	m.SetUpdate("t.local.ip6.io.")
	rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
	rrs := make([]RR, 1)
	rrs[0] = rr
	m.Insert(rrs)

	leaseRr := new(OPT)
	leaseRr.Hdr.Name = "."
	leaseRr.Hdr.Rrtype = TypeOPT
	e := new(EDNS0_UL)
	e.Code = EDNS0UL
	e.Lease = 120
	leaseRr.Option = append(leaseRr.Option, e)
	m.Extra = append(m.Extra, leaseRr)

	c := new(Client)
	m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
	c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}

	_, _, err := c.Exchange(m, "127.0.0.1:53")
	if err != nil {
		panic(err)
	}
}

func TestClientConn(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	// This uses TCP just to make it slightly different than TestClientSync
	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	cn, err := Dial("tcp", addrstr)
	if err != nil {
		t.Errorf("failed to dial %s: %v", addrstr, err)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	r, err := cn.ReadMsg()
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	h := new(Header)
	buf, err := cn.ReadMsgHeader(h)
	if buf == nil {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	if int(h.Bits&0xF) != RcodeSuccess {
		t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r)
	}
	if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 {
		t.Errorf("expected to have question and additional in response; got something else: %+v", h)
	}
	if err = r.Unpack(buf); err != nil {
		t.Errorf("unable to unpack message fully: %v", err)
	}
}
<commit_msg>deleting a dot to retrigger travis CI<commit_after>package dns

import (
	"strconv"
	"testing"
	"time"
)

func TestClientSync(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	// And now with plain Exchange().
	r, err = Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

func TestClientSyncBadId(t *testing.T) {
	HandleFunc("miek.nl.", HelloServerBadId)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	c := new(Client)
	if _, _, err := c.Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
	// And now with plain Exchange().
	if _, err := Exchange(m, addrstr); err != ErrId {
		t.Errorf("did not find a bad Id")
	}
}

func TestClientEDNS0(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeDNSKEY)

	m.SetEdns0(2048, true)

	c := new(Client)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
}

// Validates the transmission and parsing of local EDNS0 options.
func TestClientEDNS0Local(t *testing.T) {
	optStr1 := "1979:0x0707"
	optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"

	handler := func(w ResponseWriter, req *Msg) {
		m := new(Msg)
		m.SetReply(req)

		m.Extra = make([]RR, 1, 2)
		m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}

		// If the local options are what we expect, then reflect them back.
		ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
		ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
		if ec1 == optStr1 && ec2 == optStr2 {
			m.Extra = append(m.Extra, req.Extra[0])
		}

		w.WriteMsg(m)
	}

	HandleFunc("miek.nl.", handler)
	defer HandleRemove("miek.nl.")

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)

	// Add two local edns options to the query.
	ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
	ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
	o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
	m.Extra = append(m.Extra, o)

	c := new(Client)
	r, _, e := c.Exchange(m, addrstr)
	if e != nil {
		t.Logf("failed to exchange: %s", e.Error())
		t.Fail()
	}

	if r != nil && r.Rcode != RcodeSuccess {
		t.Log("failed to get a valid answer")
		t.Fail()
		t.Logf("%v\n", r)
	}

	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello local edns" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns")
		t.Fail()
	}

	// Validate the local options in the reply.
	got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
	if got != optStr1 {
		t.Logf("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
		t.Fail()
		t.Logf("%v\n", r)
	}

	got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
	if got != optStr2 {
		t.Logf("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
		t.Fail()
		t.Logf("%v\n", r)
	}
}

// ExampleTsigSecret_updateLeaseTSIG shows how to update a lease signed with TSIG
func ExampleTsigSecret_updateLeaseTSIG() {
	m := new(Msg)
	m.SetUpdate("t.local.ip6.io.")
	rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
	rrs := make([]RR, 1)
	rrs[0] = rr
	m.Insert(rrs)

	leaseRr := new(OPT)
	leaseRr.Hdr.Name = "."
	leaseRr.Hdr.Rrtype = TypeOPT
	e := new(EDNS0_UL)
	e.Code = EDNS0UL
	e.Lease = 120
	leaseRr.Option = append(leaseRr.Option, e)
	m.Extra = append(m.Extra, leaseRr)

	c := new(Client)
	m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
	c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}

	_, _, err := c.Exchange(m, "127.0.0.1:53")
	if err != nil {
		panic(err)
	}
}

func TestClientConn(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	defer HandleRemove("miek.nl.")

	// This uses TCP just to make it slightly different than TestClientSync
	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %v", err)
	}
	defer s.Shutdown()

	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeSOA)

	cn, err := Dial("tcp", addrstr)
	if err != nil {
		t.Errorf("failed to dial %s: %v", addrstr, err)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	r, err := cn.ReadMsg()
	if r == nil || r.Rcode != RcodeSuccess {
		t.Errorf("failed to get an valid answer\n%v", r)
	}

	err = cn.WriteMsg(m)
	if err != nil {
		t.Errorf("failed to exchange: %v", err)
	}
	h := new(Header)
	buf, err := cn.ReadMsgHeader(h)
	if buf == nil {
		t.Errorf("failed to get an valid answer\n%v", r)
	}
	if int(h.Bits&0xF) != RcodeSuccess {
		t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r)
	}
	if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 {
		t.Errorf("expected to have question and additional in response; got something else: %+v", h)
	}
	if err = r.Unpack(buf); err != nil {
		t.Errorf("unable to unpack message fully: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"
	"os/signal"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v3"
)

var (
	// discordgo session
	discord *discordgo.Session
	me *discordgo.User
)

func onReady(s *discordgo.Session, event *discordgo.Ready) {
	log.Info("Recieved READY payload")
	s.UpdateStatus(0, "League Of Legends")
}

func onGuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if !shardContains(event.Guild.ID) {
		return
	}

	if event.Guild.Unavailable != nil {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			s.ChannelMessageSend(channel.ID, "BEEP BOOP BOOTING")
			s.ChannelMessageSend(channel.ID, "https://media.giphy.com/media/3o85g3yQa2iG2Rdq1O/giphy.gif")
			return
		}
	}
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	log.Info("message created: ", m.Content)
	var (
		ourShard = true
	)

	if (len(m.Content) <= 0 || (m.Content[0] != '!' && m.Content[0] != '<')) { //@J.A.R.V.I.S = <@168313836951175168>
		return
	}
	parts := strings.Split(m.Content, " ")

	channel, _ := discord.State.Channel(m.ChannelID)
	if channel == nil {
		log.WithFields(log.Fields{
			"channel": m.ChannelID,
			"message": m.ID,
		}).Warning("Failed to grab channel")
		return
	}

	guild, _ := discord.State.Guild(channel.GuildID)
	if guild == nil {
		log.WithFields(log.Fields{
			"guild":   channel.GuildID,
			"channel": channel,
			"message": m.ID,
		}).Warning("Failed to grab guild")
		return
	}

	// If we're in sharding mode, test whether this message is relevant to us
	if !shardContains(channel.GuildID) {
		ourShard = false
	}

	if !ourShard {
		return
	}

	switch strings.ToLower(parts[0]) {
		case "!elo": elo(parts[1:], s, m)
		case "!weather": weather(parts[1:], s, m)
		case "<@168313836951175168>": jarvis(parts[1:], s, m)
		case "!coin": coin(s, m)
		case "!dice": dice(s, m)
		case "!whatis": classifyImage(parts[1:], s, m)
	}
}

func main() {
	var (
		Token = flag.String("t", "", "Discord Authentication Token")
		Redis = flag.String("r", "", "Redis Connection String")
		Shard = flag.String("s", "", "Integers to shard by")
		Owner = flag.String("o", "", "Owner ID")
		err   error
	)
	flag.Parse()

	if(*Token == "") {
		flag.PrintDefaults()
		return
	}

	if *Owner != "" {
		OWNER = *Owner
	}

	// Make sure shard is either empty, or an integer
	if *Shard != "" {
		SHARDS = strings.Split(*Shard, ",")

		for _, shard := range SHARDS {
			if _, err := strconv.Atoi(shard); err != nil {
				log.WithFields(log.Fields{
					"shard": shard,
					"error": err,
				}).Fatal("Invalid Shard")
				return
			}
		}
	}

	// If we got passed a redis server, try to connect
	if *Redis != "" {
		log.Info("Connecting to redis...")
		rcli = redis.NewClient(&redis.Options{Addr: *Redis, DB: 0})
		_, err = rcli.Ping().Result()

		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Fatal("Failed to connect to redis")
			return
		}
	}

	// Create a discord session
	log.Info("Starting discord session...")
	discord, err = discordgo.New(*Token)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord session")
		return
	}

	discord.AddHandler(onReady)
	discord.AddHandler(onGuildCreate)
	discord.AddHandler(onMessageCreate)

	err = discord.Open()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord websocket connection")
		return
	}

	// We're running!
	log.Info("JARVIS READY.")

	// Wait for a signal to quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<commit_msg>command doesn't work commented out<commit_after>package main

import (
	"flag"
	"os"
	"os/signal"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v3"
)

var (
	// discordgo session
	discord *discordgo.Session
	me *discordgo.User
)

func onReady(s *discordgo.Session, event *discordgo.Ready) {
	log.Info("Recieved READY payload")
	s.UpdateStatus(0, "League Of Legends")
}

func onGuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if !shardContains(event.Guild.ID) {
		return
	}

	if event.Guild.Unavailable != nil {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			s.ChannelMessageSend(channel.ID, "BEEP BOOP BOOTING")
			s.ChannelMessageSend(channel.ID, "https://media.giphy.com/media/3o85g3yQa2iG2Rdq1O/giphy.gif")
			return
		}
	}
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	log.Info("message created: ", m.Content)
	var (
		ourShard = true
	)

	if (len(m.Content) <= 0 || (m.Content[0] != '!' && m.Content[0] != '<')) { //@J.A.R.V.I.S = <@168313836951175168>
		return
	}
	parts := strings.Split(m.Content, " ")

	channel, _ := discord.State.Channel(m.ChannelID)
	if channel == nil {
		log.WithFields(log.Fields{
			"channel": m.ChannelID,
			"message": m.ID,
		}).Warning("Failed to grab channel")
		return
	}

	guild, _ := discord.State.Guild(channel.GuildID)
	if guild == nil {
		log.WithFields(log.Fields{
			"guild":   channel.GuildID,
			"channel": channel,
			"message": m.ID,
		}).Warning("Failed to grab guild")
		return
	}

	// If we're in sharding mode, test whether this message is relevant to us
	if !shardContains(channel.GuildID) {
		ourShard = false
	}

	if !ourShard {
		return
	}

	switch strings.ToLower(parts[0]) {
		case "!elo": elo(parts[1:], s, m)
		case "!weather": weather(parts[1:], s, m)
		case "<@168313836951175168>": jarvis(parts[1:], s, m)
		case "!coin": coin(s, m)
		case "!dice": dice(s, m)
		//case "!whatis": classifyImage(parts[1:], s, m)
	}
}

func main() {
	var (
		Token = flag.String("t", "", "Discord Authentication Token")
		Redis = flag.String("r", "", "Redis Connection String")
		Shard = flag.String("s", "", "Integers to shard by")
		Owner = flag.String("o", "", "Owner ID")
		err   error
	)
	flag.Parse()

	if(*Token == "") {
		flag.PrintDefaults()
		return
	}

	if *Owner != "" {
		OWNER = *Owner
	}

	// Make sure shard is either empty, or an integer
	if *Shard != "" {
		SHARDS = strings.Split(*Shard, ",")

		for _, shard := range SHARDS {
			if _, err := strconv.Atoi(shard); err != nil {
				log.WithFields(log.Fields{
					"shard": shard,
					"error": err,
				}).Fatal("Invalid Shard")
				return
			}
		}
	}

	// If we got passed a redis server, try to connect
	if *Redis != "" {
		log.Info("Connecting to redis...")
		rcli = redis.NewClient(&redis.Options{Addr: *Redis, DB: 0})
		_, err = rcli.Ping().Result()

		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Fatal("Failed to connect to redis")
			return
		}
	}

	// Create a discord session
	log.Info("Starting discord session...")
	discord, err = discordgo.New(*Token)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord session")
		return
	}

	discord.AddHandler(onReady)
	discord.AddHandler(onGuildCreate)
	discord.AddHandler(onMessageCreate)

	err = discord.Open()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord websocket connection")
		return
	}

	// We're running!
	log.Info("JARVIS READY.")

	// Wait for a signal to quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<|endoftext|>