<commit_before>package main

import (
	"bitbucket.org/davidwallace/go-opc/colorutils"
	"bufio"
	"fmt"
	"github.com/davecheney/profile"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

// read locations from JSON file into a slice of floats
func readLocations(fn string) []float64 {
	locations := make([]float64, 0)
	var file *os.File
	var err error
	if file, err = os.Open(fn); err != nil {
		panic(fmt.Sprintf("could not open layout file: %s", fn))
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if len(line) == 0 || line[0] == '[' || line[0] == ']' {
			continue
		}
		line = strings.Split(line, "[")[1]
		line = strings.Split(line, "]")[0]
		coordStrings := strings.Split(line, ", ")
		var x, y, z float64
		x, err = strconv.ParseFloat(coordStrings[0], 64)
		y, err = strconv.ParseFloat(coordStrings[1], 64)
		z, err = strconv.ParseFloat(coordStrings[2], 64)
		locations = append(locations, x, y, z)
	}
	fmt.Printf("Read %v pixel locations from %s\n", len(locations), fn)
	return locations
}

// Connect to an ip:port and send the values array with an OPC header in front of it.
func connectAndSend(ipPort string, values []byte) {
	time.Sleep(1 * time.Millisecond)

	// connect
	conn, err := net.Dial("tcp", ipPort)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer conn.Close()

	// make and send header
	channel := byte(0)
	command := byte(0)
	lenLowByte := byte(len(values) % 256)
	lenHighByte := byte(len(values) / 256)
	header := []byte{channel, command, lenHighByte, lenLowByte}
	_, err = conn.Write(header)
	if err != nil {
		fmt.Println(err)
		return
	}

	// send pixels
	_, err = conn.Write(values)
	if err != nil {
		fmt.Println(err)
	}
}

func main() {
	defer profile.Start(profile.CPUProfile).Stop()

	path := "circle.json"
	ipPort := "127.0.0.1:7890"

	LOCATIONS := readLocations(path)
	N_PIXELS := len(LOCATIONS) / 3
	VALUES := make([]byte, N_PIXELS*3)

	// fill in values over and over
	var pct, r, g, b, t float64
	var last_print = float64(time.Now().UnixNano()) / 1.0e9
	var frames = 0
	var start_time = last_print
	t = start_time
	for t < start_time+5 {
		t = float64(time.Now().UnixNano()) / 1.0e9
		frames += 1
		if t > last_print+1 {
			last_print = t
			fmt.Printf("%f ms (%d fps)\n", 1000.0/float64(frames), frames)
			frames = 0
		}
		for ii := 0; ii < N_PIXELS; ii++ {
			pct = float64(ii) / float64(N_PIXELS)

			r = pct
			g = pct
			b = pct

			VALUES[ii*3+0] = colorutils.FloatToByte(r)
			VALUES[ii*3+1] = colorutils.FloatToByte(g)
			VALUES[ii*3+2] = colorutils.FloatToByte(b)
		}

		connectAndSend(ipPort, VALUES)

		//for ii, v := range VALUES {
		//    fmt.Printf("VALUES[%d] = %d\n", ii, v)
		//}
	}

}
<commit_msg>Retry connections<commit_after>package main

import (
	"bitbucket.org/davidwallace/go-opc/colorutils"
	"bufio"
	"fmt"
	"github.com/davecheney/profile"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

// read locations from JSON file into a slice of floats
func readLocations(fn string) []float64 {
	locations := make([]float64, 0)
	var file *os.File
	var err error
	if file, err = os.Open(fn); err != nil {
		panic(fmt.Sprintf("could not open layout file: %s", fn))
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if len(line) == 0 || line[0] == '[' || line[0] == ']' {
			continue
		}
		line = strings.Split(line, "[")[1]
		line = strings.Split(line, "]")[0]
		coordStrings := strings.Split(line, ", ")
		var x, y, z float64
		x, err = strconv.ParseFloat(coordStrings[0], 64)
		y, err = strconv.ParseFloat(coordStrings[1], 64)
		z, err = strconv.ParseFloat(coordStrings[2], 64)
		locations = append(locations, x, y, z)
	}
	fmt.Printf("Read %v pixel locations from %s\n", len(locations), fn)
	return locations
}

// Connect to an ip:port and send the values array with an OPC header in front of it.
func connectAndSend(ipPort string, values []byte) {
	// try to connect until we succeed
	// if we fail after several tries, just return
	triesLeft := 5
	var conn net.Conn
	var err error
	for {
		conn, err = net.Dial("tcp", ipPort)
		if err == nil {
			break
		}
		fmt.Println(triesLeft, err)
		time.Sleep(1 * time.Millisecond)
		triesLeft -= 1
		if triesLeft == 0 {
			return
		}
	}
	defer conn.Close()

	// make and send header
	channel := byte(0)
	command := byte(0)
	lenLowByte := byte(len(values) % 256)
	lenHighByte := byte(len(values) / 256)
	header := []byte{channel, command, lenHighByte, lenLowByte}
	_, err = conn.Write(header)
	if err != nil {
		fmt.Println(err)
		return
	}

	// send pixels
	_, err = conn.Write(values)
	if err != nil {
		fmt.Println(err)
	}
}

func main() {
	defer profile.Start(profile.CPUProfile).Stop()

	path := "circle.json"
	ipPort := "127.0.0.1:7890"

	LOCATIONS := readLocations(path)
	N_PIXELS := len(LOCATIONS) / 3
	VALUES := make([]byte, N_PIXELS*3)

	// fill in values over and over
	var pct, r, g, b, t float64
	var last_print = float64(time.Now().UnixNano()) / 1.0e9
	var frames = 0
	var start_time = last_print
	t = start_time
	for t < start_time+5 {
		t = float64(time.Now().UnixNano()) / 1.0e9
		frames += 1
		if t > last_print+1 {
			last_print = t
			fmt.Printf("%f ms (%d fps)\n", 1000.0/float64(frames), frames)
			frames = 0
		}
		for ii := 0; ii < N_PIXELS; ii++ {
			pct = float64(ii) / float64(N_PIXELS)

			r = pct
			g = pct
			b = pct

			VALUES[ii*3+0] = colorutils.FloatToByte(r)
			VALUES[ii*3+1] = colorutils.FloatToByte(g)
			VALUES[ii*3+2] = colorutils.FloatToByte(b)
		}

		connectAndSend(ipPort, VALUES)

		//for ii, v := range VALUES {
		//    fmt.Printf("VALUES[%d] = %d\n", ii, v)
		//}
	}

}
<|endoftext|>


<commit_before>package rbd_test

import (
	"bytes"
	"encoding/json"
	"github.com/ceph/go-ceph/rados"
	"github.com/ceph/go-ceph/rbd"
	"github.com/stretchr/testify/assert"
	"os/exec"
	"sort"
	"testing"
)

//Rdb feature
var RbdFeatureLayering = uint64(1 << 0)
var RbdFeatureStripingV2 = uint64(1 << 1)

func GetUUID() string {
	out, _ := exec.Command("uuidgen").Output()
	return string(out[:36])
}

func TestVersion(t *testing.T) {
	var major, minor, patch = rbd.Version()
	assert.False(t, major < 0 || major > 1000, "invalid major")
	assert.False(t, minor < 0 || minor > 1000, "invalid minor")
	assert.False(t, patch < 0 || patch > 1000, "invalid patch")
}

func TestCreateImage(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	image, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)
	err = image.Remove()
	assert.NoError(t, err)

	name = GetUUID()
	image, err = rbd.Create(ioctx, name, 1<<22, 22,
			RbdFeatureLayering|RbdFeatureStripingV2)
	assert.NoError(t, err)
	err = image.Remove()
	assert.NoError(t, err)

	name = GetUUID()
	image, err = rbd.Create(ioctx, name, 1<<22, 22,
			RbdFeatureLayering|RbdFeatureStripingV2, 4096, 2)
	assert.NoError(t, err)
	err = image.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestGetImageNames(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	createdList := []string{}
	for i := 0; i < 10; i++ {
		name := GetUUID()
		_, err := rbd.Create(ioctx, name, 1<<22, 22)
		assert.NoError(t, err)
		createdList = append(createdList, name)
	}

	imageNames, err := rbd.GetImageNames(ioctx)
	assert.NoError(t, err)

	sort.Strings(createdList)
	sort.Strings(imageNames)
	assert.Equal(t, createdList, imageNames)

	for _, name := range createdList {
		img := rbd.GetImage(ioctx, name)
		err := img.Remove()
		assert.NoError(t, err)
	}

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestIOReaderWriter(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	img, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)

	err = img.Open()
	assert.NoError(t, err)

	stats, err := img.Stat()
	assert.NoError(t, err)

	encoder := json.NewEncoder(img)
	encoder.Encode(stats)

	err = img.Flush()
	assert.NoError(t, err)

	_, err = img.Seek(0, 0)
	assert.NoError(t, err)

	var stats2 *rbd.ImageInfo
	decoder := json.NewDecoder(img)
	decoder.Decode(&stats2)

	assert.Equal(t, &stats, &stats2)

	_, err = img.Seek(0, 0)
	bytes_in := []byte("input data")
	_, err = img.Write(bytes_in)
	assert.NoError(t, err)

	_, err = img.Seek(0, 0)
	assert.NoError(t, err)

	bytes_out := make([]byte, len(bytes_in))
	n_out, err := img.Read(bytes_out)

	assert.Equal(t, n_out, len(bytes_in))
	assert.Equal(t, bytes_in, bytes_out)

	err = img.Close()
	assert.NoError(t, err)

	img.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestCreateSnapshot(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	img, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)

	err = img.Open()
	assert.NoError(t, err)

	snapshot, err := img.CreateSnapshot("mysnap")
	assert.NoError(t, err)

	err = img.Close()
	err = img.Open("mysnap")
	assert.NoError(t, err)

	snapshot.Remove()
	assert.NoError(t, err)

	err = img.Close()
	assert.NoError(t, err)

	img.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestParentInfo(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := "parent"
	img, err := rbd.Create(ioctx, name, 1<<22, 22, 1)
	assert.NoError(t, err)

	err = img.Open()
	assert.NoError(t, err)

	snapshot, err := img.CreateSnapshot("mysnap")
	assert.NoError(t, err)

	err = snapshot.Protect()
	assert.NoError(t, err)

	// create an image context with the parent+snapshot
	snapImg := rbd.GetImage(ioctx, "parent")
	err = snapImg.Open("mysnap")
	assert.NoError(t, err)

	// ensure no children prior to clone
	pools, images, err := snapImg.ListChildren()
	assert.NoError(t, err)
	assert.Equal(t, len(pools), 0, "pools equal")
	assert.Equal(t, len(images), 0, "children length equal")

	imgNew, err := img.Clone("mysnap", ioctx, "child", 1, 22)
	assert.NoError(t, err)

	err = imgNew.Open()
	assert.NoError(t, err)
	parentPool := make([]byte, 128)
	parentName := make([]byte, 128)
	parentSnapname := make([]byte, 128)

	err = imgNew.GetParentInfo(parentPool, parentName, parentSnapname)
	assert.NoError(t, err)

	n := bytes.Index(parentName, []byte{0})
	pName := string(parentName[:n])

	n = bytes.Index(parentSnapname, []byte{0})
	pSnapname := string(parentSnapname[:n])
	assert.Equal(t, pName, "parent", "they should be equal")
	assert.Equal(t, pSnapname, "mysnap", "they should be equal")

	pools, images, err = snapImg.ListChildren()
	assert.NoError(t, err)
	assert.Equal(t, len(pools), 1, "pools equal")
	assert.Equal(t, len(images), 1, "children length equal")

	err = imgNew.Close()
	assert.NoError(t, err)

	err = imgNew.Remove()
	assert.NoError(t, err)

	err = snapshot.Unprotect()
	assert.NoError(t, err)

	err = snapshot.Remove()
	assert.NoError(t, err)

	err = img.Close()
	assert.NoError(t, err)

	err = snapImg.Close()
	assert.NoError(t, err)

	err = img.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestNotFound(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()

	img := rbd.GetImage(ioctx, name)
	err = img.Open()
	assert.Equal(t, err, rbd.RbdErrorNotFound)

	img.Remove()
	assert.Equal(t, err, rbd.RbdErrorNotFound)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}
<commit_msg>Add unit test for rbd_trash functionality<commit_after>package rbd_test

import (
	"bytes"
	"encoding/json"
	"github.com/ceph/go-ceph/rados"
	"github.com/ceph/go-ceph/rbd"
	"github.com/stretchr/testify/assert"
	"os/exec"
	"sort"
	"testing"
	"time"
)

//Rdb feature
var RbdFeatureLayering = uint64(1 << 0)
var RbdFeatureStripingV2 = uint64(1 << 1)

func GetUUID() string {
	out, _ := exec.Command("uuidgen").Output()
	return string(out[:36])
}

func TestVersion(t *testing.T) {
	var major, minor, patch = rbd.Version()
	assert.False(t, major < 0 || major > 1000, "invalid major")
	assert.False(t, minor < 0 || minor > 1000, "invalid minor")
	assert.False(t, patch < 0 || patch > 1000, "invalid patch")
}

func TestCreateImage(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	image, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)
	err = image.Remove()
	assert.NoError(t, err)

	name = GetUUID()
	image, err = rbd.Create(ioctx, name, 1<<22, 22,
			RbdFeatureLayering|RbdFeatureStripingV2)
	assert.NoError(t, err)
	err = image.Remove()
	assert.NoError(t, err)

	name = GetUUID()
	image, err = rbd.Create(ioctx, name, 1<<22, 22,
			RbdFeatureLayering|RbdFeatureStripingV2, 4096, 2)
	assert.NoError(t, err)
	err = image.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestGetImageNames(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	createdList := []string{}
	for i := 0; i < 10; i++ {
		name := GetUUID()
		_, err := rbd.Create(ioctx, name, 1<<22, 22)
		assert.NoError(t, err)
		createdList = append(createdList, name)
	}

	imageNames, err := rbd.GetImageNames(ioctx)
	assert.NoError(t, err)

	sort.Strings(createdList)
	sort.Strings(imageNames)
	assert.Equal(t, createdList, imageNames)

	for _, name := range createdList {
		img := rbd.GetImage(ioctx, name)
		err := img.Remove()
		assert.NoError(t, err)
	}

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestIOReaderWriter(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	img, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)

	err = img.Open()
	assert.NoError(t, err)

	stats, err := img.Stat()
	assert.NoError(t, err)

	encoder := json.NewEncoder(img)
	encoder.Encode(stats)

	err = img.Flush()
	assert.NoError(t, err)

	_, err = img.Seek(0, 0)
	assert.NoError(t, err)

	var stats2 *rbd.ImageInfo
	decoder := json.NewDecoder(img)
	decoder.Decode(&stats2)

	assert.Equal(t, &stats, &stats2)

	_, err = img.Seek(0, 0)
	bytes_in := []byte("input data")
	_, err = img.Write(bytes_in)
	assert.NoError(t, err)

	_, err = img.Seek(0, 0)
	assert.NoError(t, err)

	bytes_out := make([]byte, len(bytes_in))
	n_out, err := img.Read(bytes_out)

	assert.Equal(t, n_out, len(bytes_in))
	assert.Equal(t, bytes_in, bytes_out)

	err = img.Close()
	assert.NoError(t, err)

	img.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestCreateSnapshot(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	img, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)

	err = img.Open()
	assert.NoError(t, err)

	snapshot, err := img.CreateSnapshot("mysnap")
	assert.NoError(t, err)

	err = img.Close()
	err = img.Open("mysnap")
	assert.NoError(t, err)

	snapshot.Remove()
	assert.NoError(t, err)

	err = img.Close()
	assert.NoError(t, err)

	img.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestParentInfo(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := "parent"
	img, err := rbd.Create(ioctx, name, 1<<22, 22, 1)
	assert.NoError(t, err)

	err = img.Open()
	assert.NoError(t, err)

	snapshot, err := img.CreateSnapshot("mysnap")
	assert.NoError(t, err)

	err = snapshot.Protect()
	assert.NoError(t, err)

	// create an image context with the parent+snapshot
	snapImg := rbd.GetImage(ioctx, "parent")
	err = snapImg.Open("mysnap")
	assert.NoError(t, err)

	// ensure no children prior to clone
	pools, images, err := snapImg.ListChildren()
	assert.NoError(t, err)
	assert.Equal(t, len(pools), 0, "pools equal")
	assert.Equal(t, len(images), 0, "children length equal")

	imgNew, err := img.Clone("mysnap", ioctx, "child", 1, 22)
	assert.NoError(t, err)

	err = imgNew.Open()
	assert.NoError(t, err)
	parentPool := make([]byte, 128)
	parentName := make([]byte, 128)
	parentSnapname := make([]byte, 128)

	err = imgNew.GetParentInfo(parentPool, parentName, parentSnapname)
	assert.NoError(t, err)

	n := bytes.Index(parentName, []byte{0})
	pName := string(parentName[:n])

	n = bytes.Index(parentSnapname, []byte{0})
	pSnapname := string(parentSnapname[:n])
	assert.Equal(t, pName, "parent", "they should be equal")
	assert.Equal(t, pSnapname, "mysnap", "they should be equal")

	pools, images, err = snapImg.ListChildren()
	assert.NoError(t, err)
	assert.Equal(t, len(pools), 1, "pools equal")
	assert.Equal(t, len(images), 1, "children length equal")

	err = imgNew.Close()
	assert.NoError(t, err)

	err = imgNew.Remove()
	assert.NoError(t, err)

	err = snapshot.Unprotect()
	assert.NoError(t, err)

	err = snapshot.Remove()
	assert.NoError(t, err)

	err = img.Close()
	assert.NoError(t, err)

	err = snapImg.Close()
	assert.NoError(t, err)

	err = img.Remove()
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestNotFound(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()

	img := rbd.GetImage(ioctx, name)
	err = img.Open()
	assert.Equal(t, err, rbd.RbdErrorNotFound)

	img.Remove()
	assert.Equal(t, err, rbd.RbdErrorNotFound)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}

func TestTrashImage(t *testing.T) {
	conn, _ := rados.NewConn()
	conn.ReadDefaultConfigFile()
	conn.Connect()

	poolname := GetUUID()
	err := conn.MakePool(poolname)
	assert.NoError(t, err)

	ioctx, err := conn.OpenIOContext(poolname)
	assert.NoError(t, err)

	name := GetUUID()
	image, err := rbd.Create(ioctx, name, 1<<22, 22)
	assert.NoError(t, err)

	err = image.Trash(time.Hour)
	assert.NoError(t, err)

	trashList, err := rbd.GetTrashList(ioctx)
	assert.NoError(t, err)
	assert.Equal(t, len(trashList), 1, "trashList length equal")

	err = rbd.TrashRestore(ioctx, trashList[0].Id, name+"_restored")
	assert.NoError(t, err)

	image2 := rbd.GetImage(ioctx, name+"_restored")
	err = image2.Trash(time.Hour)
	assert.NoError(t, err)

	trashList, err = rbd.GetTrashList(ioctx)
	assert.NoError(t, err)
	assert.Equal(t, len(trashList), 1, "trashList length equal")

	err = rbd.TrashRemove(ioctx, trashList[0].Id, false)
	assert.NoError(t, err)

	ioctx.Destroy()
	conn.DeletePool(poolname)
	conn.Shutdown()
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"runtime"
	"sync"
)

type pipeResult struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	// Reader sends on cr1, receives on cr2.
	// Writer does the same on cw1, cw2.
	r1, w1 chan []byte
	r2, w2 chan pipeResult

	rclose chan os.Error // read close; error to return to writers
	wclose chan os.Error // write close; error to return to readers

	done chan int // read or write half is done
}

func (p *pipe) run() {
	var (
		rb    []byte      // pending Read
		wb    []byte      // pending Write
		wn    int         // amount written so far from wb
		rerr  os.Error    // if read end is closed, error to send to writers
		werr  os.Error    // if write end is closed, error to send to readers
		r1    chan []byte // p.cr1 or nil depending on whether Read is ok
		w1    chan []byte // p.cw1 or nil depending on whether Write is ok
		ndone int
	)

	// Read and Write are enabled at the start.
	r1 = p.r1
	w1 = p.w1

	for {
		select {
		case <-p.done:
			if ndone++; ndone == 2 {
				// both reader and writer are gone
				return
			}
			continue
		case rerr = <-p.rclose:
			if w1 == nil {
				// finish pending Write
				p.w2 <- pipeResult{wn, rerr}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			if r1 == nil {
				// Close of read side during Read.
				// finish pending Read with os.EINVAL.
				p.r2 <- pipeResult{0, os.EINVAL}
				r1 = p.r1 // allow another Read
			}
			continue
		case werr = <-p.wclose:
			if r1 == nil {
				// finish pending Read
				p.r2 <- pipeResult{0, werr}
				r1 = p.r1 // allow another Read
			}
			if w1 == nil {
				// Close of write side during Write.
				// finish pending Write with os.EINVAL.
				p.w2 <- pipeResult{wn, os.EINVAL}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			continue
		case rb = <-r1:
			if werr != nil {
				// write end is closed
				p.r2 <- pipeResult{0, werr}
				continue
			}
			r1 = nil // disable Read until this one is done
		case wb = <-w1:
			if rerr != nil {
				// read end is closed
				p.w2 <- pipeResult{0, rerr}
				continue
			}
			w1 = nil // disable Write until this one is done
		}

		if r1 == nil && w1 == nil {
			// Have rb and wb.  Execute.
			n := copy(rb, wb)
			wn += n
			wb = wb[n:]

			// Finish Read.
			p.r2 <- pipeResult{n, nil}
			r1 = p.r1 // allow another Read

			// Maybe finish Write.
			if len(wb) == 0 {
				p.w2 <- pipeResult{wn, nil}
				wn = 0
				w1 = p.w1 // allow another Write
			}
		}
	}
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finalizer can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

type pipeHalf struct {
	c1     chan []byte
	c2     chan pipeResult
	cclose chan os.Error
	done   chan int

	lock   sync.Mutex
	closed bool

	io       sync.Mutex
	ioclosed bool
}

func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
	// Run i/o operation.
	// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
	p.io.Lock()
	defer p.io.Unlock()
	if p.ioclosed {
		return 0, os.EINVAL
	}
	p.c1 <- data
	res := <-p.c2
	return res.n, res.err
}

func (p *pipeHalf) close(err os.Error) os.Error {
	// Close pipe half.
	// Only first call to close does anything.
	p.lock.Lock()
	if p.closed {
		p.lock.Unlock()
		return os.EINVAL
	}
	p.closed = true
	p.lock.Unlock()

	// First, send the close notification.
	p.cclose <- err

	// Runner is now responding to rw operations
	// with os.EINVAL.  Cut off future rw operations
	// by setting ioclosed flag.
	p.io.Lock()
	p.ioclosed = true
	p.io.Unlock()

	// With ioclosed set, there will be no more rw operations
	// working on the channels.
	// Tell the runner we won't be bothering it anymore.
	p.done <- 1

	// Successfully torn down; can disable finalizer.
	runtime.SetFinalizer(p, nil)

	return nil
}

func (p *pipeHalf) finalizer() {
	p.close(os.EINVAL)
}

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	pipeHalf
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	return r.rw(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	return r.CloseWithError(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EPIPE
	}
	return r.close(err)
}

// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
	pipeHalf
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	return w.rw(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and os.EOF.
func (w *PipeWriter) Close() os.Error {
	return w.CloseWithError(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EOF
	}
	return w.close(err)
}

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		r1:     make(chan []byte),
		r2:     make(chan pipeResult),
		w1:     make(chan []byte),
		w2:     make(chan pipeResult),
		rclose: make(chan os.Error),
		wclose: make(chan os.Error),
		done:   make(chan int),
	}
	go p.run()

	// NOTE: Cannot use composite literal here:
	//	pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
	// because this implicitly copies the pipeHalf, which copies the inner mutex.

	r := new(PipeReader)
	r.c1 = p.r1
	r.c2 = p.r2
	r.cclose = p.rclose
	r.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(r, (*PipeReader).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&r.pipeHalf, (*pipeHalf).finalizer)

	w := new(PipeWriter)
	w.c1 = p.w1
	w.c2 = p.w2
	w.cclose = p.wclose
	w.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(w, (*PipeWriter).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&w.pipeHalf, (*pipeHalf).finalizer)

	return r, w
}
<commit_msg>io: Avoid race condition in pipe.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"runtime"
	"sync"
)

type pipeResult struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	// Reader sends on cr1, receives on cr2.
	// Writer does the same on cw1, cw2.
	r1, w1 chan []byte
	r2, w2 chan pipeResult

	rclose chan os.Error // read close; error to return to writers
	wclose chan os.Error // write close; error to return to readers

	done chan int // read or write half is done
}

func (p *pipe) run() {
	var (
		rb    []byte      // pending Read
		wb    []byte      // pending Write
		wn    int         // amount written so far from wb
		rerr  os.Error    // if read end is closed, error to send to writers
		werr  os.Error    // if write end is closed, error to send to readers
		r1    chan []byte // p.cr1 or nil depending on whether Read is ok
		w1    chan []byte // p.cw1 or nil depending on whether Write is ok
		ndone int
	)

	// Read and Write are enabled at the start.
	r1 = p.r1
	w1 = p.w1

	for {
		select {
		case <-p.done:
			if ndone++; ndone == 2 {
				// both reader and writer are gone
				return
			}
			continue
		case rerr = <-p.rclose:
			if w1 == nil {
				// finish pending Write
				p.w2 <- pipeResult{wn, rerr}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			if r1 == nil {
				// Close of read side during Read.
				// finish pending Read with os.EINVAL.
				p.r2 <- pipeResult{0, os.EINVAL}
				r1 = p.r1 // allow another Read
			}
			continue
		case werr = <-p.wclose:
			if r1 == nil {
				// finish pending Read
				p.r2 <- pipeResult{0, werr}
				r1 = p.r1 // allow another Read
			}
			if w1 == nil {
				// Close of write side during Write.
				// finish pending Write with os.EINVAL.
				p.w2 <- pipeResult{wn, os.EINVAL}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			continue
		case rb = <-r1:
			if werr != nil {
				// write end is closed
				p.r2 <- pipeResult{0, werr}
				continue
			}
			r1 = nil // disable Read until this one is done
		case wb = <-w1:
			if rerr != nil {
				// read end is closed
				p.w2 <- pipeResult{0, rerr}
				continue
			}
			w1 = nil // disable Write until this one is done
		}

		if r1 == nil && w1 == nil {
			// Have rb and wb.  Execute.
			n := copy(rb, wb)
			wn += n
			wb = wb[n:]

			// Finish Read.
			p.r2 <- pipeResult{n, nil}
			r1 = p.r1 // allow another Read

			// Maybe finish Write.
			if len(wb) == 0 {
				p.w2 <- pipeResult{wn, nil}
				wn = 0
				w1 = p.w1 // allow another Write
			}
		}
	}
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finalizer can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

type pipeHalf struct {
	c1     chan []byte
	c2     chan pipeResult
	cclose chan os.Error
	done   chan int

	lock   sync.Mutex
	closed bool

	io       sync.Mutex
	ioclosed bool
}

func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
	// Run i/o operation.
	// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
	p.io.Lock()
	if p.ioclosed {
		p.io.Unlock()
		return 0, os.EINVAL
	}
	p.io.Unlock()
	p.c1 <- data
	res := <-p.c2
	return res.n, res.err
}

func (p *pipeHalf) close(err os.Error) os.Error {
	// Close pipe half.
	// Only first call to close does anything.
	p.lock.Lock()
	if p.closed {
		p.lock.Unlock()
		return os.EINVAL
	}
	p.closed = true
	p.lock.Unlock()

	// First, send the close notification.
	p.cclose <- err

	// Runner is now responding to rw operations
	// with os.EINVAL.  Cut off future rw operations
	// by setting ioclosed flag.
	p.io.Lock()
	p.ioclosed = true
	p.io.Unlock()

	// With ioclosed set, there will be no more rw operations
	// working on the channels.
	// Tell the runner we won't be bothering it anymore.
	p.done <- 1

	// Successfully torn down; can disable finalizer.
	runtime.SetFinalizer(p, nil)

	return nil
}

func (p *pipeHalf) finalizer() {
	p.close(os.EINVAL)
}

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	pipeHalf
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	return r.rw(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	return r.CloseWithError(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EPIPE
	}
	return r.close(err)
}

// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
	pipeHalf
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	return w.rw(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and os.EOF.
func (w *PipeWriter) Close() os.Error {
	return w.CloseWithError(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EOF
	}
	return w.close(err)
}

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		r1:     make(chan []byte),
		r2:     make(chan pipeResult),
		w1:     make(chan []byte),
		w2:     make(chan pipeResult),
		rclose: make(chan os.Error),
		wclose: make(chan os.Error),
		done:   make(chan int),
	}
	go p.run()

	// NOTE: Cannot use composite literal here:
	//	pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
	// because this implicitly copies the pipeHalf, which copies the inner mutex.

	r := new(PipeReader)
	r.c1 = p.r1
	r.c2 = p.r2
	r.cclose = p.rclose
	r.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(r, (*PipeReader).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&r.pipeHalf, (*pipeHalf).finalizer)

	w := new(PipeWriter)
	w.c1 = p.w1
	w.c2 = p.w2
	w.cclose = p.wclose
	w.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(w, (*PipeWriter).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&w.pipeHalf, (*pipeHalf).finalizer)

	return r, w
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/miekg/dns"

	"golang.org/x/net/publicsuffix"
)

// handlePACFile serves an automatically-generated PAC (Proxy Auto-Config) file
// pointing to this proxy server.
func handlePACFile(w http.ResponseWriter, r *http.Request) {
	proxyAddr := r.Host

	if a := r.FormValue("a"); a != "" {
		if user, pass, ok := decodeBase64Credentials(a); ok {
			conf := getConfig()
			if conf.ValidCredentials(user, pass) {
				proxyForUserLock.RLock()
				p := proxyForUser[user]
				proxyForUserLock.RUnlock()
				if p != nil {
					client := r.RemoteAddr
					host, _, err := net.SplitHostPort(client)
					if err == nil {
						client = host
					}
					p.AllowIP(client)
					proxyHost, _, err := net.SplitHostPort(proxyAddr)
					if err == nil {
						proxyAddr = net.JoinHostPort(proxyHost, strconv.Itoa(p.Port))
					}
				}
			}
		}
	}

	w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
	fmt.Fprintf(w, pacTemplate, proxyAddr)
}

var pacTemplate = `function FindProxyForURL(url, host) {
	if (
		shExpMatch(url, "ftp:*") ||
		host == "localhost" ||
		isInNet(host, "127.0.0.0", "255.0.0.0") ||
		isInNet(host, "10.0.0.0", "255.0.0.0") ||
		isInNet(host, "172.16.0.0", "255.240.0.0") ||
		isInNet(host, "192.168.0.0", "255.255.0.0")
	) {
		return "DIRECT";
	}

	return "PROXY %s";
}`

type perUserProxy struct {
	User          string
	Port          int
	Handler       http.Handler
	allowedIPs    map[string]bool
	allowedIPLock sync.RWMutex

	expectedDomains  map[string]bool
	expectedIPBlocks []*net.IPNet
	ClientPlatform   string
	expectedNetLock  sync.RWMutex
}

func (p *perUserProxy) addExpectedNetwork(network string) {
	p.expectedNetLock.Lock()
	defer p.expectedNetLock.Unlock()
	if _, nw, err := net.ParseCIDR(network); err == nil {
		p.expectedIPBlocks = append(p.expectedIPBlocks, nw)
	} else if ip := net.ParseIP(network); ip != nil {
		if ip4 := ip.To4(); ip4 != nil {
			p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip4, Mask: net.CIDRMask(32, 32)})
		} else {
			p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)})
		}
	} else {
		domain, err := publicsuffix.EffectiveTLDPlusOne(network)
		if err != nil {
			domain = network
		}
		p.expectedDomains[domain] = true
	}
}

