<commit_before>// Copyright 2014 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.

package runtime

import "unsafe"

// NOTE: Func does not expose the actual unexported fields, because we return *Func
// values to users, and we want to keep them from being able to overwrite the data
// with (say) *f = Func{}.
// All code operating on a *Func must call raw to get the *_func instead.

// A Func represents a Go function in the running binary.
type Func struct {
	opaque struct{} // unexported field to disallow conversions
}

func (f *Func) raw() *_func {
	return (*_func)(unsafe.Pointer(f))
}

// funcdata.h
const (
	_PCDATA_StackMapIndex       = 0
	_FUNCDATA_ArgsPointerMaps   = 0
	_FUNCDATA_LocalsPointerMaps = 1
	_FUNCDATA_DeadValueMaps     = 2
	_ArgsSizeUnknown            = -0x80000000
)

// moduledata records information about the layout of the executable
// image. It is written by the linker. Any changes here must be
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
// moduledata is stored in read-only memory; none of the pointers here
// are visible to the garbage collector.
type moduledata struct {
	pclntable    []byte
	ftab         []functab
	filetab      []uint32
	findfunctab  uintptr
	minpc, maxpc uintptr

	text, etext           uintptr
	noptrdata, enoptrdata uintptr
	data, edata           uintptr
	bss, ebss             uintptr
	noptrbss, enoptrbss   uintptr
	end, gcdata, gcbss    uintptr

	typelinks []*_type

	modulename   string
	modulehashes []modulehash

	gcdatamask, gcbssmask bitvector

	next *moduledata
}

// For each shared library a module links against, the linker creates an entry in the
// moduledata.modulehashes slice containing the name of the module, the abi hash seen
// at link time and a pointer to the runtime abi hash. These are checked in
// moduledataverify1 below.
type modulehash struct {
	modulename   string
	linktimehash string
	runtimehash  *string
}

var firstmoduledata moduledata  // linker symbol
var lastmoduledatap *moduledata // linker symbol

type functab struct {
	entry   uintptr
	funcoff uintptr
}

const minfunc = 16                 // minimum function size
const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table

// findfunctab is an array of these structures.
// Each bucket represents 4096 bytes of the text segment.
// Each subbucket represents 256 bytes of the text segment.
// To find a function given a pc, locate the bucket and subbucket for
// that pc.  Add together the idx and subbucket value to obtain a
// function index.  Then scan the functab array starting at that
// index to find the target function.
// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
type findfuncbucket struct {
	idx        uint32
	subbuckets [16]byte
}

func moduledataverify() {
	for datap := &firstmoduledata; datap != nil; datap = datap.next {
		moduledataverify1(datap)
	}
}

const debugPcln = false

func moduledataverify1(datap *moduledata) {
	// See golang.org/s/go12symtab for header: 0xfffffffb,
	// two zero bytes, a byte giving the PC quantum,
	// and a byte giving the pointer width in bytes.
	pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
	pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
		throw("invalid function symbol table\n")
	}

	// ftab is lookup table for function by program counter.
	nftab := len(datap.ftab) - 1
	for i := 0; i < nftab; i++ {
		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
		if datap.ftab[i].entry > datap.ftab[i+1].entry {
			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
			f2name := "end"
			if i+1 < nftab {
				f2name = funcname(f2)
			}
			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
			for j := 0; j <= i; j++ {
				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
			}
			throw("invalid runtime symbol table")
		}

		if debugPcln || nftab-i < 5 {
			// Check a PC near but not at the very end.
			// The very end might be just padding that is not covered by the tables.
			// No architecture rounds function entries to more than 16 bytes,
			// but if one came along we'd need to subtract more here.
			end := datap.ftab[i+1].entry - 16
			if end < datap.ftab[i].entry {
				end = datap.ftab[i].entry
			}
			f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
			pcvalue(f, f.pcfile, end, true)
			pcvalue(f, f.pcln, end, true)
			pcvalue(f, f.pcsp, end, true)
		}
	}

	if datap.minpc != datap.ftab[0].entry ||
		datap.maxpc != datap.ftab[nftab].entry {
		throw("minpc or maxpc invalid")
	}

	for _, modulehash := range datap.modulehashes {
		if modulehash.linktimehash != *modulehash.runtimehash {
			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
			throw("abi mismatch")
		}
	}
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func {
	return (*Func)(unsafe.Pointer(findfunc(pc)))
}

// Name returns the name of the function.
func (f *Func) Name() string {
	return funcname(f.raw())
}

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr {
	return f.raw().entry
}

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	// Pass strict=false here, because anyone can call this function,
	// and they might just be wrong about targetpc belonging to f.
	file, line32 := funcline1(f.raw(), pc, false)
	return file, int(line32)
}

func findmoduledatap(pc uintptr) *moduledata {
	for datap := &firstmoduledata; datap != nil; datap = datap.next {
		if datap.minpc <= pc && pc <= datap.maxpc {
			return datap
		}
	}
	return nil
}

func findfunc(pc uintptr) *_func {
	datap := findmoduledatap(pc)
	if datap == nil {
		return nil
	}
	const nsub = uintptr(len(findfuncbucket{}.subbuckets))

	x := pc - datap.minpc
	b := x / pcbucketsize
	i := x % pcbucketsize / (pcbucketsize / nsub)

	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
	idx := ffb.idx + uint32(ffb.subbuckets[i])
	if pc < datap.ftab[idx].entry {
		throw("findfunc: bad findfunctab entry")
	}

	// linear search to find func with pc >= entry.
	for datap.ftab[idx+1].entry <= pc {
		idx++
	}
	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
}

func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
	if off == 0 {
		return -1
	}
	datap := findmoduledatap(f.entry) // inefficient
	if datap == nil {
		if strict && panicking == 0 {
			print("runtime: no module data for ", hex(f.entry), "\n")
			throw("no module data")
		}
		return -1
	}
	p := datap.pclntable[off:]
	pc := f.entry
	val := int32(-1)
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		if targetpc < pc {
			return val
		}
	}

	// If there was a table, it should have covered all program counters.
	// If not, something is wrong.
	if panicking != 0 || !strict {
		return -1
	}

	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")

	p = datap.pclntable[off:]
	pc = f.entry
	val = -1
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		print("\tvalue=", val, " until pc=", hex(pc), "\n")
	}

	throw("invalid runtime symbol table")
	return -1
}

func cfuncname(f *_func) *byte {
	if f == nil || f.nameoff == 0 {
		return nil
	}
	datap := findmoduledatap(f.entry) // inefficient
	if datap == nil {
		return nil
	}
	return (*byte)(unsafe.Pointer(&datap.pclntable[f.nameoff]))
}

func funcname(f *_func) string {
	return gostringnocopy(cfuncname(f))
}

func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
	datap := findmoduledatap(f.entry) // inefficient
	if datap == nil {
		return "?", 0
	}
	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
	line = pcvalue(f, f.pcln, targetpc, strict)
	if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
		return "?", 0
	}
	file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
	return
}

func funcline(f *_func, targetpc uintptr) (file string, line int32) {
	return funcline1(f, targetpc, true)
}

func funcspdelta(f *_func, targetpc uintptr) int32 {
	x := pcvalue(f, f.pcsp, targetpc, true)
	if x&(ptrSize-1) != 0 {
		print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
	}
	return x
}

func pcdatavalue(f *_func, table int32, targetpc uintptr) int32 {
	if table < 0 || table >= f.npcdata {
		return -1
	}
	off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
	return pcvalue(f, off, targetpc, true)
}

func funcdata(f *_func, i int32) unsafe.Pointer {
	if i < 0 || i >= f.nfuncdata {
		return nil
	}
	p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
	if ptrSize == 8 && uintptr(p)&4 != 0 {
		if uintptr(unsafe.Pointer(f))&4 != 0 {
			println("runtime: misaligned func", f)
		}
		p = add(p, 4)
	}
	return *(*unsafe.Pointer)(add(p, uintptr(i)*ptrSize))
}

// step advances to the next pc, value pair in the encoded table.
func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
	p, uvdelta := readvarint(p)
	if uvdelta == 0 && !first {
		return nil, false
	}
	if uvdelta&1 != 0 {
		uvdelta = ^(uvdelta >> 1)
	} else {
		uvdelta >>= 1
	}
	vdelta := int32(uvdelta)
	p, pcdelta := readvarint(p)
	*pc += uintptr(pcdelta * _PCQuantum)
	*val += vdelta
	return p, true
}

// readvarint reads a varint from p.
func readvarint(p []byte) (newp []byte, val uint32) {
	var v, shift uint32
	for {
		b := p[0]
		p = p[1:]
		v |= (uint32(b) & 0x7F) << shift
		if b&0x80 == 0 {
			break
		}
		shift += 7
	}
	return p, v
}

type stackmap struct {
	n        int32   // number of bitmaps
	nbit     int32   // number of bits in each bitmap
	bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
}

//go:nowritebarrier
func stackmapdata(stkmap *stackmap, n int32) bitvector {
	if n < 0 || n >= stkmap.n {
		throw("stackmapdata: index out of range")
	}
	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
}
<commit_msg>runtime: make pcln table check not trigger next to foreign code<commit_after>// Copyright 2014 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.

package runtime

import "unsafe"

// NOTE: Func does not expose the actual unexported fields, because we return *Func
// values to users, and we want to keep them from being able to overwrite the data
// with (say) *f = Func{}.
// All code operating on a *Func must call raw to get the *_func instead.

// A Func represents a Go function in the running binary.
type Func struct {
	opaque struct{} // unexported field to disallow conversions
}

func (f *Func) raw() *_func {
	return (*_func)(unsafe.Pointer(f))
}

// funcdata.h
const (
	_PCDATA_StackMapIndex       = 0
	_FUNCDATA_ArgsPointerMaps   = 0
	_FUNCDATA_LocalsPointerMaps = 1
	_FUNCDATA_DeadValueMaps     = 2
	_ArgsSizeUnknown            = -0x80000000
)

// moduledata records information about the layout of the executable
// image. It is written by the linker. Any changes here must be
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
// moduledata is stored in read-only memory; none of the pointers here
// are visible to the garbage collector.
type moduledata struct {
	pclntable    []byte
	ftab         []functab
	filetab      []uint32
	findfunctab  uintptr
	minpc, maxpc uintptr

	text, etext           uintptr
	noptrdata, enoptrdata uintptr
	data, edata           uintptr
	bss, ebss             uintptr
	noptrbss, enoptrbss   uintptr
	end, gcdata, gcbss    uintptr

	typelinks []*_type

	modulename   string
	modulehashes []modulehash

	gcdatamask, gcbssmask bitvector

	next *moduledata
}

// For each shared library a module links against, the linker creates an entry in the
// moduledata.modulehashes slice containing the name of the module, the abi hash seen
// at link time and a pointer to the runtime abi hash. These are checked in
// moduledataverify1 below.
type modulehash struct {
	modulename   string
	linktimehash string
	runtimehash  *string
}

var firstmoduledata moduledata  // linker symbol
var lastmoduledatap *moduledata // linker symbol

type functab struct {
	entry   uintptr
	funcoff uintptr
}

const minfunc = 16                 // minimum function size
const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table