func (c *config) newPerUserProxy(user string, portInfo customPortInfo) (*perUserProxy, error) {
	p := &perUserProxy{
		User:            user,
		Port:            portInfo.Port,
		ClientPlatform:  portInfo.ClientPlatform,
		Handler:         proxyHandler{user: user},
		allowedIPs:      map[string]bool{},
		expectedDomains: map[string]bool{},
	}

	for _, network := range portInfo.ExpectedNetworks {
		p.addExpectedNetwork(network)
	}

	proxyForUserLock.Lock()
	proxyForUser[user] = p
	proxyForUserLock.Unlock()
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", portInfo.Port))
	if err != nil {
		return nil, err
	}
	listener = tcpKeepAliveListener{listener.(*net.TCPListener)}

	go func() {
		<-shutdownChan
		listener.Close()
	}()

	server := http.Server{
		Handler:     p,
		IdleTimeout: c.CloseIdleConnections,
	}
	go server.Serve(listener)
	log.Printf("opened per-user listener for %s on port %d", user, portInfo.Port)

	return p, nil
}

func (p *perUserProxy) AllowIP(ip string) {
	p.allowedIPLock.Lock()
	p.allowedIPs[ip] = true
	p.allowedIPLock.Unlock()
	log.Printf("Added IP address %s, authenticated as %s, on port %d", ip, p.User, p.Port)

	domain := rdnsDomain(ip)
	if domain != "" {
		p.expectedNetLock.Lock()
		alreadyExpected := p.expectedDomains[domain]
		if !alreadyExpected {
			p.expectedDomains[domain] = true
		}
		p.expectedNetLock.Unlock()
		if !alreadyExpected {
			log.Printf("Added %s to the list of expected domains on port %d", domain, p.Port)
		}
	}
}

// rdnsDomain returns the base domain name of ip's reverse-DNS hostname (or the
// empty string if it is unavailable).
func rdnsDomain(ip string) string {
	var host string
	names, err := net.LookupAddr(ip)
	if err == nil && len(names) > 0 {
		host = names[0]
	}
	if host == "" {
		// If a PTR record isn't available, fall back to SOA.
		host, _ = rdnsSOA(ip)
	}
	if host == "" {
		return ""
	}
	host = strings.TrimSuffix(host, ".")
	domain, err := publicsuffix.EffectiveTLDPlusOne(host)
	if err != nil {
		return host
	}
	return domain
}

var dnsServer string

func init() {
	conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
	if err != nil || len(conf.Servers) == 0 {
		return
	}
	dnsServer = conf.Servers[0] + ":" + conf.Port
}

// rdnsSOA returns the nameserver from the SOA (start of authority) reverse-DNS
// record for ip.
func rdnsSOA(ip string) (server string, err error) {
	octets := strings.Split(ip, ".")
	if len(octets) != 4 {
		return "", errors.New("invalid IPv4 address")
	}
	octets[0], octets[1], octets[2], octets[3] = octets[3], octets[2], octets[1], octets[0]

	m := new(dns.Msg)

	for i := 0; i < 4; i++ {
		m.SetQuestion(strings.Join(octets[i:], ".")+".in-addr.arpa.", dns.TypeSOA)
		soa, err := dns.Exchange(m, dnsServer)
		if err != nil {
			return "", err
		}
		if soa.Rcode != dns.RcodeSuccess || len(soa.Answer) == 0 {
			continue
		}
		trsoa, ok := soa.Answer[0].(*dns.SOA)
		if !ok {
			continue
		}
		return trsoa.Ns, nil
	}

	return "", errors.New("SOA not found")
}