// findfunctab is an array of these structures.
// Each bucket represents 4096 bytes of the text segment.
// Each subbucket represents 256 bytes of the text segment.
// To find a function given a pc, locate the bucket and subbucket for
// that pc.  Add together the idx and subbucket value to obtain a
// function index.  Then scan the functab array starting at that
// index to find the target function.
// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
type findfuncbucket struct {
	idx        uint32
	subbuckets [16]byte
}

func moduledataverify() {
	for datap := &firstmoduledata; datap != nil; datap = datap.next {
		moduledataverify1(datap)
	}
}

const debugPcln = false

func moduledataverify1(datap *moduledata) {
	// See golang.org/s/go12symtab for header: 0xfffffffb,
	// two zero bytes, a byte giving the PC quantum,
	// and a byte giving the pointer width in bytes.
	pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
	pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
		throw("invalid function symbol table\n")
	}

	// ftab is lookup table for function by program counter.
	nftab := len(datap.ftab) - 1
	for i := 0; i < nftab; i++ {
		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
		if datap.ftab[i].entry > datap.ftab[i+1].entry {
			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
			f2name := "end"
			if i+1 < nftab {
				f2name = funcname(f2)
			}
			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
			for j := 0; j <= i; j++ {
				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
			}
			throw("invalid runtime symbol table")
		}

		if debugPcln || nftab-i < 5 {
			// Check a PC near but not at the very end.
			// The very end might be just padding that is not covered by the tables.
			// No architecture rounds function entries to more than 16 bytes,
			// but if one came along we'd need to subtract more here.
			// But don't use the next PC if it corresponds to a foreign object chunk
			// (no pcln table, f2.pcln == 0). That chunk might have an alignment
			// more than 16 bytes.
			f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
			end := f.entry
			if i+1 < nftab {
				f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
				if f2.pcln != 0 {
					end = f2.entry - 16
					if end < f.entry {
						end = f.entry
					}
				}
			}
			pcvalue(f, f.pcfile, end, true)
			pcvalue(f, f.pcln, end, true)
			pcvalue(f, f.pcsp, end, true)
		}
	}

	if datap.minpc != datap.ftab[0].entry ||
		datap.maxpc != datap.ftab[nftab].entry {
		throw("minpc or maxpc invalid")
	}

	for _, modulehash := range datap.modulehashes {
		if modulehash.linktimehash != *modulehash.runtimehash {
			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
			throw("abi mismatch")
		}
	}
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func {
	return (*Func)(unsafe.Pointer(findfunc(pc)))
}

// Name returns the name of the function.
func (f *Func) Name() string {
	return funcname(f.raw())
}

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr {
	return f.raw().entry
}

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	// Pass strict=false here, because anyone can call this function,
	// and they might just be wrong about targetpc belonging to f.
	file, line32 := funcline1(f.raw(), pc, false)
	return file, int(line32)
}

func findmoduledatap(pc uintptr) *moduledata {
	for datap := &firstmoduledata; datap != nil; datap = datap.next {
		if datap.minpc <= pc && pc <= datap.maxpc {
			return datap
		}
	}
	return nil
}

func findfunc(pc uintptr) *_func {
	datap := findmoduledatap(pc)
	if datap == nil {
		return nil
	}
	const nsub = uintptr(len(findfuncbucket{}.subbuckets))

	x := pc - datap.minpc
	b := x / pcbucketsize
	i := x % pcbucketsize / (pcbucketsize / nsub)

	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
	idx := ffb.idx + uint32(ffb.subbuckets[i])
	if pc < datap.ftab[idx].entry {
		throw("findfunc: bad findfunctab entry")
	}

	// linear search to find func with pc >= entry.
	for datap.ftab[idx+1].entry <= pc {
		idx++
	}
	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
}

func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
	if off == 0 {
		return -1
	}
	datap := findmoduledatap(f.entry) // inefficient
	if datap == nil {
		if strict && panicking == 0 {
			print("runtime: no module data for ", hex(f.entry), "\n")
			throw("no module data")
		}
		return -1
	}
	p := datap.pclntable[off:]
	pc := f.entry
	val := int32(-1)
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		if targetpc < pc {
			return val
		}
	}

	// If there was a table, it should have covered all program counters.
	// If not, something is wrong.
	if panicking != 0 || !strict {
		return -1
	}

	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")

	p = datap.pclntable[off:]
	pc = f.entry
	val = -1
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		print("\tvalue=", val, " until pc=", hex(pc), "\n")
	}

	throw("invalid runtime symbol table")
	return -1
}

func cfuncname(f *_func) *byte {
	if f == nil || f.nameoff == 0 {
		return nil
	}
	datap := findmoduledatap(f.entry) // inefficient
	if datap == nil {
		return nil
	}
	return (*byte)(unsafe.Pointer(&datap.pclntable[f.nameoff]))
}

func funcname(f *_func) string {
	return gostringnocopy(cfuncname(f))
}

func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
	datap := findmoduledatap(f.entry) // inefficient
	if datap == nil {
		return "?", 0
	}
	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
	line = pcvalue(f, f.pcln, targetpc, strict)
	if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
		return "?", 0
	}
	file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
	return
}

func funcline(f *_func, targetpc uintptr) (file string, line int32) {
	return funcline1(f, targetpc, true)
}

func funcspdelta(f *_func, targetpc uintptr) int32 {
	x := pcvalue(f, f.pcsp, targetpc, true)
	if x&(ptrSize-1) != 0 {
		print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
	}
	return x
}

func pcdatavalue(f *_func, table int32, targetpc uintptr) int32 {
	if table < 0 || table >= f.npcdata {
		return -1
	}
	off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
	return pcvalue(f, off, targetpc, true)
}

func funcdata(f *_func, i int32) unsafe.Pointer {
	if i < 0 || i >= f.nfuncdata {
		return nil
	}
	p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
	if ptrSize == 8 && uintptr(p)&4 != 0 {
		if uintptr(unsafe.Pointer(f))&4 != 0 {
			println("runtime: misaligned func", f)
		}
		p = add(p, 4)
	}
	return *(*unsafe.Pointer)(add(p, uintptr(i)*ptrSize))
}

// step advances to the next pc, value pair in the encoded table.
func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
	p, uvdelta := readvarint(p)
	if uvdelta == 0 && !first {
		return nil, false
	}
	if uvdelta&1 != 0 {
		uvdelta = ^(uvdelta >> 1)
	} else {
		uvdelta >>= 1
	}
	vdelta := int32(uvdelta)
	p, pcdelta := readvarint(p)
	*pc += uintptr(pcdelta * _PCQuantum)
	*val += vdelta
	return p, true
}

// readvarint reads a varint from p.
func readvarint(p []byte) (newp []byte, val uint32) {
	var v, shift uint32
	for {
		b := p[0]
		p = p[1:]
		v |= (uint32(b) & 0x7F) << shift
		if b&0x80 == 0 {
			break
		}
		shift += 7
	}
	return p, v
}

type stackmap struct {
	n        int32   // number of bitmaps
	nbit     int32   // number of bits in each bitmap
	bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
}

//go:nowritebarrier
func stackmapdata(stkmap *stackmap, n int32) bitvector {
	if n < 0 || n >= stkmap.n {
		throw("stackmapdata: index out of range")
	}
	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
}
<|endoftext|>


<commit_before>package pkcs11

/*
#cgo LDFLAGS: -lltdl
// This is for Unix
#define CK_PTR *
#define CK_DEFINE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
#ifndef NULL_PTR
#define NULL_PTR 0
#endif
#include "pkcs11.h"
#include <stdlib.h>
#include <ltdl.h>

struct ctx {
	lt_dlhandle handle;
	CK_FUNCTION_LIST_PTR_PTR funcs;
};

struct ctx * new(const char *module) {
	if (lt_dlinit() != 0) {
		return NULL;
	}
	struct ctx *c;
	c = calloc(1, sizeof(struct ctx));
	c->handle = lt_dlopen(module);
	if (c->handle == NULL) {
		return NULL;
	}
	c->funcs = lt_dlsym(c->handle, "C_GetFunctionList");
	if (c->funcs == NULL) {
		return NULL;
	}
	return c;
}

void destroy(struct ctx *c) {
	if (c->handle == NULL) {
		return;
	}
	if (lt_dlclose(c->handle) < 0) {
		return;
	}
	lt_dlexit();
	free(c);
}
*/
import "C"

import (
	"unsafe"
)

type Pkcs11 struct {
	ctx *C.struct_ctx
// moet ** zijn?	funcs C.CK_FUNCTION_LIST_PTR
	session C.CK_SESSION_HANDLE
}

// New returns a new instance of...
// It returns nil if the module can not be loaded.
func New(module string) *Pkcs11 {
	p := new(Pkcs11)
        mod := C.CString(module)
	defer C.free(unsafe.Pointer(mod))
	p.ctx = C.new(mod)
	// Call initialize
	return p
}

// Destroy unload the module and frees any remaining memory.
func (p *Pkcs11) Destroy() {
	if p == nil {
		return
	}
	C.destroy(p.ctx)
}
<commit_msg>A working initialize<commit_after>package pkcs11

/*
#cgo LDFLAGS: -lltdl
// This is for Unix
#define CK_PTR *
#define CK_DEFINE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
#ifndef NULL_PTR
#define NULL_PTR 0
#endif
#include "pkcs11.h"
#include <stdlib.h>
#include <ltdl.h>

struct ctx {
	lt_dlhandle handle;
	CK_FUNCTION_LIST_PTR sym;
};

struct ctx * new(const char *module) {
	if (lt_dlinit() != 0) {
		return NULL;
	}
	struct ctx *c;
	CK_C_GetFunctionList list;
	CK_RV rv;

	c = calloc(1, sizeof(struct ctx));
	c->handle = lt_dlopen(module);
	if (c->handle == NULL) {
		free(c);
		return NULL;
	}
	list = (CK_C_GetFunctionList) lt_dlsym(c->handle, "C_GetFunctionList");
	if (list == NULL) {
		free(c);
		return NULL;
	}
	list(&c->sym);
	// Initialize
	CK_C_INITIALIZE_ARGS InitArgs = {NULL, NULL, NULL, NULL, CKF_OS_LOCKING_OK, NULL};
	rv = ((CK_FUNCTION_LIST_PTR)c->sym)->C_Initialize( (CK_VOID_PTR) &InitArgs);
	if (rv != CKR_OK) {
		free(c);
		return NULL;
	}
	return c;
}

void destroy(struct ctx *c) {
	if (c->handle == NULL) {
		return;
	}
	if (lt_dlclose(c->handle) < 0) {
		return;
	}
	lt_dlexit();
	free(c);
}
*/
import "C"

import (
	"unsafe"
)

type Pkcs11 struct {
	ctx *C.struct_ctx
// moet ** zijn?	funcs C.CK_FUNCTION_LIST_PTR
	session C.CK_SESSION_HANDLE
}

// New returns a new instance of...
// It returns nil if the module can not be loaded.
func New(module string) *Pkcs11 {
	p := new(Pkcs11)
        mod := C.CString(module)
	defer C.free(unsafe.Pointer(mod))
	p.ctx = C.new(mod)
	// Call initialize
	return p
}