func (p *perUserProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	p.allowedIPLock.RLock()
	ok := p.allowedIPs[host]
	p.allowedIPLock.RUnlock()

	if ok {
		p.Handler.ServeHTTP(w, r)
		return
	}

	// This client's IP address is not pre-authorized for this port, but
	// maybe it sent credentials and we can authorize it now.
	// We accept credentials in either the Proxy-Authorization header or
	// a URL parameter named "a".
	conf := getConfig()

	user, pass, ok := ProxyCredentials(r)
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in Proxy-Authorization header from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	user, pass, ok = decodeBase64Credentials(r.FormValue("a"))
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in URL parameter from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	expectedNetwork := false
	ip := net.ParseIP(host)
	p.expectedNetLock.RLock()
	expectedPlatform := p.ClientPlatform
	for _, nw := range p.expectedIPBlocks {
		if nw.Contains(ip) {
			expectedNetwork = true
			break
		}
	}
	p.expectedNetLock.RUnlock()

	domain := rdnsDomain(host)
	if !expectedNetwork && domain != "" {
		p.expectedNetLock.RLock()
		expectedNetwork = p.expectedDomains[domain]
		p.expectedNetLock.RUnlock()
	}

	if expectedNetwork {
		pf := platform(r.Header.Get("User-Agent"))
		if expectedPlatform != "" && pf == expectedPlatform || darwinPlatforms[expectedPlatform] && pf == "Darwin" {
			log.Printf("Authenticating %s as %s based on IP address and platform (domain=%s, platform=%s, user-agent=%q, port=%d)", host, p.User, domain, expectedPlatform, r.Header.Get("User-Agent"), p.Port)
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		}
	}

	// Maybe this is a request where authentication isn't even required according
	// to the ACLs. If so, let it through, but don't mark the IP address as
	// authenticated.
	tally := conf.URLRules.MatchingRules(r.URL)
	scores := conf.categoryScores(tally)
	categories := conf.significantCategories(scores)
	reqACLs := conf.ACLs.requestACLs(r, "")
	thisRule, _ := conf.ChooseACLCategoryAction(reqACLs, categories, "allow", "require-auth")
	if thisRule.Action != "require-auth" {
		log.Printf("Allowing request in spite of missing authentication (url=%v, user=%s, port=%d, client=%s)", r.URL, p.User, p.Port, r.RemoteAddr)
		p.Handler.ServeHTTP(w, r)
		return
	}

	log.Printf("Missing required proxy authentication from %v to %v (User-Agent=%q, domain=%s, port=%d)", r.RemoteAddr, r.URL, r.Header.Get("User-Agent"), domain, p.Port)
	conf.send407(w)
}

var proxyForUser = make(map[string]*perUserProxy)
var proxyForUserLock sync.RWMutex

func (c *config) openPerUserPorts() {
	for user, portInfo := range c.CustomPorts {
		proxyForUserLock.RLock()
		p := proxyForUser[user]
		proxyForUserLock.RUnlock()
		if p == nil {
			_, err := c.newPerUserProxy(user, portInfo)
			if err != nil {
				log.Printf("error opening per-user listener for %s: %v", user, err)
			}
		} else {
			for _, network := range portInfo.ExpectedNetworks {
				p.addExpectedNetwork(network)
			}
			if portInfo.ClientPlatform != "" {
				p.expectedNetLock.Lock()
				p.ClientPlatform = portInfo.ClientPlatform
				p.expectedNetLock.Unlock()
			}
		}
	}
}

type portListEntry struct {
	User                 string
	Port                 int
	Platform             string
	AuthenticatedClients []string
	ExpectedNetworks     []string
}

func handlePerUserPortList(w http.ResponseWriter, r *http.Request) {
	var data []portListEntry

	proxyForUserLock.RLock()

	for _, p := range proxyForUser {
		var clients []string
		p.allowedIPLock.RLock()

		for c := range p.allowedIPs {
			clients = append(clients, c)
		}

		p.allowedIPLock.RUnlock()

		var networks []string
		p.expectedNetLock.RLock()
		for d := range p.expectedDomains {
			networks = append(networks, d)
		}
		for _, nw := range p.expectedIPBlocks {
			networks = append(networks, nw.String())
		}
		clientPlatform := p.ClientPlatform
		p.expectedNetLock.RUnlock()

		data = append(data, portListEntry{
			User:                 p.User,
			Port:                 p.Port,
			Platform:             clientPlatform,
			AuthenticatedClients: clients,
			ExpectedNetworks:     networks,
		})
	}

	proxyForUserLock.RUnlock()

	ServeJSON(w, r, data)
}

func handlePerUserAuthenticate(w http.ResponseWriter, r *http.Request) {
	user := r.FormValue("user")
	if user == "" {
		http.Error(w, `You must specify which user to authenticate with the "user" form parameter.`, 400)
		return
	}
	proxyForUserLock.RLock()
	p := proxyForUser[user]
	proxyForUserLock.RUnlock()
	if p == nil {
		http.Error(w, user+" does not have a per-user proxy port set up.", 500)
		return
	}

	ip := r.FormValue("ip")
	if ip == "" {
		http.Error(w, `You must specify the client IP address with the "ip" form parameter.`, 400)
		return
	}

	p.AllowIP(ip)
	fmt.Fprintf(w, "Added %s as an authenticated IP address for %s.", ip, user)
}
<commit_msg>Fix memory leak when reloading expected network list.<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/miekg/dns"

	"golang.org/x/net/publicsuffix"
)

// handlePACFile serves an automatically-generated PAC (Proxy Auto-Config) file
// pointing to this proxy server.
func handlePACFile(w http.ResponseWriter, r *http.Request) {
	proxyAddr := r.Host

	if a := r.FormValue("a"); a != "" {
		if user, pass, ok := decodeBase64Credentials(a); ok {
			conf := getConfig()
			if conf.ValidCredentials(user, pass) {
				proxyForUserLock.RLock()
				p := proxyForUser[user]
				proxyForUserLock.RUnlock()
				if p != nil {
					client := r.RemoteAddr
					host, _, err := net.SplitHostPort(client)
					if err == nil {
						client = host
					}
					p.AllowIP(client)
					proxyHost, _, err := net.SplitHostPort(proxyAddr)
					if err == nil {
						proxyAddr = net.JoinHostPort(proxyHost, strconv.Itoa(p.Port))
					}
				}
			}
		}
	}

	w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
	fmt.Fprintf(w, pacTemplate, proxyAddr)
}

var pacTemplate = `function FindProxyForURL(url, host) {
	if (
		shExpMatch(url, "ftp:*") ||
		host == "localhost" ||
		isInNet(host, "127.0.0.0", "255.0.0.0") ||
		isInNet(host, "10.0.0.0", "255.0.0.0") ||
		isInNet(host, "172.16.0.0", "255.240.0.0") ||
		isInNet(host, "192.168.0.0", "255.255.0.0")
	) {
		return "DIRECT";
	}

	return "PROXY %s";
}`

type perUserProxy struct {
	User          string
	Port          int
	Handler       http.Handler
	allowedIPs    map[string]bool
	allowedIPLock sync.RWMutex

	expectedDomains  map[string]bool
	expectedIPBlocks []*net.IPNet
	ClientPlatform   string
	expectedNetLock  sync.RWMutex
}

func (p *perUserProxy) addExpectedNetwork(network string) {
	p.expectedNetLock.Lock()
	defer p.expectedNetLock.Unlock()
	if _, nw, err := net.ParseCIDR(network); err == nil {
		p.expectedIPBlocks = append(p.expectedIPBlocks, nw)
	} else if ip := net.ParseIP(network); ip != nil {
		if ip4 := ip.To4(); ip4 != nil {
			p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip4, Mask: net.CIDRMask(32, 32)})
		} else {
			p.expectedIPBlocks = append(p.expectedIPBlocks, &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)})
		}
	} else {
		domain, err := publicsuffix.EffectiveTLDPlusOne(network)
		if err != nil {
			domain = network
		}
		p.expectedDomains[domain] = true
	}
}