// Destroy unload the module and frees any remaining memory.
func (p *Pkcs11) Destroy() {
	if p == nil {
		return
	}
	C.destroy(p.ctx)
}
<|endoftext|>


<commit_before>package http

import (
	"context"
	"fmt"
	"github.com/gost/server/sensorthings/models"
	"log"
	"net/http"
	"net/http/httptest"
	"strconv"
	"strings"
	"time"
)

// Server interface for starting and stopping the HTTP server
type Server interface {
	Start()
	Stop()
}

// GostServer is the type that contains all of the relevant information to set
// up the GOST HTTP Server
type GostServer struct {
	host       string      // Hostname for example "localhost" or "192.168.1.14"
	port       int         // Port number where you want to run your http server on
	api        *models.API // SensorThings api to interact with from the HttpServer
	https      bool
	httpsCert  string
	httpsKey   string
	httpServer *http.Server
}

// CreateServer initialises a new GOST HTTPServer based on the given parameters
func CreateServer(host string, port int, api *models.API, https bool, httpsCert, httpsKey string) Server {
	a := *api
	router := CreateRouter(api)
	return &GostServer{
		host:      host,
		port:      port,
		api:       api,
		https:     https,
		httpsCert: httpsCert,
		httpsKey:  httpsKey,
		httpServer: &http.Server{
			Addr:         fmt.Sprintf("%s:%s", host, strconv.Itoa(port)),
			Handler:      PostProcessHandler(LowerCaseURI(router), a.GetConfig().Server.ExternalURI),
			ReadTimeout:  30 * time.Second,
			WriteTimeout: 30 * time.Second,
		},
	}
}

// Start command to start the GOST HTTPServer
func (s *GostServer) Start() {
	t := "HTTP"
	if s.https {
		t = "HTTPS"
	}
	log.Printf("Started GOST %v Server on %v:%v", t, s.host, s.port)

	var err error
	if s.https {
		err = s.httpServer.ListenAndServeTLS(s.httpsCert, s.httpsKey)
	} else {
		err = s.httpServer.ListenAndServe()
	}

	if err != nil {
		panic(fmt.Errorf("GOST server not properly stopped: %v", err))
	}
}

// Stop command to stop the GOST HTTP server
func (s *GostServer) Stop() {
	if s.httpServer != nil {
		log.Print("Stopping HTTP(S) Server")
		s.httpServer.Shutdown(context.Background())
	}
}

// LowerCaseURI is a middleware function that lower cases the url path
func LowerCaseURI(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		lowerCasePath := strings.ToLower(r.URL.Path)
		// temporarily disabled checking on paths due to problems in serving with /$value
		/*
			api := *s.api
			split := strings.Split(lowerCasePath, "/")
			for i, s := range split {
				if len(s) == 0 || i+1 == len(split) {
					continue
				}

				found := false
				for _, a := range api.GetAcceptedPaths() {
					if strings.HasPrefix(s, a) {
						found = true
					}
				}

				if !found {
					w.Header().Set("Content-Type", "application/json; charset=UTF-8")
					w.WriteHeader(http.StatusNotFound)
					w.Write([]byte(""))
					return
				}
			}
		*/

		r.URL.RawPath = r.URL.Path
		r.URL.Path = lowerCasePath
		h.ServeHTTP(w, r)
	}

	return http.HandlerFunc(fn)
}

// PostProcessHandler runs after all the other handlers and can be used to modify
// the response. In this case modify links (due to proxy running) or handle CORS functionality
// Basically we catch all the response using httptest.NewRecorder (headers + body), modify and
// write to response. Is this a right approach?
func PostProcessHandler(h http.Handler, externalUri string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		origURI := externalUri
		forwardedURI := r.Header.Get("X-Forwarded-For")

		rec := httptest.NewRecorder()

		// first run the next handler and get results
		h.ServeHTTP(rec, r)

		// read response body and replace links
		bytes := rec.Body.Bytes()
		s := string(bytes)
		if len(s) > 0 {
			if len(forwardedURI) > 0 {
				// if both are changed (X-Forwarded-For and External uri environment variabele) use the last one
				if origURI == "http://localhost:8080/" {
					s = strings.Replace(s, origURI, forwardedURI, -1)
				}
			}

		}
		// handle headers too...
		for k, v := range rec.HeaderMap {
			val := v[0]

			// if there is a location header and a proxy running, change
			// the location url too
			if k == "Location" && len(forwardedURI) > 0 {
				if origURI == "http://localhost:8080/" {
					val = strings.Replace(val, origURI, forwardedURI, -1)
				}
			}

			// add the header to response
			w.Header().Add(k, val)
		}

		// handle status code
		w.WriteHeader(rec.Code)

		// write modified response
		w.Write([]byte(s))
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Added logging to file<commit_after>package http

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strconv"
	"strings"
	"time"

	gostLog "github.com/gost/server/log"
	"github.com/gost/server/sensorthings/models"
	log "github.com/sirupsen/logrus"
)

var (
	logger     *log.Logger
	httpLogger *log.Entry
)

func setupLogger() {
	logger, err := gostLog.GetLoggerInstance()
	if err != nil {
		log.Error(err)
	}

	//Setting default fields for main logger
	httpLogger = logger.WithFields(log.Fields{"package": "http"})
}

// Server interface for starting and stopping the HTTP server
type Server interface {
	Start()
	Stop()
}

// GostServer is the type that contains all of the relevant information to set
// up the GOST HTTP Server
type GostServer struct {
	host       string      // Hostname for example "localhost" or "192.168.1.14"
	port       int         // Port number where you want to run your http server on
	api        *models.API // SensorThings api to interact with from the HttpServer
	https      bool
	httpsCert  string
	httpsKey   string
	httpServer *http.Server
}

// CreateServer initialises a new GOST HTTPServer based on the given parameters
func CreateServer(host string, port int, api *models.API, https bool, httpsCert, httpsKey string) Server {
	setupLogger()
	a := *api
	router := CreateRouter(api)
	return &GostServer{
		host:      host,
		port:      port,
		api:       api,
		https:     https,
		httpsCert: httpsCert,
		httpsKey:  httpsKey,
		httpServer: &http.Server{
			Addr:         fmt.Sprintf("%s:%s", host, strconv.Itoa(port)),
			Handler:      PostProcessHandler(LowerCaseURI(router), a.GetConfig().Server.ExternalURI),
			ReadTimeout:  30 * time.Second,
			WriteTimeout: 30 * time.Second,
		},
	}
}

// Start command to start the GOST HTTPServer
func (s *GostServer) Start() {
	t := "HTTP"
	if s.https {
		t = "HTTPS"
	}
	log.Printf("Started GOST %v Server on %v:%v", t, s.host, s.port)
	httpLogger.Infof("Started GOST %v Server on %v:%v", t, s.host, s.port)

	var err error
	if s.https {
		err = s.httpServer.ListenAndServeTLS(s.httpsCert, s.httpsKey)
	} else {
		err = s.httpServer.ListenAndServe()
	}

	if err != nil {
		httpLogger.Errorf("GOST server not properly stopped: %v", err)
		panic(fmt.Errorf("GOST server not properly stopped: %v", err))
	}
}

// Stop command to stop the GOST HTTP server
func (s *GostServer) Stop() {
	if s.httpServer != nil {
		log.Print("Stopping HTTP(S) Server")
		httpLogger.Info("Stopping HTTP(S) Server")
		s.httpServer.Shutdown(context.Background())
	}
}

// LowerCaseURI is a middleware function that lower cases the url path
func LowerCaseURI(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		lowerCasePath := strings.ToLower(r.URL.Path)
		// temporarily disabled checking on paths due to problems in serving with /$value
		/*
			api := *s.api
			split := strings.Split(lowerCasePath, "/")
			for i, s := range split {
				if len(s) == 0 || i+1 == len(split) {
					continue
				}

				found := false
				for _, a := range api.GetAcceptedPaths() {
					if strings.HasPrefix(s, a) {
						found = true
					}
				}

				if !found {
					w.Header().Set("Content-Type", "application/json; charset=UTF-8")
					w.WriteHeader(http.StatusNotFound)
					w.Write([]byte(""))
					return
				}
			}
		*/

		r.URL.RawPath = r.URL.Path
		r.URL.Path = lowerCasePath
		h.ServeHTTP(w, r)
	}

	return http.HandlerFunc(fn)
}

// PostProcessHandler runs after all the other handlers and can be used to modify
// the response. In this case modify links (due to proxy running) or handle CORS functionality
// Basically we catch all the response using httptest.NewRecorder (headers + body), modify and
// write to response. Is this a right approach?
func PostProcessHandler(h http.Handler, externalUri string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		origURI := externalUri
		forwardedURI := r.Header.Get("X-Forwarded-For")

		rec := httptest.NewRecorder()

		// first run the next handler and get results
		h.ServeHTTP(rec, r)

		// read response body and replace links
		bytes := rec.Body.Bytes()
		s := string(bytes)
		if len(s) > 0 {
			if len(forwardedURI) > 0 {
				// if both are changed (X-Forwarded-For and External uri environment variabele) use the last one
				if origURI == "http://localhost:8080/" {
					s = strings.Replace(s, origURI, forwardedURI, -1)
				}
			}

		}
		// handle headers too...
		for k, v := range rec.HeaderMap {
			val := v[0]

			// if there is a location header and a proxy running, change
			// the location url too
			if k == "Location" && len(forwardedURI) > 0 {
				if origURI == "http://localhost:8080/" {
					val = strings.Replace(val, origURI, forwardedURI, -1)
				}
			}

			// add the header to response
			w.Header().Add(k, val)
		}

		// handle status code
		w.WriteHeader(rec.Code)

		// write modified response
		w.Write([]byte(s))
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


<commit_before>package models

import (
	"crypto/rand"
	"errors"
	"log"
	"math/big"
	"time"

	r "github.com/dancannon/gorethink"
	"golang.org/x/crypto/bcrypt"
)

// User holds attribute for an Ease user.
type User struct {
	ID           string    `gorethink:"id,omitempty" json:"id"`
	Username     string    `gorethink:"username" json:"username"`
	PasswordHash string    `gorethink:"password_hash" json:"-"`
	APIToken     string    `gorethink:"api_token" json:"api_token"`
	LoginToken   string    `gorethink:"login_token" json:"login_token"`
	CreatedAt    time.Time `gorethink:"created_at" json:"created_at"`
}

// UserQuerier queries the user table and logs users in.
type UserQuerier struct {
	session *r.Session
}

// NewUserQuerier returns a new UserQuerier.
func NewUserQuerier(session *r.Session) *UserQuerier {
	return &UserQuerier{session: session}
}

// NewUser creates a new user with tokens and a hashed password.
func NewUser(username, password string) (*User, error) {
	user := &User{}
	user.CreatedAt = time.Now()
	user.Username = username
	apiToken, err := generateRandomString(30)
	if err != nil {
		log.Println("Error: Couldn't generate random API token.")
		log.Println(err)
		return nil, err
	}
	user.APIToken = apiToken
	loginToken, err := generateRandomString(30)
	if err != nil {
		log.Println("Error: Couldn't generate random login token.")
		log.Println(err)
		return nil, err
	}
	user.LoginToken = loginToken

	byteHash, err :=
		bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	user.PasswordHash = string(byteHash)
	if err != nil {
		log.Println("Error: Couldn't hash password.")
		log.Println(err)
		return nil, err
	}
	return user, nil
}

// Save saves the given user and returns it.
// It verifies that the given username isn't already taken.
// Returns the updated user.
func (querier *UserQuerier) Save(user *User) (*User, error) {
	// Check that a user with the given username doesn't already exist.
	otherUser := querier.Find(user.Username)
	if otherUser != nil && user.ID != otherUser.ID {
		return nil, errors.New("A user with that name already exists")
	}

	// Upsert the user.
	res, err := r.Table("users").Insert(
		user, r.InsertOpts{Conflict: "replace"},
	).RunWrite(querier.session)

	if err != nil {
		friendlyErr := errors.New("Couldn't save user")
		log.Println(friendlyErr)
		log.Println(err)
		return nil, friendlyErr
	}

	// Get the user's ID if one was generated.
	if user.ID == "" {
		user.ID = res.GeneratedKeys[0]
	}

	return user, nil
}

// Find finds the user with the given username.  Returns nil if none found.
func (querier *UserQuerier) Find(username string) *User {
	res, err := r.Table("users").Filter(map[string]string{
		"username": username,
	}).Run(querier.session)
	if err != nil || res.IsNil() {
		return nil
	}
	var user *User
	err = res.One(&user)
	if err != nil {
		return nil
	}
	return user
}

// AttemptLogin attempts to login the user with the given username and password.
// Returns the user if successful, nil if failed.
func (querier *UserQuerier) AttemptLogin(username, password string) (*User, error) {
	user := querier.Find(username)
	if user == nil {
		return nil, errors.New("Couldn't find user with that username")
	}
	err :=
		bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password))
	if err != nil {
		return nil, errors.New("Password was invalid")
	}
	return user, nil
}

// Possible token chars.
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// generateRandomString generates a random string of length n.
func generateRandomString(n int) (string, error) {
	b := make([]rune, n)
	for i := range b {
		randInt, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
		if err != nil {
			return "", err
		}
		b[i] = letters[int(randInt.Int64())]
	}
	return string(b), nil
}
<commit_msg>Insert everyhing explicitly into test db.<commit_after>package models

import (
	"crypto/rand"
	"errors"
	"log"
	"math/big"
	"time"

	r "github.com/dancannon/gorethink"
	"golang.org/x/crypto/bcrypt"
)

// User holds attribute for an Ease user.
type User struct {
	ID           string    `gorethink:"id,omitempty" json:"id"`
	Username     string    `gorethink:"username" json:"username"`
	PasswordHash string    `gorethink:"password_hash" json:"-"`
	APIToken     string    `gorethink:"api_token" json:"api_token"`
	LoginToken   string    `gorethink:"login_token" json:"login_token"`
	CreatedAt    time.Time `gorethink:"created_at" json:"created_at"`
}

// UserQuerier queries the user table and logs users in.
type UserQuerier struct {
	session *r.Session
}

// NewUserQuerier returns a new UserQuerier.
func NewUserQuerier(session *r.Session) *UserQuerier {
	return &UserQuerier{session: session}
}

// NewUser creates a new user with tokens and a hashed password.
func NewUser(username, password string) (*User, error) {
	user := &User{}
	user.CreatedAt = time.Now()
	user.Username = username
	apiToken, err := generateRandomString(30)
	if err != nil {
		log.Println("Error: Couldn't generate random API token.")
		log.Println(err)
		return nil, err
	}
	user.APIToken = apiToken
	loginToken, err := generateRandomString(30)
	if err != nil {
		log.Println("Error: Couldn't generate random login token.")
		log.Println(err)
		return nil, err
	}
	user.LoginToken = loginToken

	byteHash, err :=
		bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	user.PasswordHash = string(byteHash)
	if err != nil {
		log.Println("Error: Couldn't hash password.")
		log.Println(err)
		return nil, err
	}
	return user, nil
}

// Save saves the given user and returns it.
// It verifies that the given username isn't already taken.
// Returns the updated user.
func (querier *UserQuerier) Save(user *User) (*User, error) {
	// Check that a user with the given username doesn't already exist.
	otherUser := querier.Find(user.Username)
	if otherUser != nil && user.ID != otherUser.ID {
		return nil, errors.New("A user with that name already exists")
	}

	// Upsert the user.
	res, err := r.DB("test").Table("users").Insert(
		user, r.InsertOpts{Conflict: "replace"},
	).RunWrite(querier.session)

	if err != nil {
		friendlyErr := errors.New("Couldn't save user")
		log.Println(friendlyErr)
		log.Println(err)
		return nil, friendlyErr
	}

	// Get the user's ID if one was generated.
	if user.ID == "" {
		user.ID = res.GeneratedKeys[0]
	}

	return user, nil
}

// Find finds the user with the given username.  Returns nil if none found.
func (querier *UserQuerier) Find(username string) *User {
	res, err := r.DB("test").Table("users").Filter(map[string]string{
		"username": username,
	}).Run(querier.session)
	if err != nil || res.IsNil() {
		return nil
	}
	var user *User
	err = res.One(&user)
	if err != nil {
		return nil
	}
	return user
}

// AttemptLogin attempts to login the user with the given username and password.
// Returns the user if successful, nil if failed.
func (querier *UserQuerier) AttemptLogin(username, password string) (*User, error) {
	user := querier.Find(username)
	if user == nil {
		return nil, errors.New("Couldn't find user with that username")
	}
	err :=
		bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password))
	if err != nil {
		return nil, errors.New("Password was invalid")
	}
	return user, nil
}

// Possible token chars.
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// generateRandomString generates a random string of length n.
func generateRandomString(n int) (string, error) {
	b := make([]rune, n)
	for i := range b {
		randInt, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
		if err != nil {
			return "", err
		}
		b[i] = letters[int(randInt.Int64())]
	}
	return string(b), nil
}
<|endoftext|>


<commit_before>// multicastservice.go
package main

import (
	"fmt"
	"log"
	"net"
)

type multicastservice struct {
	conn   *net.UDPConn
	mcaddr *net.UDPAddr
}

func (m multicastservice) getBlob(h HCID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"blob\", \"HCID\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	return b, err

}