func (c *config) newPerUserProxy(user string, portInfo customPortInfo) (*perUserProxy, error) {
	p := &perUserProxy{
		User:            user,
		Port:            portInfo.Port,
		ClientPlatform:  portInfo.ClientPlatform,
		Handler:         proxyHandler{user: user},
		allowedIPs:      map[string]bool{},
		expectedDomains: map[string]bool{},
	}

	for _, network := range portInfo.ExpectedNetworks {
		p.addExpectedNetwork(network)
	}

	proxyForUserLock.Lock()
	proxyForUser[user] = p
	proxyForUserLock.Unlock()
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", portInfo.Port))
	if err != nil {
		return nil, err
	}
	listener = tcpKeepAliveListener{listener.(*net.TCPListener)}

	go func() {
		<-shutdownChan
		listener.Close()
	}()

	server := http.Server{
		Handler:     p,
		IdleTimeout: c.CloseIdleConnections,
	}
	go server.Serve(listener)
	log.Printf("opened per-user listener for %s on port %d", user, portInfo.Port)

	return p, nil
}

func (p *perUserProxy) AllowIP(ip string) {
	p.allowedIPLock.Lock()
	p.allowedIPs[ip] = true
	p.allowedIPLock.Unlock()
	log.Printf("Added IP address %s, authenticated as %s, on port %d", ip, p.User, p.Port)

	domain := rdnsDomain(ip)
	if domain != "" {
		p.expectedNetLock.Lock()
		alreadyExpected := p.expectedDomains[domain]
		if !alreadyExpected {
			p.expectedDomains[domain] = true
		}
		p.expectedNetLock.Unlock()
		if !alreadyExpected {
			log.Printf("Added %s to the list of expected domains on port %d", domain, p.Port)
		}
	}
}

// rdnsDomain returns the base domain name of ip's reverse-DNS hostname (or the
// empty string if it is unavailable).
func rdnsDomain(ip string) string {
	var host string
	names, err := net.LookupAddr(ip)
	if err == nil && len(names) > 0 {
		host = names[0]
	}
	if host == "" {
		// If a PTR record isn't available, fall back to SOA.
		host, _ = rdnsSOA(ip)
	}
	if host == "" {
		return ""
	}
	host = strings.TrimSuffix(host, ".")
	domain, err := publicsuffix.EffectiveTLDPlusOne(host)
	if err != nil {
		return host
	}
	return domain
}

var dnsServer string

func init() {
	conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
	if err != nil || len(conf.Servers) == 0 {
		return
	}
	dnsServer = conf.Servers[0] + ":" + conf.Port
}

// rdnsSOA returns the nameserver from the SOA (start of authority) reverse-DNS
// record for ip.
func rdnsSOA(ip string) (server string, err error) {
	octets := strings.Split(ip, ".")
	if len(octets) != 4 {
		return "", errors.New("invalid IPv4 address")
	}
	octets[0], octets[1], octets[2], octets[3] = octets[3], octets[2], octets[1], octets[0]

	m := new(dns.Msg)

	for i := 0; i < 4; i++ {
		m.SetQuestion(strings.Join(octets[i:], ".")+".in-addr.arpa.", dns.TypeSOA)
		soa, err := dns.Exchange(m, dnsServer)
		if err != nil {
			return "", err
		}
		if soa.Rcode != dns.RcodeSuccess || len(soa.Answer) == 0 {
			continue
		}
		trsoa, ok := soa.Answer[0].(*dns.SOA)
		if !ok {
			continue
		}
		return trsoa.Ns, nil
	}

	return "", errors.New("SOA not found")
}

func (p *perUserProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	p.allowedIPLock.RLock()
	ok := p.allowedIPs[host]
	p.allowedIPLock.RUnlock()

	if ok {
		p.Handler.ServeHTTP(w, r)
		return
	}

	// This client's IP address is not pre-authorized for this port, but
	// maybe it sent credentials and we can authorize it now.
	// We accept credentials in either the Proxy-Authorization header or
	// a URL parameter named "a".
	conf := getConfig()

	user, pass, ok := ProxyCredentials(r)
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in Proxy-Authorization header from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	user, pass, ok = decodeBase64Credentials(r.FormValue("a"))
	if ok {
		if user == p.User && conf.ValidCredentials(user, pass) {
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		} else {
			log.Printf("Incorrect username or password in URL parameter from %v: %s:%s, on port %d", r.RemoteAddr, user, pass, p.Port)
		}
	}

	expectedNetwork := false
	ip := net.ParseIP(host)
	p.expectedNetLock.RLock()
	expectedPlatform := p.ClientPlatform
	for _, nw := range p.expectedIPBlocks {
		if nw.Contains(ip) {
			expectedNetwork = true
			break
		}
	}
	p.expectedNetLock.RUnlock()

	domain := rdnsDomain(host)
	if !expectedNetwork && domain != "" {
		p.expectedNetLock.RLock()
		expectedNetwork = p.expectedDomains[domain]
		p.expectedNetLock.RUnlock()
	}

	if expectedNetwork {
		pf := platform(r.Header.Get("User-Agent"))
		if expectedPlatform != "" && pf == expectedPlatform || darwinPlatforms[expectedPlatform] && pf == "Darwin" {
			log.Printf("Authenticating %s as %s based on IP address and platform (domain=%s, platform=%s, user-agent=%q, port=%d)", host, p.User, domain, expectedPlatform, r.Header.Get("User-Agent"), p.Port)
			p.AllowIP(host)
			p.Handler.ServeHTTP(w, r)
			return
		}
	}

	// Maybe this is a request where authentication isn't even required according
	// to the ACLs. If so, let it through, but don't mark the IP address as
	// authenticated.
	tally := conf.URLRules.MatchingRules(r.URL)
	scores := conf.categoryScores(tally)
	categories := conf.significantCategories(scores)
	reqACLs := conf.ACLs.requestACLs(r, "")
	thisRule, _ := conf.ChooseACLCategoryAction(reqACLs, categories, "allow", "require-auth")
	if thisRule.Action != "require-auth" {
		log.Printf("Allowing request in spite of missing authentication (url=%v, user=%s, port=%d, client=%s)", r.URL, p.User, p.Port, r.RemoteAddr)
		p.Handler.ServeHTTP(w, r)
		return
	}

	log.Printf("Missing required proxy authentication from %v to %v (User-Agent=%q, domain=%s, port=%d)", r.RemoteAddr, r.URL, r.Header.Get("User-Agent"), domain, p.Port)
	conf.send407(w)
}

var proxyForUser = make(map[string]*perUserProxy)
var proxyForUserLock sync.RWMutex

func (c *config) openPerUserPorts() {
	for user, portInfo := range c.CustomPorts {
		proxyForUserLock.RLock()
		p := proxyForUser[user]
		proxyForUserLock.RUnlock()
		if p == nil {
			_, err := c.newPerUserProxy(user, portInfo)
			if err != nil {
				log.Printf("error opening per-user listener for %s: %v", user, err)
			}
		} else {
			p.expectedNetLock.Lock()
			p.ClientPlatform = portInfo.ClientPlatform
			p.expectedIPBlocks = p.expectedIPBlocks[:0]
			p.expectedNetLock.Unlock()
			for _, network := range portInfo.ExpectedNetworks {
				p.addExpectedNetwork(network)
			}
		}
	}
}

type portListEntry struct {
	User                 string
	Port                 int
	Platform             string
	AuthenticatedClients []string
	ExpectedNetworks     []string
}

func handlePerUserPortList(w http.ResponseWriter, r *http.Request) {
	var data []portListEntry

	proxyForUserLock.RLock()

	for _, p := range proxyForUser {
		var clients []string
		p.allowedIPLock.RLock()

		for c := range p.allowedIPs {
			clients = append(clients, c)
		}

		p.allowedIPLock.RUnlock()

		var networks []string
		p.expectedNetLock.RLock()
		for d := range p.expectedDomains {
			networks = append(networks, d)
		}
		for _, nw := range p.expectedIPBlocks {
			networks = append(networks, nw.String())
		}
		clientPlatform := p.ClientPlatform
		p.expectedNetLock.RUnlock()

		data = append(data, portListEntry{
			User:                 p.User,
			Port:                 p.Port,
			Platform:             clientPlatform,
			AuthenticatedClients: clients,
			ExpectedNetworks:     networks,
		})
	}

	proxyForUserLock.RUnlock()

	ServeJSON(w, r, data)
}

func handlePerUserAuthenticate(w http.ResponseWriter, r *http.Request) {
	user := r.FormValue("user")
	if user == "" {
		http.Error(w, `You must specify which user to authenticate with the "user" form parameter.`, 400)
		return
	}
	proxyForUserLock.RLock()
	p := proxyForUser[user]
	proxyForUserLock.RUnlock()
	if p == nil {
		http.Error(w, user+" does not have a per-user proxy port set up.", 500)
		return
	}

	ip := r.FormValue("ip")
	if ip == "" {
		http.Error(w, `You must specify the client IP address with the "ip" form parameter.`, 400)
		return
	}

	p.AllowIP(ip)
	fmt.Fprintf(w, "Added %s as an authenticated IP address for %s.", ip, user)
}
<|endoftext|>


<commit_before>package translation

import "io"

type DeltaType int

const (
	DeltaUnmodified DeltaType = iota
	DeltaAdded
	DeltaDeleted
	DeltaModified
	DeltaRenamed
	DeltaCopied
)

type Delta struct {
	rsync.Operation
	OldPath, NewPath string
	Type             DeltaType
}

type Session struct {
	Socket
	Command string
}

type Variant interface {
	Diff(target io.ReadSeeker) (<-chan Delta, error)
	Patch(target io.WriteCloser, patch <-chan Delta) error
}

type Translator interface {
	TranslateRdiff(rdiff chan<- Delta) (translatedRdiff <-chan Delta, err error)
	TranslateRdiffToRexec(rdiff chan<- Delta) (session *Session, err error)
}
<commit_msg>refactor: renamed Variant to Object<commit_after>package translation

import "io"

type DeltaType int

const (
	DeltaUnmodified DeltaType = iota
	DeltaAdded
	DeltaDeleted
	DeltaModified
	DeltaRenamed
	DeltaCopied
)

type Delta struct {
	rsync.Operation
	OldPath, NewPath string
	Type             DeltaType
}

type Session struct {
	Socket
	Command string
}

type Object interface {
	Diff(target io.ReadSeeker) (<-chan Delta, error)
	Patch(target io.WriteCloser, patch <-chan Delta) error
}

type Translator interface {
	TranslateRdiff(rdiff chan<- Delta) (translatedRdiff <-chan Delta, err error)
	TranslateRdiffToRexec(rdiff chan<- Delta) (session *Session, err error)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	_ "github.com/bmizerany/pq"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"strconv"
)

var (
	port   = flag.Int("port", 7979, "Server Port")
	DbConn = setupDb()
)

const (
	ConnString = "user=postgres dbname=dataviewer"
)

type Hdl func(w http.ResponseWriter, r *http.Request)
type Parcel struct {
	OpaNum int `json:"opa"`
}