func (m multicastservice) getCommit(h HKID) (c commit, err error) {
	message := fmt.Sprintf("{\"type\":\"commit\",\"HKID\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	return c, err
}

func (m multicastservice) getTag(h HKID, namesegment string) (t tag, err error) {
	message := fmt.Sprintf("{\"type\":\"tag\", \"HKID\": \"%s\", \"namesegment\": \"%s\"}", h.Hex(), namesegment)
	m.sendmessage(message)
	return t, err

}

func (m multicastservice) getKey(h HKID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"key\",\"HKID\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	return b, err
}

func (m multicastservice) listenmessage() (err error) {
	//It is taking only 256 bytes of data.
	go func() {
		for {
			b := make([]byte, 256)
			_, _, err := m.conn.ReadFromUDP(b)
			if err != nil {
				log.Printf("multicasterror, %s, \n", err)
				return
			}
			m.receivemessage(string(b))
		}
	}()
	return
}

func (m multicastservice) sendmessage(message string) (err error) {
	b := make([]byte, 256)
	copy(b, message)
	_, err = m.conn.WriteToUDP(b, m.mcaddr)
	if err != nil {
		log.Printf("multicasterror, %s, \n", err)
		return
	}

	return err
}

func (m multicastservice) receivemessage(message string) (err error) {
	log.Printf("Received message, %s,\n", message)
	return err
}

func multicastservicefactory() (m multicastservice) {
	mcaddr, err := net.ResolveUDPAddr("udp", "224.0.1.20:5354")
	if err != nil {
		return multicastservice{}
	}

	conn, err := net.ListenMulticastUDP("udp", nil, mcaddr)
	if err != nil {
		return multicastservice{}
	}
	return multicastservice{conn, mcaddr}

}

func init() {
	multicastserviceInstance := multicastservicefactory()
	multicastserviceInstance.listenmessage()
	multicastserviceInstance.getBlob(HCID{})
	multicastserviceInstance.getCommit(HKID{})
	multicastserviceInstance.getTag(HKID{}, "Hey")
	multicastserviceInstance.getKey(HKID{})

}
<commit_msg>Added send and receive infrastructure<commit_after>// multicastservice.go
package main

import (
	"fmt"
	"log"
	"net"
)

type multicastservice struct {
	conn            *net.UDPConn
	mcaddr          *net.UDPAddr
	responsechannel chan response
	waiting         map[hid]chan response
}

func (m multicastservice) getBlob(h HCID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"blob\", \"HCID\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	return b, err

}

func (m multicastservice) getCommit(h HKID) (c commit, err error) {
	message := fmt.Sprintf("{\"type\":\"commit\",\"HKID\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	return c, err
}

func (m multicastservice) getTag(h HKID, namesegment string) (t tag, err error) {
	message := fmt.Sprintf("{\"type\":\"tag\", \"HKID\": \"%s\", \"namesegment\": \"%s\"}", h.Hex(), namesegment)
	m.sendmessage(message)
	return t, err

}

func (m multicastservice) getKey(h HKID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"key\",\"HKID\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	//add channel to waiting map
	//wait on channel
	return b, err
}

func (m multicastservice) listenmessage() (err error) {
	//It is taking only 256 bytes of data.
	go func() {
		for {
			b := make([]byte, 256)
			_, _, err := m.conn.ReadFromUDP(b)
			if err != nil {
				log.Printf("multicasterror, %s, \n", err)
				return
			}
			m.receivemessage(string(b))
		}
	}()
	return
}

func (m multicastservice) sendmessage(message string) (err error) {
	b := make([]byte, 256)
	copy(b, message)
	_, err = m.conn.WriteToUDP(b, m.mcaddr)
	if err != nil {
		log.Printf("multicasterror, %s, \n", err)
		return
	}

	return err
}

func (m multicastservice) receivemessage(message string) (err error) {
	log.Printf("Received message, %s,\n", message)
	//parse message
	//if in waiting map send on channel

	return err
}

func multicastservicefactory() (m multicastservice) {
	mcaddr, err := net.ResolveUDPAddr("udp", "224.0.1.20:5354")
	if err != nil {
		return multicastservice{}
	}

	conn, err := net.ListenMulticastUDP("udp", nil, mcaddr)
	if err != nil {
		return multicastservice{}
	}

	responsechannel := make(chan response)

	return multicastservice{conn, mcaddr}
}

func init() {
	multicastserviceInstance := multicastservicefactory()
	multicastserviceInstance.listenmessage()

}

type response struct {
	typestring  string
	hkid        HKID
	hcid        HCID
	namesegment string
	url         string
}

type responseblob struct {
	hcid HCID
	url  string
}

type responsecommit struct {
	hkid HKID
	url  string
}

type responsetag struct {
	hkid        HKID
	namesegment string
	url         string
}

type responsekey struct {
	hkid HKID
	url  string
}
<|endoftext|>


<commit_before>// multicastservice.go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

type tagfields struct {
	hkid        HKID
	namesegment string
}

type multicastservice struct {
	conn             *net.UDPConn
	mcaddr           *net.UDPAddr
	waitingforblob   map[string]chan blob
	waitingfortag    map[string]chan tag
	waitingforcommit map[string]chan commit
	waitingforkey    map[string]chan blob
}

func (m multicastservice) GetBlob(h HCID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"blob\", \"hcid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	blobchannel := make(chan blob, 1)
	m.waitingforblob[h.Hex()] = blobchannel
	select {
	case b = <-blobchannel:
		return b, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return b, fmt.Errorf("GetBlob on Multicast service timed out")
	}

}

func (m multicastservice) GetCommit(h HKID) (c commit, err error) {
	message := fmt.Sprintf("{\"type\":\"commit\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	commitchannel := make(chan commit, 1)
	m.waitingforcommit[h.Hex()] = commitchannel

	select {
	case c = <-commitchannel:
		return c, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return c, fmt.Errorf("GetCommit on Multicast service timed out")
	}

}

func (m multicastservice) GetTag(h HKID, namesegment string) (t tag, err error) {
	message := fmt.Sprintf("{\"type\":\"tag\", \"hkid\": \"%s\", \"namesegment\": \"%s\"}", h.Hex(), namesegment)
	m.sendmessage(message)
	tagchannel := make(chan tag, 1)
	m.waitingfortag[h.Hex()+namesegment] = tagchannel

	select {
	case t = <-tagchannel:
		return t, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return t, fmt.Errorf("GetTag on Multicast service timed out")
	}

}

func (m multicastservice) GetKey(h HKID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"key\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	keychannel := make(chan blob)
	m.waitingforkey[h.Hex()] = keychannel
	select {
	case b = <-keychannel:
		return b, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return b, fmt.Errorf("GetKey on Multicast service timed out")
	}

}

func (m multicastservice) listenmessage() (err error) {
	//It is taking only 256 bytes of data.
	go func() {
		for {
			b := make([]byte, 256)
			_, addr, err := m.conn.ReadFromUDP(b)
			if err != nil {
				log.Printf("multicasterror, %s, \n", err)
				return
			}
			msg := strings.Trim(string(b), "\x00")
			//log.Printf("%s", m.conn.LocalAddr())
			m.receivemessage(msg, addr)
		}
	}()
	return
}

func (m multicastservice) sendmessage(message string) (err error) {
	b := make([]byte, 256)
	copy(b, message)
	//log.Printf("Sent message, %s", message)
	_, err = m.conn.WriteToUDP(b, m.mcaddr)
	if err != nil {
		log.Printf("multicasterror, %s, \n", err)
		return
	}

	return err
}

func (m multicastservice) receivemessage(message string, addr net.Addr) (err error) {
	//log.Printf("Received message, %s,\n", message)
	hkid, hcid, typestring, namesegment, url := parseMessage(message)
	if url == "" {
		checkAndRespond(hkid, hcid, typestring, namesegment)
		return nil
	}
	host, _, err := net.SplitHostPort(addr.String())
	if err != nil {
		return err
	}
	url = fmt.Sprintf("http://%s:%d%s", host, 8080, url)

	if typestring == "blob" {
		blobchannel, present := m.waitingforblob[hcid.String()]
		log.Printf("url is %s", url)
		data, err := m.geturl(url)
		if err == nil {
			if present {
				blobchannel <- data
			}
			if blob(data).Hash().Hex() == hcid.Hex() {
				localfileserviceInstance.PostBlob(data)
			}
		} else {
			log.Printf("error: %s", err)
		}
	}

	if typestring == "tag" {
		tagchannel, present := m.waitingfortag[hkid.Hex()+namesegment]
		data, err := m.geturl(url)
		t, err := TagFromBytes(data)
		if err == nil {
			if present {
				tagchannel <- t
			}
			if t.Verify() {
				localfileserviceInstance.PostTag(t)
			}
		} else {
			log.Printf("error, %s", err)
			log.Printf("Data, %s", data)
		}
	}

	if typestring == "commit" {
		commitchannel, present := m.waitingforcommit[hkid.String()]
		data, err := m.geturl(url)
		if err != nil {
			log.Printf("Error for geturl in commitchannel is, %s", err)
		} else {
			c, err := CommitFromBytes(data)

			if err == nil {
				if present {
					commitchannel <- c
				}
				if c.Verify() {
					localfileserviceInstance.PostCommit(c)
				}
			}
		}
	}
	if typestring == "key" {
		keychannel, present := m.waitingforkey[hkid.String()]
		data, err := m.geturl(url)
		if err == nil {
			if present {
				keychannel <- data
			}
			p, err := PrivteKeyFromBytes(data)

			if err != nil && p.Verify() && p.Hkid().Hex() == hkid.Hex() {
				localfileserviceInstance.PostKey(p)
			}

		}
	}

	return err
}

func (m multicastservice) geturl(url string) (data []byte, err error) {
	resp, err := http.Get(url) //Takes the http channel and makes it a channel object
	if err != nil {
		log.Printf("The HTTP Get error is %s", err)
		return data, err

	}
	defer resp.Body.Close() //Do this after return is called
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("The ReadAll error is %s", err)
		return data, err
	} else {
		return data, nil
	}

}

func multicastservicefactory() (m multicastservice) {
	mcaddr, err := net.ResolveUDPAddr("udp", "224.0.1.20:5354")
	if err != nil {
		return multicastservice{}
	}

	conn, err := net.ListenMulticastUDP("udp", nil, mcaddr)
	if err != nil {
		return multicastservice{}
	}

	return multicastservice{
		conn:             conn,
		mcaddr:           mcaddr,
		waitingforblob:   map[string]chan blob{},
		waitingfortag:    map[string]chan tag{},
		waitingforcommit: map[string]chan commit{},
		waitingforkey:    map[string]chan blob{},
	}
}

var multicastserviceInstance multicastservice

func init() {
	multicastserviceInstance = multicastservicefactory()
	multicastserviceInstance.listenmessage()

}
<commit_msg>multicastservice no longer prints url<commit_after>// multicastservice.go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

type tagfields struct {
	hkid        HKID
	namesegment string
}

type multicastservice struct {
	conn             *net.UDPConn
	mcaddr           *net.UDPAddr
	waitingforblob   map[string]chan blob
	waitingfortag    map[string]chan tag
	waitingforcommit map[string]chan commit
	waitingforkey    map[string]chan blob
}

func (m multicastservice) GetBlob(h HCID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"blob\", \"hcid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	blobchannel := make(chan blob, 1)
	m.waitingforblob[h.Hex()] = blobchannel
	select {
	case b = <-blobchannel:
		return b, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return b, fmt.Errorf("GetBlob on Multicast service timed out")
	}

}

func (m multicastservice) GetCommit(h HKID) (c commit, err error) {
	message := fmt.Sprintf("{\"type\":\"commit\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	commitchannel := make(chan commit, 1)
	m.waitingforcommit[h.Hex()] = commitchannel

	select {
	case c = <-commitchannel:
		return c, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return c, fmt.Errorf("GetCommit on Multicast service timed out")
	}

}

func (m multicastservice) GetTag(h HKID, namesegment string) (t tag, err error) {
	message := fmt.Sprintf("{\"type\":\"tag\", \"hkid\": \"%s\", \"namesegment\": \"%s\"}", h.Hex(), namesegment)
	m.sendmessage(message)
	tagchannel := make(chan tag, 1)
	m.waitingfortag[h.Hex()+namesegment] = tagchannel

	select {
	case t = <-tagchannel:
		return t, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return t, fmt.Errorf("GetTag on Multicast service timed out")
	}

}

func (m multicastservice) GetKey(h HKID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"key\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	keychannel := make(chan blob)
	m.waitingforkey[h.Hex()] = keychannel
	select {
	case b = <-keychannel:
		return b, err

	case <-time.After(12000 * time.Millisecond):
		log.Printf("Timing out now")
		return b, fmt.Errorf("GetKey on Multicast service timed out")
	}

}

func (m multicastservice) listenmessage() (err error) {
	//It is taking only 256 bytes of data.
	go func() {
		for {
			b := make([]byte, 256)
			_, addr, err := m.conn.ReadFromUDP(b)
			if err != nil {
				log.Printf("multicasterror, %s, \n", err)
				return
			}
			msg := strings.Trim(string(b), "\x00")
			//log.Printf("%s", m.conn.LocalAddr())
			m.receivemessage(msg, addr)
		}
	}()
	return
}

func (m multicastservice) sendmessage(message string) (err error) {
	b := make([]byte, 256)
	copy(b, message)
	//log.Printf("Sent message, %s", message)
	_, err = m.conn.WriteToUDP(b, m.mcaddr)
	if err != nil {
		log.Printf("multicasterror, %s, \n", err)
		return
	}

	return err
}

func (m multicastservice) receivemessage(message string, addr net.Addr) (err error) {
	//log.Printf("Received message, %s,\n", message)
	hkid, hcid, typestring, namesegment, url := parseMessage(message)
	if url == "" {
		checkAndRespond(hkid, hcid, typestring, namesegment)
		return nil
	}
	host, _, err := net.SplitHostPort(addr.String())
	if err != nil {
		return err
	}
	url = fmt.Sprintf("http://%s:%d%s", host, 8080, url)

	if typestring == "blob" {
		blobchannel, present := m.waitingforblob[hcid.String()]
		//log.Printf("url is %s", url)
		data, err := m.geturl(url)
		if err == nil {
			if present {
				blobchannel <- data
			}
			if blob(data).Hash().Hex() == hcid.Hex() {
				localfileserviceInstance.PostBlob(data)
			}
		} else {
			log.Printf("error: %s", err)
		}
	}

	if typestring == "tag" {
		tagchannel, present := m.waitingfortag[hkid.Hex()+namesegment]
		data, err := m.geturl(url)
		t, err := TagFromBytes(data)
		if err == nil {
			if present {
				tagchannel <- t
			}
			if t.Verify() {
				localfileserviceInstance.PostTag(t)
			}
		} else {
			log.Printf("error, %s", err)
			log.Printf("Data, %s", data)
		}
	}

	if typestring == "commit" {
		commitchannel, present := m.waitingforcommit[hkid.String()]
		data, err := m.geturl(url)
		if err != nil {
			log.Printf("Error for geturl in commitchannel is, %s", err)
		} else {
			c, err := CommitFromBytes(data)

			if err == nil {
				if present {
					commitchannel <- c
				}
				if c.Verify() {
					localfileserviceInstance.PostCommit(c)
				}
			}
		}
	}
	if typestring == "key" {
		keychannel, present := m.waitingforkey[hkid.String()]
		data, err := m.geturl(url)
		if err == nil {
			if present {
				keychannel <- data
			}
			p, err := PrivteKeyFromBytes(data)

			if err != nil && p.Verify() && p.Hkid().Hex() == hkid.Hex() {
				localfileserviceInstance.PostKey(p)
			}

		}
	}

	return err
}

func (m multicastservice) geturl(url string) (data []byte, err error) {
	resp, err := http.Get(url) //Takes the http channel and makes it a channel object
	if err != nil {
		log.Printf("The HTTP Get error is %s", err)
		return data, err

	}
	defer resp.Body.Close() //Do this after return is called
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("The ReadAll error is %s", err)
		return data, err
	} else {
		return data, nil
	}

}

func multicastservicefactory() (m multicastservice) {
	mcaddr, err := net.ResolveUDPAddr("udp", "224.0.1.20:5354")
	if err != nil {
		return multicastservice{}
	}

	conn, err := net.ListenMulticastUDP("udp", nil, mcaddr)
	if err != nil {
		return multicastservice{}
	}

	return multicastservice{
		conn:             conn,
		mcaddr:           mcaddr,
		waitingforblob:   map[string]chan blob{},
		waitingfortag:    map[string]chan tag{},
		waitingforcommit: map[string]chan commit{},
		waitingforkey:    map[string]chan blob{},
	}
}

var multicastserviceInstance multicastservice

func init() {
	multicastserviceInstance = multicastservicefactory()
	multicastserviceInstance.listenmessage()

}
<|endoftext|>


<commit_before>// Copyright 2017 Hajime Hoshi
//
// 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 oto

type Player struct {
	player *player
}

func NewPlayer(sampleRate, channelNum, bytesPerSample, bufferSizeInBytes int) (*Player, error) {
	p, err := newPlayer(sampleRate, channelNum, bytesPerSample, bufferSizeInBytes)
	if err != nil {
		return nil, err
	}
	return &Player{p}, nil
}

// Write is io.Writer's Write.
func (p *Player) Write(data []uint8) (int, error) {
	written := 0
	total := len(data)
	// TODO: Fix player's Write to satisfy io.Writer.
	// Now player's Write doesn't satisfy io.Writer's requirements since
	// the current Write might return without processing all given data.
	for written < total {
		n, err := p.player.Write(data)
		written += n
		if err != nil {
			return written, err
		}
		data = data[n:]
	}
	return written, nil
}

// Close is io.Closer's Close.
func (p *Player) Close() error {
	return p.player.Close()
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<commit_msg>Mitigate the busy loop (#10)<commit_after>// Copyright 2017 Hajime Hoshi
//
// 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 oto

import (
	"time"
)

type Player struct {
	player *player
}

func NewPlayer(sampleRate, channelNum, bytesPerSample, bufferSizeInBytes int) (*Player, error) {
	p, err := newPlayer(sampleRate, channelNum, bytesPerSample, bufferSizeInBytes)
	if err != nil {
		return nil, err
	}
	return &Player{p}, nil
}

// Write is io.Writer's Write.
func (p *Player) Write(data []uint8) (int, error) {
	written := 0
	total := len(data)
	// TODO: Fix player's Write to satisfy io.Writer.
	// Now player's Write doesn't satisfy io.Writer's requirements since
	// the current Write might return without processing all given data.
	for written < total {
		n, err := p.player.Write(data)
		written += n
		if err != nil {
			return written, err
		}
		data = data[n:]
		// Mitigate the busy loop (#10).
		time.Sleep(100 * time.Microsecond)
	}
	return written, nil
}

// Close is io.Closer's Close.
func (p *Player) Close() error {
	return p.player.Close()
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"neon/util"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"time"

	"gopkg.in/yaml.v2"
)

const (
	// DefaultRepo is local repository root directory
	DefaultRepo = "~/.neon"
	// RegexpPlugin is regexp for a plugin name
	RegexpPlugin = `[\w-]+/[\w-]+`
)

// Fields is the list of possible root fields for a build file
var Fields = []string{"doc", "default", "extends", "repository", "context",
	"singleton", "shell", "properties", "configuration", "environment", "targets"}

// Build structure
type Build struct {
	File        string
	Dir         string
	Here        string
	Default     []string
	Doc         string
	Repository  string
	Singleton   string
	Shell       map[string][]string
	Scripts     []string
	Extends     []string
	Config      []string
	Properties  util.Object
	Environment map[string]string
	Targets     map[string]*Target
	Parents     []*Build
}

// NewBuild makes a build from a build file
// - file: path of the build file
// Return:
// - Pointer to the build
// - error if something went wrong
func NewBuild(file string) (*Build, error) {
	object, build, err := parseBuildFile(file)
	if err != nil {
		return nil, err
	}
	if err := object.CheckFields(Fields); err != nil {
		return nil, fmt.Errorf("parsing build file: %v", err)
	}
	if err := ParseSingleton(object, build); err != nil {
		return nil, err
	}
	if err := ParseShell(object, build); err != nil {
		return nil, err
	}
	if err := ParseDefault(object, build); err != nil {
		return nil, err
	}
	if err := ParseDoc(object, build); err != nil {
		return nil, err
	}
	if err := ParseRepository(object, build); err != nil {
		return nil, err
	}
	if err := ParseContext(object, build); err != nil {
		return nil, err
	}
	if err := ParseExtends(object, build); err != nil {
		return nil, err
	}
	if err := ParseProperties(object, build); err != nil {
		return nil, err
	}
	if err := ParseConfiguration(object, build); err != nil {
		return nil, err
	}
	if err := ParseEnvironment(object, build); err != nil {
		return nil, err
	}
	if err := ParseTargets(object, build); err != nil {
		return nil, err
	}
	build.Properties = build.GetProperties()
	build.Environment = build.GetEnvironment()
	build.SetDir(build.Dir)
	return build, nil
}

func parseBuildFile(file string) (util.Object, *Build, error) {
	build := &Build{}
	file = util.ExpandUserHome(file)
	build.File = filepath.Base(file)
	base, err := filepath.Abs(filepath.Dir(file))
	if err != nil {
		return nil, nil, fmt.Errorf("getting build file directory: %v", err)
	}
	build.Dir = base
	here, err := os.Getwd()
	if err != nil {
		return nil, nil, fmt.Errorf("getting current directory: %v", err)
	}
	build.Here = here
	source, err := util.ReadFile(file)
	if err != nil {
		return nil, nil, fmt.Errorf("loading build file '%s': %v", file, err)
	}
	var object util.Object
	if err = yaml.Unmarshal(source, &object); err != nil {
		return nil, nil, fmt.Errorf("build must be a map with string keys: %v", err)
	}
	return object, build, nil
}

// GetProperties returns build properties, including those inherited from
// parents
// Return: build properties as an Object
func (build *Build) GetProperties() util.Object {
	var properties = make(map[string]interface{})
	for _, parent := range build.Parents {
		for name, value := range parent.GetProperties() {
			properties[name] = value
		}
	}
	for name, value := range build.Properties {
		properties[name] = value
	}
	return properties
}

// GetEnvironment returns the build environment, including the environment
// inherited from parents
// Return: environment as a map with string keys and values
func (build *Build) GetEnvironment() map[string]string {
	var environment = make(map[string]string)
	for _, parent := range build.Parents {
		for name, value := range parent.GetEnvironment() {
			environment[name] = value
		}
	}
	for name, value := range build.Environment {
		environment[name] = value
	}
	return environment
}

// GetTargets returns build targets, including those inherited from parents
// Return: targets as a map of targets with their name as keys
func (build *Build) GetTargets() map[string]*Target {
	var targets = make(map[string]*Target)
	for _, parent := range build.Parents {
		for name, target := range parent.GetTargets() {
			targets[name] = target
		}
	}
	for name, target := range build.Targets {
		targets[name] = target
	}
	return targets
}

// GetTargetByName return target with given name. If not defined in build,
// return target inherited from parent
// - name: the target name as a string
// Return: found target
func (build *Build) GetTargetByName(name string) *Target {
	target, found := build.Targets[name]
	if found {
		return target
	}
	for _, parent := range build.Parents {
		target = parent.GetTargetByName(name)
		if target != nil {
			return target
		}
	}
	return nil
}

// SetDir sets the build directory, propagating to parents
// - dir: build directory as a string
func (build *Build) SetDir(dir string) {
	build.Dir = dir
	for _, parent := range build.Parents {
		parent.SetDir(dir)
	}
}

// SetCommandLineProperties defines properties passed on command line in the
// context. These properties overwrite those define in the build file.
// - props: properties as a YAML map
// Return: error if something went wrong
func (build *Build) SetCommandLineProperties(props string) error {
	var object util.Object
	err := yaml.Unmarshal([]byte(props), &object)
	if err != nil {
		return fmt.Errorf("parsing command line properties: properties must be a map with string keys")
	}
	for name, value := range object {
		build.Properties[name] = value
	}
	return nil
}

// GetDefault returns default targets. If none is defined in build, return
// those from parent build files.
// Return: default targets a slice of strings
func (build *Build) GetDefault() []string {
	if len(build.Default) > 0 {
		return build.Default
	}
	for _, parent := range build.Parents {
		if len(parent.Default) > 0 {
			return parent.Default
		}
	}
	for _, parent := range build.Parents {
		parentDefault := parent.GetDefault()
		if len(parentDefault) > 0 {
			return parentDefault
		}
	}
	return build.Default
}

// Run runs given targets in a build context. If no target is given, runs
// default one.
// - context: the context to run into
// - targets: targets to run as a slice of strings
// Return: error if something went wrong
func (build *Build) Run(context *Context, targets []string) error {
	if err := build.EnsureSingle(context); err != nil {
		return err
	}
	if len(targets) == 0 {
		targets = build.GetDefault()
		if len(targets) == 0 {
			return fmt.Errorf("no default target")
		}
	}
	for _, target := range targets {
		err := build.RunTarget(context, target)
		if err != nil {
			return err
		}
	}
	return nil
}

// RunTarget runs given target in a build context.
// - context: build context
// - name: name of the target to run as a string
// Return: an error if something went wrong
func (build *Build) RunTarget(context *Context, name string) error {
	target := build.GetTargetByName(name)
	if target == nil {
		return fmt.Errorf("target '%s' not found", name)
	}
	err := target.Run(context)
	if err != nil {
		return fmt.Errorf("running target '%s': %v", name, err)
	}
	return nil
}

// RunParentTarget runs parent target with given name in a build context.
// - context: build context
// - name: the name of the target to run
// Return:
// - boolean: that tells if parent target was found
// - error: if something went wrong
func (build *Build) RunParentTarget(context *Context, name string) (bool, error) {
	for _, parent := range build.Parents {
		target := parent.GetTargetByName(name)
		if target != nil {
			err := context.Stack.Push(target)
			if err != nil {
				return false, err
			}
			err = target.Steps.Run(context)
			if err != nil {
				return true, fmt.Errorf("running target '%s': %v", name, err)
			}
			return true, nil
		}
	}
	return false, nil
}

// GetShell return shell for current os.
// Return:
// - shell as a slice of strings (such as ["sh", "-c"])
// - error if something went wrong
func (build *Build) GetShell() ([]string, error) {
	for system, shell := range build.Shell {
		if system != "default" && system == runtime.GOOS {
			return shell, nil
		}
	}
	shell, ok := build.Shell["default"]
	if !ok {
		return nil, fmt.Errorf("no shell found for '%s'", runtime.GOOS)
	}
	return shell, nil
}

// EnsureSingle runs a TCP server on given port to ensure that a single
// instance is running on a machine. Fails if another instance is already
// running on same port.
// - context: build context
// Return: an error if another instance is running on same port
func (build *Build) EnsureSingle(context *Context) error {
	if build.Singleton == "" {
		return nil
	}
	expression := build.Singleton
	if IsExpression(expression) {
		expression = expression[1:]
	}
	singleton, err := context.EvaluateExpression(expression)
	if err != nil {
		return fmt.Errorf("evaluating singleton port expression '%s': %v", expression, err)
	}
	port, ok := singleton.(int64)
	if !ok {
		return fmt.Errorf("singleton port expression '%s' must return an integer", expression)
	}
	if port < 0 || port > 65535 {
		return fmt.Errorf("singleton port port must be between 0 and 65535")
	}
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return fmt.Errorf("listening singleton port: %v", err)
	}
	go func() {
		for {
			listener.Accept()
			time.Sleep(100 * time.Millisecond)
		}
	}()
	return nil
}
<commit_msg>Fixed infinite loop detection<commit_after>package build

import (
	"fmt"
	"neon/util"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"time"

	"gopkg.in/yaml.v2"
)

const (
	// DefaultRepo is local repository root directory
	DefaultRepo = "~/.neon"
	// RegexpPlugin is regexp for a plugin name
	RegexpPlugin = `[\w-]+/[\w-]+`
)

// Fields is the list of possible root fields for a build file
var Fields = []string{"doc", "default", "extends", "repository", "context",
	"singleton", "shell", "properties", "configuration", "environment", "targets"}

// Build structure
type Build struct {
	File        string
	Dir         string
	Here        string
	Default     []string
	Doc         string
	Repository  string
	Singleton   string
	Shell       map[string][]string
	Scripts     []string
	Extends     []string
	Config      []string
	Properties  util.Object
	Environment map[string]string
	Targets     map[string]*Target
	Parents     []*Build
}

// NewBuild makes a build from a build file
// - file: path of the build file
// Return:
// - Pointer to the build
// - error if something went wrong
func NewBuild(file string) (*Build, error) {
	object, build, err := parseBuildFile(file)
	if err != nil {
		return nil, err
	}
	if err := object.CheckFields(Fields); err != nil {
		return nil, fmt.Errorf("parsing build file: %v", err)
	}
	if err := ParseSingleton(object, build); err != nil {
		return nil, err
	}
	if err := ParseShell(object, build); err != nil {
		return nil, err
	}
	if err := ParseDefault(object, build); err != nil {
		return nil, err
	}
	if err := ParseDoc(object, build); err != nil {
		return nil, err
	}
	if err := ParseRepository(object, build); err != nil {
		return nil, err
	}
	if err := ParseContext(object, build); err != nil {
		return nil, err
	}
	if err := ParseExtends(object, build); err != nil {
		return nil, err
	}
	if err := ParseProperties(object, build); err != nil {
		return nil, err
	}
	if err := ParseConfiguration(object, build); err != nil {
		return nil, err
	}
	if err := ParseEnvironment(object, build); err != nil {
		return nil, err
	}
	if err := ParseTargets(object, build); err != nil {
		return nil, err
	}
	build.Properties = build.GetProperties()
	build.Environment = build.GetEnvironment()
	build.SetDir(build.Dir)
	return build, nil
}

func parseBuildFile(file string) (util.Object, *Build, error) {
	build := &Build{}
	file = util.ExpandUserHome(file)
	build.File = filepath.Base(file)
	base, err := filepath.Abs(filepath.Dir(file))
	if err != nil {
		return nil, nil, fmt.Errorf("getting build file directory: %v", err)
	}
	build.Dir = base
	here, err := os.Getwd()
	if err != nil {
		return nil, nil, fmt.Errorf("getting current directory: %v", err)
	}
	build.Here = here
	source, err := util.ReadFile(file)
	if err != nil {
		return nil, nil, fmt.Errorf("loading build file '%s': %v", file, err)
	}
	var object util.Object
	if err = yaml.Unmarshal(source, &object); err != nil {
		return nil, nil, fmt.Errorf("build must be a map with string keys: %v", err)
	}
	return object, build, nil
}

// GetProperties returns build properties, including those inherited from
// parents
// Return: build properties as an Object
func (build *Build) GetProperties() util.Object {
	var properties = make(map[string]interface{})
	for _, parent := range build.Parents {
		for name, value := range parent.GetProperties() {
			properties[name] = value
		}
	}
	for name, value := range build.Properties {
		properties[name] = value
	}
	return properties
}

// GetEnvironment returns the build environment, including the environment
// inherited from parents
// Return: environment as a map with string keys and values
func (build *Build) GetEnvironment() map[string]string {
	var environment = make(map[string]string)
	for _, parent := range build.Parents {
		for name, value := range parent.GetEnvironment() {
			environment[name] = value
		}
	}
	for name, value := range build.Environment {
		environment[name] = value
	}
	return environment
}

// GetTargets returns build targets, including those inherited from parents
// Return: targets as a map of targets with their name as keys
func (build *Build) GetTargets() map[string]*Target {
	var targets = make(map[string]*Target)
	for _, parent := range build.Parents {
		for name, target := range parent.GetTargets() {
			targets[name] = target
		}
	}
	for name, target := range build.Targets {
		targets[name] = target
	}
	return targets
}

// GetTargetByName return target with given name. If not defined in build,
// return target inherited from parent
// - name: the target name as a string
// Return: found target
func (build *Build) GetTargetByName(name string) *Target {
	target, found := build.Targets[name]
	if found {
		return target
	}
	for _, parent := range build.Parents {
		target = parent.GetTargetByName(name)
		if target != nil {
			return target
		}
	}
	return nil
}

// SetDir sets the build directory, propagating to parents
// - dir: build directory as a string
func (build *Build) SetDir(dir string) {
	build.Dir = dir
	for _, parent := range build.Parents {
		parent.SetDir(dir)
	}
}

// SetCommandLineProperties defines properties passed on command line in the
// context. These properties overwrite those define in the build file.
// - props: properties as a YAML map
// Return: error if something went wrong
func (build *Build) SetCommandLineProperties(props string) error {
	var object util.Object
	err := yaml.Unmarshal([]byte(props), &object)
	if err != nil {
		return fmt.Errorf("parsing command line properties: properties must be a map with string keys")
	}
	for name, value := range object {
		build.Properties[name] = value
	}
	return nil
}

// GetDefault returns default targets. If none is defined in build, return
// those from parent build files.
// Return: default targets a slice of strings
func (build *Build) GetDefault() []string {
	if len(build.Default) > 0 {
		return build.Default
	}
	for _, parent := range build.Parents {
		if len(parent.Default) > 0 {
			return parent.Default
		}
	}
	for _, parent := range build.Parents {
		parentDefault := parent.GetDefault()
		if len(parentDefault) > 0 {
			return parentDefault
		}
	}
	return build.Default
}

// Run runs given targets in a build context. If no target is given, runs
// default one.
// - context: the context to run into
// - targets: targets to run as a slice of strings
// Return: error if something went wrong
func (build *Build) Run(context *Context, targets []string) error {
	if err := build.EnsureSingle(context); err != nil {
		return err
	}
	if len(targets) == 0 {
		targets = build.GetDefault()
		if len(targets) == 0 {
			return fmt.Errorf("no default target")
		}
	}
	for _, target := range targets {
		context.Stack = NewStack()
		err := build.RunTarget(context, target)
		if err != nil {
			return err
		}
	}
	return nil
}

// RunTarget runs given target in a build context.
// - context: build context
// - name: name of the target to run as a string
// Return: an error if something went wrong
func (build *Build) RunTarget(context *Context, name string) error {
	target := build.GetTargetByName(name)
	if target == nil {
		return fmt.Errorf("target '%s' not found", name)
	}
	err := target.Run(context)
	if err != nil {
		return fmt.Errorf("running target '%s': %v", name, err)
	}
	return nil
}

// RunParentTarget runs parent target with given name in a build context.
// - context: build context
// - name: the name of the target to run
// Return:
// - boolean: that tells if parent target was found
// - error: if something went wrong
func (build *Build) RunParentTarget(context *Context, name string) (bool, error) {
	for _, parent := range build.Parents {
		target := parent.GetTargetByName(name)
		if target != nil {
			err := context.Stack.Push(target)
			if err != nil {
				return false, err
			}
			err = target.Steps.Run(context)
			if err != nil {
				return true, fmt.Errorf("running target '%s': %v", name, err)
			}
			return true, nil
		}
	}
	return false, nil
}

// GetShell return shell for current os.
// Return:
// - shell as a slice of strings (such as ["sh", "-c"])
// - error if something went wrong
func (build *Build) GetShell() ([]string, error) {
	for system, shell := range build.Shell {
		if system != "default" && system == runtime.GOOS {
			return shell, nil
		}
	}
	shell, ok := build.Shell["default"]
	if !ok {
		return nil, fmt.Errorf("no shell found for '%s'", runtime.GOOS)
	}
	return shell, nil
}

// EnsureSingle runs a TCP server on given port to ensure that a single
// instance is running on a machine. Fails if another instance is already
// running on same port.
// - context: build context
// Return: an error if another instance is running on same port
func (build *Build) EnsureSingle(context *Context) error {
	if build.Singleton == "" {
		return nil
	}
	expression := build.Singleton
	if IsExpression(expression) {
		expression = expression[1:]
	}
	singleton, err := context.EvaluateExpression(expression)
	if err != nil {
		return fmt.Errorf("evaluating singleton port expression '%s': %v", expression, err)
	}
	port, ok := singleton.(int64)
	if !ok {
		return fmt.Errorf("singleton port expression '%s' must return an integer", expression)
	}
	if port < 0 || port > 65535 {
		return fmt.Errorf("singleton port port must be between 0 and 65535")
	}
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return fmt.Errorf("listening singleton port: %v", err)
	}
	go func() {
		for {
			listener.Accept()
			time.Sleep(100 * time.Millisecond)
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"strconv"
)

type counter struct {
	Count int
	Name  string
	Desc  string
}

var counters = []counter{}

func init() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/static/", staticFilesHandler)
	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/add", addHandler)
	http.HandleFunc("/remove", removeHandler)
	http.HandleFunc("/inc", incHandler)
	http.HandleFunc("/dec", decHandler)
}

func getHandler(rw http.ResponseWriter, req *http.Request) {
	e := json.NewEncoder(rw)
	e.Encode(counters)
}

func addHandler(rw http.ResponseWriter, req *http.Request) {
	c := counter{}
	c.Name = req.FormValue("Name")
	c.Desc = req.FormValue("Desc")
	c.Count, _ = strconv.Atoi(req.FormValue("Count"))
	counters = append(counters, c)
}

func incHandler(rw http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	for _, c := range counters {
		if c.Name == name {
			c.Count++
			break
		}
	}
}

func decHandler(rw http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	for _, c := range counters {
		if c.Name == name {
			c.Count--
			break
		}
	}
}

func removeHandler(rw http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	for i, c := range counters {
		if c.Name == name {
			counters = append(counters[:i], counters[i+1:]...)
			break
		}
	}
}

func indexHandler(rw http.ResponseWriter, req *http.Request) {

	http.ServeFile(rw, req, "static/index.html")
}

func staticFilesHandler(rw http.ResponseWriter, req *http.Request) {
	http.ServeFile(rw, req, req.URL.Path[1:])
}
<commit_msg>use pointer instead of value type<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"strconv"
)

type counter struct {
	Count int
	Name  string
	Desc  string
}

var counters = []*counter{}

func init() {
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/static/", staticFilesHandler)
	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/add", addHandler)
	http.HandleFunc("/remove", removeHandler)
	http.HandleFunc("/inc", incHandler)
	http.HandleFunc("/dec", decHandler)
}

func getHandler(rw http.ResponseWriter, req *http.Request) {
	e := json.NewEncoder(rw)
	e.Encode(counters)
}

func addHandler(rw http.ResponseWriter, req *http.Request) {
	c := &counter{}
	c.Name = req.FormValue("Name")
	c.Desc = req.FormValue("Desc")
	c.Count, _ = strconv.Atoi(req.FormValue("Count"))
	counters = append(counters, c)
}

func incHandler(rw http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	for _, c := range counters {
		if c.Name == name {
			c.Count++
			break
		}
	}
}

func decHandler(rw http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	for _, c := range counters {
		if c.Name == name {
			c.Count--
			break
		}
	}
}

func removeHandler(rw http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	for i, c := range counters {
		if c.Name == name {
			counters = append(counters[:i], counters[i+1:]...)
			break
		}
	}
}

func indexHandler(rw http.ResponseWriter, req *http.Request) {

	http.ServeFile(rw, req, "static/index.html")
}

func staticFilesHandler(rw http.ResponseWriter, req *http.Request) {
	http.ServeFile(rw, req, req.URL.Path[1:])
}

func main() {
	http.ListenAndServe(":9090", nil)
}
<|endoftext|>


<commit_before>// Copyright 2018-2019 Authors of Cilium
//
// 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.

// +build privileged_tests

package loader

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/cilium/cilium/pkg/testutils"

	"github.com/vishvananda/netlink"
	. "gopkg.in/check.v1"
)

// Hook up gocheck into the "go test" runner.
type LoaderTestSuite struct{}

var (
	_              = Suite(&LoaderTestSuite{})
	contextTimeout = 10 * time.Second
	benchTimeout   = 5*time.Minute + 5*time.Second

	dirInfo *directoryInfo
	ep      = testutils.NewTestEndpoint()
)

func Test(t *testing.T) {
	TestingT(t)
}

func (s *LoaderTestSuite) TearDownTest(c *C) {
	// Old map names as created by older versions of these tests
	//
	// FIXME GH-6701: Remove for 1.5.0
	os.Remove("/sys/fs/bpf/tc/globals/cilium_policy_foo")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_calls_111")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_ep_config_111")

	files, err := filepath.Glob("/sys/fs/bpf/tc/globals/test_*")
	if err != nil {
		panic(err)
	}
	for _, f := range files {
		if err := os.Remove(f); err != nil {
			panic(err)
		}
	}
}

// runTests configures devices for running the whole testsuite, and runs the
// tests. It is kept separate from TestMain() so that this function can defer
// cleanups and pass the exit code of the test run to the caller which can run
// os.Exit() with the result.
func runTests(m *testing.M) (int, error) {
	testIncludes = "-I/usr/include/x86_64-linux-gnu/"

	tmpDir, err := ioutil.TempDir("/tmp/", "cilium_")
	if err != nil {
		return 1, fmt.Errorf("Failed to create temporary directory: %s", err)
	}
	defer os.RemoveAll(tmpDir)
	if dirInfo, err = getDirs(tmpDir); err != nil {
		return 1, err
	}

	cleanup, err := prepareEnv(&ep)
	if err != nil {
		return 1, fmt.Errorf("Failed to prepare environment: %s", err)
	}
	defer func() {
		if err := cleanup(); err != nil {
			log.Errorf(err.Error())
		}
	}()

	return m.Run(), nil
}

func TestMain(m *testing.M) {
	exitCode, err := runTests(m)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func prepareEnv(ep *testutils.TestEndpoint) (func() error, error) {
	link := netlink.Dummy{
		LinkAttrs: netlink.LinkAttrs{
			Name: ep.InterfaceName(),
		},
	}
	if err := netlink.LinkAdd(&link); err != nil {
		if !os.IsExist(err) {
			return nil, fmt.Errorf("Failed to add link: %s", err)
		}
	}
	cleanupFn := func() error {
		if err := netlink.LinkDel(&link); err != nil {
			return fmt.Errorf("Failed to delete link: %s", err)
		}
		return nil
	}
	return cleanupFn, nil
}

func getDirs(tmpDir string) (*directoryInfo, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Failed to get working directory: %s", err)
	}
	bpfdir := filepath.Join(wd, "..", "..", "..", "bpf")
	dirs := directoryInfo{
		Library: bpfdir,
		Runtime: bpfdir,
		State:   bpfdir,
		Output:  tmpDir,
	}

	return &dirs, nil
}