func setupDb() (db *sql.DB) {
	db, err := sql.Open("postgres", ConnString)
	if err != nil {
		log.Fatalf("Bad db conn: %v", err)
	}
	return
}

func ParcelMarshal(w http.ResponseWriter, p *Parcel, err error) {
	if err != nil {
		fmt.Println(err)
		http.Error(w, "Could not find parcel", 404)
		return
	}

	b, _ := json.Marshal(p)
	w.Write(b)
}

func ByCoords(w http.ResponseWriter, r *http.Request) {
	lat, err := strconv.ParseFloat(r.FormValue("lat"), 32)
	if err != nil {
		http.Error(w, "Bad 'lat' value", 500)
		return
	}
	lon, err := strconv.ParseFloat(r.FormValue("lon"), 32)
	if err != nil {
		http.Error(w, "Bad 'lon' value", 500)
		return
	}

	pt := fmt.Sprintf("POINT (%f %f)", lon, lat)
	sql := `SELECT brt_id
            FROM pwd_parcels
            WHERE ST_Intersects(ST_GeomFromText($1, 4326), geom) = true;`
	s, err := DbConn.Prepare(sql)
	var p Parcel
	fmt.Println(pt)
	if err != nil {
		fmt.Println(err)
	}
	err = s.QueryRow(pt).Scan(&p.OpaNum)
	ParcelMarshal(w, &p, err)
}

func main() {
	flag.Parse()
	defer DbConn.Close()

	r := mux.NewRouter()
	api := r.PathPrefix("/api/v0.1").Subrouter()
	api.HandleFunc("/parcel/", ByCoords).Queries("lat", "", "lon", "")
	//api.Handle("/parcel/", ByAddress).Queries("address", "")
	//api.Handle("/parcel/", ByRegMap).Queries("regmap", "")
	//api.Handle("/parcel/", ByOpa).Queries("opa", "")

	http.Handle("/", r)
	p := strconv.Itoa(*port)
	if err := http.ListenAndServe(":"+p, nil); err != nil {
		fmt.Println("Failed to start server: %v", err)
	} else {
		fmt.Println("Serving on port: " + p)
	}
}
<commit_msg>Database config from settings file<commit_after>package main

import (
	"code.google.com/p/gcfg"
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	_ "github.com/bmizerany/pq"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"strconv"
)

type Hdl func(w http.ResponseWriter, r *http.Request)
type Parcel struct {
	OpaNum int `json:"opa"`
}

type Config struct {
	Database struct {
		Name string
		User string
	}
}

var (
	port       = flag.Int("port", 7979, "Server Port")
	DbConn     *sql.DB
	ConnString string
)

func setupDb() (db *sql.DB) {
	db, err := sql.Open("postgres", ConnString)
	if err != nil {
		log.Fatalf("Bad db conn: %v", err)
	}
	return
}

func ParcelMarshal(w http.ResponseWriter, p *Parcel, err error) {
	if err != nil {
		fmt.Println(err)
		http.Error(w, "Could not find parcel", 404)
		return
	}

	b, _ := json.Marshal(p)
	w.Write(b)
}

func ByCoords(w http.ResponseWriter, r *http.Request) {
	lat, err := strconv.ParseFloat(r.FormValue("lat"), 32)
	if err != nil {
		http.Error(w, "Bad 'lat' value", 500)
		return
	}
	lon, err := strconv.ParseFloat(r.FormValue("lon"), 32)
	if err != nil {
		http.Error(w, "Bad 'lon' value", 500)
		return
	}

	pt := fmt.Sprintf("POINT (%f %f)", lon, lat)
	sql := `SELECT brt_id
            FROM pwd_parcels
            WHERE ST_Intersects(ST_GeomFromText($1, 4326), geom) = true;`
	s, err := DbConn.Prepare(sql)
	var p Parcel
	fmt.Println(pt)
	if err != nil {
		fmt.Println(err)
	}
	err = s.QueryRow(pt).Scan(&p.OpaNum)
	ParcelMarshal(w, &p, err)
}

func main() {
	flag.Parse()
	defer DbConn.Close()

	var conf Config
	err := gcfg.ReadFileInto(&conf, "settings.conf")
	if err != nil {
		fmt.Println("Invalid setting.conf file", err)
		return
	}
	ConnString = fmt.Sprintf("user=%s dbname=%s", conf.Database.User, conf.Database.Name)
	DbConn = setupDb()

	r := mux.NewRouter()
	api := r.PathPrefix("/api/v0.1").Subrouter()
	api.StrictSlash(false)
	api.HandleFunc("/parcel/", ByCoords).Queries("lat", "", "lon", "")
	//api.Handle("/parcel/", ByAddress).Queries("address", "")
	//api.Handle("/parcel/", ByRegMap).Queries("regmap", "")
	//api.Handle("/parcel/", ByOpa).Queries("opa", "")

	http.Handle("/", r)
	p := strconv.Itoa(*port)
	if err := http.ListenAndServe(":"+p, nil); err != nil {
		fmt.Println("Failed to start server: %v", err)
	} else {
		fmt.Println("Serving on port: " + p)
	}
}
<|endoftext|>


<commit_before>// Package raw enables reading and writing data at the device driver level for
// a network interface.
package raw

import (
	"errors"
	"net"
	"time"

	"golang.org/x/net/bpf"
)

const (
	// Maximum read timeout per syscall.
	// It is required because read/recvfrom won't be interrupted on closing of the file descriptor.
	readTimeout = 200 * time.Millisecond
)

var (
	// ErrNotImplemented is returned when certain functionality is not yet
	// implemented for the host operating system.
	ErrNotImplemented = errors.New("raw: not implemented")
)

var _ net.Addr = &Addr{}

// Addr is a network address which can be used to contact other machines, using
// their hardware addresses.
type Addr struct {
	HardwareAddr net.HardwareAddr
}

// Network returns the address's network name, "raw".
func (a *Addr) Network() string {
	return "raw"
}

// String returns the address's hardware address.
func (a *Addr) String() string {
	return a.HardwareAddr.String()
}

var _ net.PacketConn = &Conn{}

// Conn is an implementation of the net.PacketConn interface which can send
// and receive data at the network interface device driver level.
type Conn struct {
	// packetConn is the operating system-specific implementation of
	// a raw connection.
	p *packetConn
}

// ReadFrom implements the net.PacketConn ReadFrom method.
func (c *Conn) ReadFrom(b []byte) (int, net.Addr, error) {
	return c.p.ReadFrom(b)
}

// WriteTo implements the net.PacketConn WriteTo method.
func (c *Conn) WriteTo(b []byte, addr net.Addr) (int, error) {
	return c.p.WriteTo(b, addr)
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.p.Close()
}

// LocalAddr returns the local network address.
func (c *Conn) LocalAddr() net.Addr {
	return c.p.LocalAddr()
}

// SetDeadline implements the net.PacketConn SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
	return c.p.SetDeadline(t)
}

// SetReadDeadline implements the net.PacketConn SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.p.SetReadDeadline(t)
}

// SetWriteDeadline implements the net.PacketConn SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.p.SetWriteDeadline(t)
}

var _ bpf.Setter = &Conn{}

// SetBPF attaches an assembled BPF program to the connection.
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
	return c.p.SetBPF(filter)
}

// SetPromiscuous enables or disables promiscuous mode on the interface, allowing it
// to receive traffic that is not addressed to the interface.
func (c *Conn) SetPromiscuous(b bool) error {
	return c.p.SetPromiscuous(b)
}

// A Protocol is a network protocol constant which identifies the type of
// traffic a raw socket should send and receive.
type Protocol uint16

// ListenPacket creates a net.PacketConn which can be used to send and receive
// data at the network interface device driver level.
//
// ifi specifies the network interface which will be used to send and receive
// data.  proto specifies the protocol (usually the EtherType) which should be
// captured and transmitted.  proto, if needed, is automatically converted to
// network byte order (big endian), akin to the htons() function in C.
func ListenPacket(ifi *net.Interface, proto uint16) (*Conn, error) {
	p, err := listenPacket(ifi, proto)
	if err != nil {
		return nil, err
	}

	return &Conn{
		p: p,
	}, nil
}

// htons converts a short (uint16) from host-to-network byte order.
// Thanks to mikioh for this neat trick:
// https://github.com/mikioh/-stdyng/blob/master/afpacket.go
func htons(i uint16) uint16 {
	return (i<<8)&0xff00 | i>>8
}

// Copyright (c) 2012 The Go Authors. All rights reserved.
// Source code in this file is based on src/net/interface_linux.go,
// from the Go standard library.  The Go license can be found here:
// https://golang.org/LICENSE.

// Taken from:
// https://github.com/golang/go/blob/master/src/net/net.go#L417-L421.
type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }
<commit_msg>raw: actually remove Protocol<commit_after>// Package raw enables reading and writing data at the device driver level for
// a network interface.
package raw

import (
	"errors"
	"net"
	"time"

	"golang.org/x/net/bpf"
)

const (
	// Maximum read timeout per syscall.
	// It is required because read/recvfrom won't be interrupted on closing of the file descriptor.
	readTimeout = 200 * time.Millisecond
)

var (
	// ErrNotImplemented is returned when certain functionality is not yet
	// implemented for the host operating system.
	ErrNotImplemented = errors.New("raw: not implemented")
)

var _ net.Addr = &Addr{}

// Addr is a network address which can be used to contact other machines, using
// their hardware addresses.
type Addr struct {
	HardwareAddr net.HardwareAddr
}

// Network returns the address's network name, "raw".
func (a *Addr) Network() string {
	return "raw"
}

// String returns the address's hardware address.
func (a *Addr) String() string {
	return a.HardwareAddr.String()
}

var _ net.PacketConn = &Conn{}

// Conn is an implementation of the net.PacketConn interface which can send
// and receive data at the network interface device driver level.
type Conn struct {
	// packetConn is the operating system-specific implementation of
	// a raw connection.
	p *packetConn
}

// ReadFrom implements the net.PacketConn ReadFrom method.
func (c *Conn) ReadFrom(b []byte) (int, net.Addr, error) {
	return c.p.ReadFrom(b)
}

// WriteTo implements the net.PacketConn WriteTo method.
func (c *Conn) WriteTo(b []byte, addr net.Addr) (int, error) {
	return c.p.WriteTo(b, addr)
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.p.Close()
}

// LocalAddr returns the local network address.
func (c *Conn) LocalAddr() net.Addr {
	return c.p.LocalAddr()
}

// SetDeadline implements the net.PacketConn SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
	return c.p.SetDeadline(t)
}

// SetReadDeadline implements the net.PacketConn SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.p.SetReadDeadline(t)
}

// SetWriteDeadline implements the net.PacketConn SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.p.SetWriteDeadline(t)
}

var _ bpf.Setter = &Conn{}

// SetBPF attaches an assembled BPF program to the connection.
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
	return c.p.SetBPF(filter)
}

// SetPromiscuous enables or disables promiscuous mode on the interface, allowing it
// to receive traffic that is not addressed to the interface.
func (c *Conn) SetPromiscuous(b bool) error {
	return c.p.SetPromiscuous(b)
}