// TestCompileAndLoad checks that the datapath can be compiled and loaded.
func (s *LoaderTestSuite) TestCompileAndLoad(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileAndLoad(ctx, &ep, dirInfo)
	c.Assert(err, IsNil)
}

// TestReload compiles and attaches the datapath multiple times.
func (s *LoaderTestSuite) TestReload(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileDatapath(ctx, &ep, dirInfo, true)
	c.Assert(err, IsNil)

	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)

	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)
}

// TestCompileFailure attempts to compile then cancels the context and ensures
// that the failure paths may be hit.
func (s *LoaderTestSuite) TestCompileFailure(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	exit := make(chan bool)
	defer close(exit)
	go func() {
		select {
		case <-time.After(100 * time.Millisecond):
			cancel()
		case <-exit:
			break
		}
	}()

	timeout := time.Now().Add(contextTimeout)
	var err error
	for err == nil && time.Now().Before(timeout) {
		err = compileAndLoad(ctx, &ep, dirInfo)
	}
	c.Assert(err, NotNil)
}

// BenchmarkCompileOnly benchmarks the just the entire compilation process.
func BenchmarkCompileOnly(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		debug := false // Otherwise we compile lots more.
		if err := compileDatapath(ctx, &ep, dirInfo, debug); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkCompileAndLoad benchmarks the entire compilation + loading process.
func BenchmarkCompileAndLoad(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := compileAndLoad(ctx, &ep, dirInfo); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkReplaceDatapath compiles the datapath program, then benchmarks only
// the loading of the program into the kernel.
func BenchmarkReplaceDatapath(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	if err := compileDatapath(ctx, &ep, dirInfo, false); err != nil {
		b.Fatal(err)
	}
	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint); err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>loader: Simplify unit tests with CiliumRootDir<commit_after>// Copyright 2018-2019 Authors of Cilium
//
// 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.

// +build privileged_tests

package loader

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/cilium/cilium/pkg/testutils"

	"github.com/vishvananda/netlink"
	. "gopkg.in/check.v1"
)

// Hook up gocheck into the "go test" runner.
type LoaderTestSuite struct{}

var (
	_              = Suite(&LoaderTestSuite{})
	contextTimeout = 10 * time.Second
	benchTimeout   = 5*time.Minute + 5*time.Second

	dirInfo *directoryInfo
	ep      = testutils.NewTestEndpoint()
	bpfDir  = filepath.Join(testutils.CiliumRootDir, "bpf")
)

func Test(t *testing.T) {
	TestingT(t)
}

func (s *LoaderTestSuite) TearDownTest(c *C) {
	// Old map names as created by older versions of these tests
	//
	// FIXME GH-6701: Remove for 1.5.0
	os.Remove("/sys/fs/bpf/tc/globals/cilium_policy_foo")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_calls_111")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_ep_config_111")

	files, err := filepath.Glob("/sys/fs/bpf/tc/globals/test_*")
	if err != nil {
		panic(err)
	}
	for _, f := range files {
		if err := os.Remove(f); err != nil {
			panic(err)
		}
	}
}