// ListenPacket creates a net.PacketConn which can be used to send and receive
// data at the network interface device driver level.
//
// ifi specifies the network interface which will be used to send and receive
// data.  proto specifies the protocol (usually the EtherType) which should be
// captured and transmitted.  proto, if needed, is automatically converted to
// network byte order (big endian), akin to the htons() function in C.
func ListenPacket(ifi *net.Interface, proto uint16) (*Conn, error) {
	p, err := listenPacket(ifi, proto)
	if err != nil {
		return nil, err
	}

	return &Conn{
		p: p,
	}, nil
}

// htons converts a short (uint16) from host-to-network byte order.
// Thanks to mikioh for this neat trick:
// https://github.com/mikioh/-stdyng/blob/master/afpacket.go
func htons(i uint16) uint16 {
	return (i<<8)&0xff00 | i>>8
}

// Copyright (c) 2012 The Go Authors. All rights reserved.
// Source code in this file is based on src/net/interface_linux.go,
// from the Go standard library.  The Go license can be found here:
// https://golang.org/LICENSE.

// Taken from:
// https://github.com/golang/go/blob/master/src/net/net.go#L417-L421.
type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }
<|endoftext|>


<commit_before>/*
Copyright 2019 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rdt

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/ghodss/yaml"

	pkgcfg "github.com/intel/cri-resource-manager/pkg/config"
	logger "github.com/intel/cri-resource-manager/pkg/log"
	"github.com/intel/cri-resource-manager/pkg/utils"
)

const resctrlGroupPrefix = "cri-resmgr."

// Control is the interface managing Intel RDT resources
type Control interface {
	// GetClasses returns the names of RDT classes (or resctrl control groups)
	// available
	GetClasses() []string

	// SetProcessClass assigns a set of processes to a RDT class
	SetProcessClass(string, ...string) error
}

var rdtInfo Info

type control struct {
	logger.Logger

	conf config
}

type config struct {
	Options       SchemaOptions                 `json:"options,omitempty"`
	ResctrlGroups map[string]ResctrlGroupConfig `json:"resctrlGroups"`
}

// NewControl returns new instance of the RDT Control interface
func NewControl(resctrlpath string, config string) (Control, error) {
	var err error
	r := &control{Logger: logger.NewLogger("rdt")}

	// Get info from the resctrl filesystem
	rdtInfo, err = getRdtInfo(resctrlpath)
	if err != nil {
		return nil, err
	}

	// Configure resctrl
	r.conf = opt.Config
	if err := r.configureResctrl(r.conf); err != nil {
		return nil, rdtError("configuration failed: %v", err)
	}

	pkgcfg.GetModule("rdt").AddNotify(r.configNotify)

	return r, nil
}

func (r *control) GetClasses() []string {
	ret := make([]string, len(r.conf.ResctrlGroups))

	i := 0
	for k := range r.conf.ResctrlGroups {
		ret[i] = k
		i++
	}
	sort.Strings(ret)
	return ret
}

func (r *control) SetProcessClass(class string, pids ...string) error {
	if _, ok := r.conf.ResctrlGroups[class]; !ok {
		return rdtError("unknown RDT class %q", class)
	}

	path := filepath.Join(r.resctrlGroupPath(class), "tasks")
	f, err := os.OpenFile(path, os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	for _, pid := range pids {
		if _, err := f.WriteString(pid + "\n"); err != nil {
			unwrapped := err
			if pathError, ok := err.(*os.PathError); ok {
				unwrapped = pathError.Unwrap()
			}
			if unwrapped == syscall.ESRCH {
				r.Debug("no task %s", pid)
			} else {
				return rdtError("failed to assign processes %v to class %q: %v", pids, class, r.cmdError(err))
			}
		}
	}
	return nil
}

func (r *control) configNotify(event pkgcfg.Event, source pkgcfg.Source) error {
	r.Info("configuration %s", event)

	err := r.configureResctrl(opt.Config)
	if err != nil {
		return rdtError("resctrl configuration failed: %v", err)
	}

	r.conf = opt.Config

	return nil
}

func (r *control) configureResctrl(conf config) error {
	r.Debug("applying new configuration:\n%s", utils.DumpJSON(conf))

	// Remove stale resctrl groups
	existingGroups, err := r.getResctrlGroups()
	if err != nil {
		return err
	}

	for _, name := range existingGroups {
		if _, ok := conf.ResctrlGroups[name]; !ok {
			tasks, err := r.resctrlGroupTasks(name)
			if err != nil {
				return rdtError("failed to get resctrl group tasks: %v", err)
			}
			path := r.resctrlGroupPath(name)
			if len(tasks) > 0 {
				return rdtError("refusing to remove non-empty resctrl group %q", path)
			}
			err = os.Remove(path)
			if err != nil {
				return rdtError("failed to remove resctrl group %q: %v", path, err)
			}
		}
	}

	// Try to apply given configuration
	for name, grpConf := range conf.ResctrlGroups {
		err := r.configureResctrlGroup(name, grpConf, conf.Options)
		if err != nil {
			return err
		}
	}

	return nil
}

func parseConfData(raw []byte) (config, error) {
	conf := config{}

	err := yaml.Unmarshal(raw, &conf)
	if err != nil {
		return conf, rdtError("failed to parse configuration: %v", err)
	}
	return conf, nil
}

func (r *control) configureResctrlGroup(name string, config ResctrlGroupConfig, options SchemaOptions) error {
	if err := os.Mkdir(r.resctrlGroupPath(name), 0755); err != nil && !os.IsExist(err) {
		return err
	}

	schemata := ""
	// Handle L3 cache allocation
	switch {
	case rdtInfo.l3.Supported():
		if !config.L3CodeSchema.IsNil() && !options.L3Code.Optional {
			return rdtError("separate L3 code path schema for %q requested but CDP not enabled", name)
		}
		if !config.L3DataSchema.IsNil() && !options.L3Data.Optional {
			return rdtError("separate L3 data path schema for %q requested but CDP not enabled", name)
		}
		r.Debug("configuring L3 schema for %q", name)
		schemata += config.L3Schema.ToStr(L3SchemaTypeUnified)
	case rdtInfo.l3data.Supported() || rdtInfo.l3code.Supported():
		if !config.L3CodeSchema.IsNil() {
			r.Debug("using specific L3 code schema for %q", name)
			schemata += config.L3CodeSchema.ToStr(L3SchemaTypeCode)
		} else {
			// No L3 code schema was specified -> use the "unified" L3 schema
			r.Debug("using unified L3 schema in code path for %q", name)
			schemata += config.L3Schema.ToStr(L3SchemaTypeCode)
		}
		if !config.L3DataSchema.IsNil() {
			r.Debug("using specific L3 data schema for %q", name)
			schemata += config.L3DataSchema.ToStr(L3SchemaTypeData)
		} else {
			// No L3 data schema was specified -> use the "unified" L3 schema
			r.Debug("using unified L3 schema in data path for %q", name)
			schemata += config.L3Schema.ToStr(L3SchemaTypeData)
		}
	default:
		if (!config.L3Schema.IsNil() && !options.L3.Optional) ||
			(!config.L3CodeSchema.IsNil() && !options.L3Code.Optional) ||
			(!config.L3DataSchema.IsNil() && !options.L3Data.Optional) {
			return rdtError("L3 cache allocation for %q specified in configuration but not supported by system", name)
		}
	}

	// Handle memory bandwidth allocation
	switch {
	case rdtInfo.mb.Supported():
		schemata += config.MBSchema.ToStr()
	default:
		if !config.MBSchema.IsNil() && !options.MB.Optional {
			return rdtError("memory bandwidth allocation specified in configuration but not supported by system")
		}
	}

	if len(schemata) > 0 {
		r.Debug("writing schemata %q", schemata)
		dirName := r.resctrlGroupDirName(name)
		if err := r.writeRdtFile(filepath.Join(dirName, "schemata"), []byte(schemata)); err != nil {
			return err
		}
	} else {
		r.Debug("empty schemata")
	}

	return nil
}

func (r *control) resctrlGroupDirName(name string) string {
	return resctrlGroupPrefix + name
}

func (r *control) resctrlGroupPath(name string) string {
	return filepath.Join(rdtInfo.resctrlPath, r.resctrlGroupDirName(name))
}

func (r *control) getResctrlGroups() ([]string, error) {

	files, err := ioutil.ReadDir(rdtInfo.resctrlPath)
	if err != nil {
		return nil, err
	}
	groups := make([]string, 0, len(files))
	for _, file := range files {
		fullName := file.Name()
		if strings.HasPrefix(fullName, resctrlGroupPrefix) {
			groups = append(groups, fullName[len(resctrlGroupPrefix):])
		}
	}
	return groups, nil
}

func (r *control) resctrlGroupTasks(name string) ([]string, error) {
	data, err := r.readRdtFile(filepath.Join(r.resctrlGroupDirName(name), "tasks"))
	if err != nil {
		return []string{}, err
	}
	split := strings.Split(strings.TrimSpace(string(data)), "\n")
	if len(split[0]) > 0 {
		return split, nil
	}
	return []string{}, nil
}

func (r *control) readRdtFile(rdtPath string) ([]byte, error) {
	return ioutil.ReadFile(filepath.Join(rdtInfo.resctrlPath, rdtPath))
}

func (r *control) writeRdtFile(rdtPath string, data []byte) error {
	if err := ioutil.WriteFile(filepath.Join(rdtInfo.resctrlPath, rdtPath), data, 0644); err != nil {
		return r.cmdError(err)
	}
	return nil
}

func (r *control) cmdError(origErr error) error {
	errData, readErr := r.readRdtFile(filepath.Join("info", "last_cmd_status"))
	if readErr != nil {
		return origErr
	}
	cmdStatus := strings.TrimSpace(string(errData))
	if len(cmdStatus) > 0 && cmdStatus != "ok" {
		return fmt.Errorf("%s", cmdStatus)
	}
	return origErr
}

func rdtError(format string, args ...interface{}) error {
	return fmt.Errorf("rdt: "+format, args...)
}
<commit_msg>(import)Merge pull request #79 from klihub/fixes/multiline-debug-log<commit_after>/*
Copyright 2019 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rdt

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/ghodss/yaml"

	pkgcfg "github.com/intel/cri-resource-manager/pkg/config"
	logger "github.com/intel/cri-resource-manager/pkg/log"
	"github.com/intel/cri-resource-manager/pkg/utils"
)

const resctrlGroupPrefix = "cri-resmgr."

// Control is the interface managing Intel RDT resources
type Control interface {
	// GetClasses returns the names of RDT classes (or resctrl control groups)
	// available
	GetClasses() []string

	// SetProcessClass assigns a set of processes to a RDT class
	SetProcessClass(string, ...string) error
}

var rdtInfo Info

type control struct {
	logger.Logger

	conf config
}

type config struct {
	Options       SchemaOptions                 `json:"options,omitempty"`
	ResctrlGroups map[string]ResctrlGroupConfig `json:"resctrlGroups"`
}

// NewControl returns new instance of the RDT Control interface
func NewControl(resctrlpath string, config string) (Control, error) {
	var err error
	r := &control{Logger: logger.NewLogger("rdt")}

	// Get info from the resctrl filesystem
	rdtInfo, err = getRdtInfo(resctrlpath)
	if err != nil {
		return nil, err
	}

	// Configure resctrl
	r.conf = opt.Config
	if err := r.configureResctrl(r.conf); err != nil {
		return nil, rdtError("configuration failed: %v", err)
	}

	pkgcfg.GetModule("rdt").AddNotify(r.configNotify)

	return r, nil
}

func (r *control) GetClasses() []string {
	ret := make([]string, len(r.conf.ResctrlGroups))

	i := 0
	for k := range r.conf.ResctrlGroups {
		ret[i] = k
		i++
	}
	sort.Strings(ret)
	return ret
}

func (r *control) SetProcessClass(class string, pids ...string) error {
	if _, ok := r.conf.ResctrlGroups[class]; !ok {
		return rdtError("unknown RDT class %q", class)
	}

	path := filepath.Join(r.resctrlGroupPath(class), "tasks")
	f, err := os.OpenFile(path, os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	for _, pid := range pids {
		if _, err := f.WriteString(pid + "\n"); err != nil {
			unwrapped := err
			if pathError, ok := err.(*os.PathError); ok {
				unwrapped = pathError.Unwrap()
			}
			if unwrapped == syscall.ESRCH {
				r.Debug("no task %s", pid)
			} else {
				return rdtError("failed to assign processes %v to class %q: %v", pids, class, r.cmdError(err))
			}
		}
	}
	return nil
}

func (r *control) configNotify(event pkgcfg.Event, source pkgcfg.Source) error {
	r.Info("configuration %s", event)

	err := r.configureResctrl(opt.Config)
	if err != nil {
		return rdtError("resctrl configuration failed: %v", err)
	}

	r.conf = opt.Config

	return nil
}

func (r *control) configureResctrl(conf config) error {
	r.DebugBlock("  applying ", "%s", utils.DumpJSON(conf))

	// Remove stale resctrl groups
	existingGroups, err := r.getResctrlGroups()
	if err != nil {
		return err
	}

	for _, name := range existingGroups {
		if _, ok := conf.ResctrlGroups[name]; !ok {
			tasks, err := r.resctrlGroupTasks(name)
			if err != nil {
				return rdtError("failed to get resctrl group tasks: %v", err)
			}
			path := r.resctrlGroupPath(name)
			if len(tasks) > 0 {
				return rdtError("refusing to remove non-empty resctrl group %q", path)
			}
			err = os.Remove(path)
			if err != nil {
				return rdtError("failed to remove resctrl group %q: %v", path, err)
			}
		}
	}

	// Try to apply given configuration
	for name, grpConf := range conf.ResctrlGroups {
		err := r.configureResctrlGroup(name, grpConf, conf.Options)
		if err != nil {
			return err
		}
	}

	return nil
}

func parseConfData(raw []byte) (config, error) {
	conf := config{}

	err := yaml.Unmarshal(raw, &conf)
	if err != nil {
		return conf, rdtError("failed to parse configuration: %v", err)
	}
	return conf, nil
}

func (r *control) configureResctrlGroup(name string, config ResctrlGroupConfig, options SchemaOptions) error {
	if err := os.Mkdir(r.resctrlGroupPath(name), 0755); err != nil && !os.IsExist(err) {
		return err
	}

	schemata := ""
	// Handle L3 cache allocation
	switch {
	case rdtInfo.l3.Supported():
		if !config.L3CodeSchema.IsNil() && !options.L3Code.Optional {
			return rdtError("separate L3 code path schema for %q requested but CDP not enabled", name)
		}
		if !config.L3DataSchema.IsNil() && !options.L3Data.Optional {
			return rdtError("separate L3 data path schema for %q requested but CDP not enabled", name)
		}
		r.Debug("configuring L3 schema for %q", name)
		schemata += config.L3Schema.ToStr(L3SchemaTypeUnified)
	case rdtInfo.l3data.Supported() || rdtInfo.l3code.Supported():
		if !config.L3CodeSchema.IsNil() {
			r.Debug("using specific L3 code schema for %q", name)
			schemata += config.L3CodeSchema.ToStr(L3SchemaTypeCode)
		} else {
			// No L3 code schema was specified -> use the "unified" L3 schema
			r.Debug("using unified L3 schema in code path for %q", name)
			schemata += config.L3Schema.ToStr(L3SchemaTypeCode)
		}
		if !config.L3DataSchema.IsNil() {
			r.Debug("using specific L3 data schema for %q", name)
			schemata += config.L3DataSchema.ToStr(L3SchemaTypeData)
		} else {
			// No L3 data schema was specified -> use the "unified" L3 schema
			r.Debug("using unified L3 schema in data path for %q", name)
			schemata += config.L3Schema.ToStr(L3SchemaTypeData)
		}
	default:
		if (!config.L3Schema.IsNil() && !options.L3.Optional) ||
			(!config.L3CodeSchema.IsNil() && !options.L3Code.Optional) ||
			(!config.L3DataSchema.IsNil() && !options.L3Data.Optional) {
			return rdtError("L3 cache allocation for %q specified in configuration but not supported by system", name)
		}
	}

	// Handle memory bandwidth allocation
	switch {
	case rdtInfo.mb.Supported():
		schemata += config.MBSchema.ToStr()
	default:
		if !config.MBSchema.IsNil() && !options.MB.Optional {
			return rdtError("memory bandwidth allocation specified in configuration but not supported by system")
		}
	}

	if len(schemata) > 0 {
		r.Debug("writing schemata %q", schemata)
		dirName := r.resctrlGroupDirName(name)
		if err := r.writeRdtFile(filepath.Join(dirName, "schemata"), []byte(schemata)); err != nil {
			return err
		}
	} else {
		r.Debug("empty schemata")
	}

	return nil
}

func (r *control) resctrlGroupDirName(name string) string {
	return resctrlGroupPrefix + name
}

func (r *control) resctrlGroupPath(name string) string {
	return filepath.Join(rdtInfo.resctrlPath, r.resctrlGroupDirName(name))
}

func (r *control) getResctrlGroups() ([]string, error) {

	files, err := ioutil.ReadDir(rdtInfo.resctrlPath)
	if err != nil {
		return nil, err
	}
	groups := make([]string, 0, len(files))
	for _, file := range files {
		fullName := file.Name()
		if strings.HasPrefix(fullName, resctrlGroupPrefix) {
			groups = append(groups, fullName[len(resctrlGroupPrefix):])
		}
	}
	return groups, nil
}

func (r *control) resctrlGroupTasks(name string) ([]string, error) {
	data, err := r.readRdtFile(filepath.Join(r.resctrlGroupDirName(name), "tasks"))
	if err != nil {
		return []string{}, err
	}
	split := strings.Split(strings.TrimSpace(string(data)), "\n")
	if len(split[0]) > 0 {
		return split, nil
	}
	return []string{}, nil
}

func (r *control) readRdtFile(rdtPath string) ([]byte, error) {
	return ioutil.ReadFile(filepath.Join(rdtInfo.resctrlPath, rdtPath))
}

func (r *control) writeRdtFile(rdtPath string, data []byte) error {
	if err := ioutil.WriteFile(filepath.Join(rdtInfo.resctrlPath, rdtPath), data, 0644); err != nil {
		return r.cmdError(err)
	}
	return nil
}

func (r *control) cmdError(origErr error) error {
	errData, readErr := r.readRdtFile(filepath.Join("info", "last_cmd_status"))
	if readErr != nil {
		return origErr
	}
	cmdStatus := strings.TrimSpace(string(errData))
	if len(cmdStatus) > 0 && cmdStatus != "ok" {
		return fmt.Errorf("%s", cmdStatus)
	}
	return origErr
}

func rdtError(format string, args ...interface{}) error {
	return fmt.Errorf("rdt: "+format, args...)
}
<|endoftext|>


<commit_before>// saving_test.go
package main

import (
	"math/rand"
	"testing"
)

func BenchmarkCsvSavingOnlySum(b *testing.B) {
	data := make([]StatForTime, 0)
	keyMap := GetKeymap()
	rnd := rand.New(rand.NewSource(42))
	for i := 0; i < b.N; i++ {
		var curStat StatForTime
		curStat.Init()
		for keyNum := range keyMap {
			if rnd.Float32() > 0.7 {
				curStat.keys[keyNum] = rnd.Intn(5000)
			}
		}
		data = append(data, curStat)
	}
	b.ResetTimer()
	SaveToCsvFile(data, keyMap, "/tmp/bla.csv", true)
}

func BenchmarkCsvSaving(b *testing.B) {
	data := make([]StatForTime, 0)
	keyMap := GetKeymap()
	rnd := rand.New(rand.NewSource(42))
	for i := 0; i < b.N; i++ {
		var curStat StatForTime
		curStat.Init()
		for keyNum := range keyMap {
			if rnd.Float32() > 0.7 {
				curStat.keys[keyNum] = rnd.Intn(5000)
			}
		}
		data = append(data, curStat)
	}
	b.ResetTimer()
	SaveToCsvFile(data, keyMap, "/tmp/bla.csv", false)
}
<commit_msg>Added saving to system tempfile<commit_after>// saving_test.go
package main

import (
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"testing"
)

func BenchmarkCsvSavingOnlySum(b *testing.B) {
	data := make([]StatForTime, 0)
	keyMap := GetKeymap()
	rnd := rand.New(rand.NewSource(42))
	for i := 0; i < b.N; i++ {
		var curStat StatForTime
		curStat.Init()
		for keyNum := range keyMap {
			if rnd.Float32() > 0.7 {
				curStat.keys[keyNum] = rnd.Intn(5000)
			}
		}
		data = append(data, curStat)
	}

	tmpFile, err := ioutil.TempFile(os.TempDir(), "benchmark")
	if err != nil {
		log.Fatal(err)
	}

	defer os.Remove(tmpFile.Name())

	b.ResetTimer()

	SaveToCsvWriter(data, keyMap, tmpFile, true)
}

func BenchmarkCsvSaving(b *testing.B) {
	data := make([]StatForTime, 0)
	keyMap := GetKeymap()
	rnd := rand.New(rand.NewSource(42))
	for i := 0; i < b.N; i++ {
		var curStat StatForTime
		curStat.Init()
		for keyNum := range keyMap {
			if rnd.Float32() > 0.7 {
				curStat.keys[keyNum] = rnd.Intn(5000)
			}
		}
		data = append(data, curStat)
	}
	tmpFile, err := ioutil.TempFile(os.TempDir(), "benchmark")
	if err != nil {
		log.Fatal(err)
	}

	defer os.Remove(tmpFile.Name())

	b.ResetTimer()

	SaveToCsvWriter(data, keyMap, tmpFile, false)
}
<|endoftext|>