// runTests configures devices for running the whole testsuite, and runs the
// tests. It is kept separate from TestMain() so that this function can defer
// cleanups and pass the exit code of the test run to the caller which can run
// os.Exit() with the result.
func runTests(m *testing.M) (int, error) {
	testIncludes = "-I/usr/include/x86_64-linux-gnu/"

	tmpDir, err := ioutil.TempDir("/tmp/", "cilium_")
	if err != nil {
		return 1, fmt.Errorf("Failed to create temporary directory: %s", err)
	}
	defer os.RemoveAll(tmpDir)
	dirInfo = getDirs(tmpDir)

	cleanup, err := prepareEnv(&ep)
	if err != nil {
		return 1, fmt.Errorf("Failed to prepare environment: %s", err)
	}
	defer func() {
		if err := cleanup(); err != nil {
			log.Errorf(err.Error())
		}
	}()

	return m.Run(), nil
}

func TestMain(m *testing.M) {
	exitCode, err := runTests(m)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func prepareEnv(ep *testutils.TestEndpoint) (func() error, error) {
	link := netlink.Dummy{
		LinkAttrs: netlink.LinkAttrs{
			Name: ep.InterfaceName(),
		},
	}
	if err := netlink.LinkAdd(&link); err != nil {
		if !os.IsExist(err) {
			return nil, fmt.Errorf("Failed to add link: %s", err)
		}
	}
	cleanupFn := func() error {
		if err := netlink.LinkDel(&link); err != nil {
			return fmt.Errorf("Failed to delete link: %s", err)
		}
		return nil
	}
	return cleanupFn, nil
}

func getDirs(tmpDir string) *directoryInfo {
	return &directoryInfo{
		Library: bpfDir,
		Runtime: bpfDir,
		State:   bpfDir,
		Output:  tmpDir,
	}
}

// TestCompileAndLoad checks that the datapath can be compiled and loaded.
func (s *LoaderTestSuite) TestCompileAndLoad(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileAndLoad(ctx, &ep, dirInfo)
	c.Assert(err, IsNil)
}

// TestReload compiles and attaches the datapath multiple times.
func (s *LoaderTestSuite) TestReload(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileDatapath(ctx, &ep, dirInfo, true)
	c.Assert(err, IsNil)

	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)

	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)
}

// TestCompileFailure attempts to compile then cancels the context and ensures
// that the failure paths may be hit.
func (s *LoaderTestSuite) TestCompileFailure(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	exit := make(chan bool)
	defer close(exit)
	go func() {
		select {
		case <-time.After(100 * time.Millisecond):
			cancel()
		case <-exit:
			break
		}
	}()

	timeout := time.Now().Add(contextTimeout)
	var err error
	for err == nil && time.Now().Before(timeout) {
		err = compileAndLoad(ctx, &ep, dirInfo)
	}
	c.Assert(err, NotNil)
}

// BenchmarkCompileOnly benchmarks the just the entire compilation process.
func BenchmarkCompileOnly(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		debug := false // Otherwise we compile lots more.
		if err := compileDatapath(ctx, &ep, dirInfo, debug); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkCompileAndLoad benchmarks the entire compilation + loading process.
func BenchmarkCompileAndLoad(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := compileAndLoad(ctx, &ep, dirInfo); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkReplaceDatapath compiles the datapath program, then benchmarks only
// the loading of the program into the kernel.
func BenchmarkReplaceDatapath(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	if err := compileDatapath(ctx, &ep, dirInfo, false); err != nil {
		b.Fatal(err)
	}
	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint); err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>