<commit_before>// +build evmjit

package vm

/*
#include <stdint.h>
#include <stdlib.h>

struct evmjit_result
{
	int32_t  returnCode;
	uint64_t returnDataSize;
	void*    returnData;
};

struct evmjit_result evmjit_run(void* _data, void* _env);

// Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib
// More: https://github.com/ethereum/evmjit
#cgo LDFLAGS: -levmjit
*/
import "C"

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/state"
	"math/big"
	"unsafe"
)

type JitVm struct {
	env        Environment
	me         ContextRef
	callerAddr []byte
	price      *big.Int
	data       RuntimeData
}

type i256 [32]byte

const (
	Gas = iota
	address
	Caller
	Origin
	CallValue
	CallDataSize
	GasPrice
	CoinBase
	TimeStamp
	Number
	Difficulty
	GasLimit
	CodeSize

	_size

	ReturnDataOffset   = CallValue // Reuse 2 fields for return data reference
	ReturnDataSize     = CallDataSize
	SuicideDestAddress = address ///< Suicide balance destination address
)

type RuntimeData struct {
	elems    [_size]i256
	callData *byte
	code     *byte
}

func hash2llvm(h []byte) i256 {
	var m i256
	copy(m[len(m)-len(h):], h) // right aligned copy
	return m
}

func llvm2hash(m *i256) []byte {
	return C.GoBytes(unsafe.Pointer(m), C.int(len(m)))
}

func llvm2hashRef(m *i256) []byte {
	return (*[1 << 30]byte)(unsafe.Pointer(m))[:len(m):len(m)]
}

func address2llvm(addr []byte) i256 {
	n := hash2llvm(addr)
	bswap(&n)
	return n
}

// bswap swap bytes of the 256-bit integer on LLVM side
// TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations
func bswap(m *i256) *i256 {
	for i, l := 0, len(m); i < l/2; i++ {
		m[i], m[l-i-1] = m[l-i-1], m[i]
	}
	return m
}

func trim(m []byte) []byte {
	skip := 0
	for i := 0; i < len(m); i++ {
		if m[i] == 0 {
			skip++
		} else {
			break
		}
	}
	return m[skip:]
}

func getDataPtr(m []byte) *byte {
	var p *byte
	if len(m) > 0 {
		p = &m[0]
	}
	return p
}

func big2llvm(n *big.Int) i256 {
	m := hash2llvm(n.Bytes())
	bswap(&m)
	return m
}

func llvm2big(m *i256) *big.Int {
	n := big.NewInt(0)
	for i := 0; i < len(m); i++ {
		b := big.NewInt(int64(m[i]))
		b.Lsh(b, uint(i)*8)
		n.Add(n, b)
	}
	return n
}

// llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC)
// User must asure that referenced memory is available to Go until the data is copied or not needed any more
func llvm2bytesRef(data *byte, length uint64) []byte {
	if length == 0 {
		return nil
	}
	if data == nil {
		panic("Unexpected nil data pointer")
	}
	return (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
}

func untested(condition bool, message string) {
	if condition {
		panic("Condition `" + message + "` tested. Remove assert.")
	}
}

func assert(condition bool, message string) {
	if !condition {
		panic("Assert `" + message + "` failed!")
	}
}

func NewJitVm(env Environment) *JitVm {
	return &JitVm{env: env}
}

func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
	// TODO: depth is increased but never checked by VM. VM should not know about it at all.
	self.env.SetDepth(self.env.Depth() + 1)

	// TODO: Move it to Env.Call() or sth
	if Precompiled[string(me.Address())] != nil {
		// if it's address of precopiled contract
		// fallback to standard VM
		stdVm := New(self.env)
		return stdVm.Run(me, caller, code, value, gas, price, callData)
	}

	if self.me != nil {
		panic("JitVm.Run() can be called only once per JitVm instance")
	}

	self.me = me
	self.callerAddr = caller.Address()
	self.price = price

	self.data.elems[Gas] = big2llvm(gas)
	self.data.elems[address] = address2llvm(self.me.Address())
	self.data.elems[Caller] = address2llvm(caller.Address())
	self.data.elems[Origin] = address2llvm(self.env.Origin())
	self.data.elems[CallValue] = big2llvm(value)
	self.data.elems[CallDataSize] = big2llvm(big.NewInt(int64(len(callData)))) // TODO: Keep call data size as i64
	self.data.elems[GasPrice] = big2llvm(price)
	self.data.elems[CoinBase] = address2llvm(self.env.Coinbase())
	self.data.elems[TimeStamp] = big2llvm(big.NewInt(self.env.Time())) // TODO: Keep timestamp as i64
	self.data.elems[Number] = big2llvm(self.env.BlockNumber())
	self.data.elems[Difficulty] = big2llvm(self.env.Difficulty())
	self.data.elems[GasLimit] = big2llvm(self.env.GasLimit())
	self.data.elems[CodeSize] = big2llvm(big.NewInt(int64(len(code)))) // TODO: Keep code size as i64
	self.data.callData = getDataPtr(callData)
	self.data.code = getDataPtr(code)

	result := C.evmjit_run(unsafe.Pointer(&self.data), unsafe.Pointer(self))

	if result.returnCode >= 100 {
		err = errors.New("OOG from JIT")
		gas.SetInt64(0) // Set gas to 0, JIT does not bother
	} else {
		gasLeft := llvm2big(&self.data.elems[Gas]) // TODO: Set value directly to gas instance
		gas.Set(gasLeft)
		if result.returnCode == 1 { // RETURN
			ret = C.GoBytes(result.returnData, C.int(result.returnDataSize))
			C.free(result.returnData)
		} else if result.returnCode == 2 { // SUICIDE
			// TODO: Suicide support logic should be moved to Env to be shared by VM implementations
			state := self.Env().State()
			receiverAddr := llvm2hashRef(bswap(&self.data.elems[address]))
			receiver := state.GetOrNewStateObject(receiverAddr)
			balance := state.GetBalance(me.Address())
			receiver.AddAmount(balance)
			state.Delete(me.Address())
		}
	}

	return
}

func (self *JitVm) Printf(format string, v ...interface{}) VirtualMachine {
	return self
}

func (self *JitVm) Endl() VirtualMachine {
	return self
}

func (self *JitVm) Env() Environment {
	return self.env
}

//export env_sha3
func env_sha3(dataPtr *byte, length uint64, resultPtr unsafe.Pointer) {
	data := llvm2bytesRef(dataPtr, length)
	hash := crypto.Sha3(data)
	result := (*i256)(resultPtr)
	*result = hash2llvm(hash)
}

//export env_sstore
func env_sstore(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, valuePtr unsafe.Pointer) {
	vm := (*JitVm)(vmPtr)
	index := llvm2hash(bswap((*i256)(indexPtr)))
	value := llvm2hash(bswap((*i256)(valuePtr)))
	value = trim(value)
	if len(value) == 0 {
		prevValue := vm.env.State().GetState(vm.me.Address(), index)
		if len(prevValue) != 0 {
			vm.Env().State().Refund(vm.callerAddr, GasSStoreRefund)
		}
	}

	vm.env.State().SetState(vm.me.Address(), index, value)
}

//export env_sload
func env_sload(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, resultPtr unsafe.Pointer) {
	vm := (*JitVm)(vmPtr)
	index := llvm2hash(bswap((*i256)(indexPtr)))
	value := vm.env.State().GetState(vm.me.Address(), index)
	result := (*i256)(resultPtr)
	*result = hash2llvm(value)
	bswap(result)
}

//export env_balance
func env_balance(_vm unsafe.Pointer, _addr unsafe.Pointer, _result unsafe.Pointer) {
	vm := (*JitVm)(_vm)
	addr := llvm2hash((*i256)(_addr))
	balance := vm.Env().State().GetBalance(addr)
	result := (*i256)(_result)
	*result = big2llvm(balance)
}

//export env_blockhash
func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Pointer) {
	vm := (*JitVm)(_vm)
	number := llvm2big((*i256)(_number))
	result := (*i256)(_result)

	currNumber := vm.Env().BlockNumber()
	limit := big.NewInt(0).Sub(currNumber, big.NewInt(256))
	if number.Cmp(limit) >= 0 && number.Cmp(currNumber) < 0 {
		hash := vm.Env().GetHash(uint64(number.Int64()))
		*result = hash2llvm(hash)
	} else {
		*result = i256{}
	}
}

//export env_call
func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
	vm := (*JitVm)(_vm)

	//fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("Recovered in env_call (depth %d, out %p %d): %s\n", vm.Env().Depth(), outDataPtr, outDataLen, r)
		}
	}()

	balance := vm.Env().State().GetBalance(vm.me.Address())
	value := llvm2big((*i256)(_value))

	if balance.Cmp(value) >= 0 {
		receiveAddr := llvm2hash((*i256)(_receiveAddr))
		inData := C.GoBytes(inDataPtr, C.int(inDataLen))
		outData := llvm2bytesRef(outDataPtr, outDataLen)
		codeAddr := llvm2hash((*i256)(_codeAddr))
		llvmGas := (*i256)(_gas)
		gas := llvm2big(llvmGas)
		var out []byte
		var err error
		if bytes.Equal(codeAddr, receiveAddr) {
			out, err = vm.env.Call(vm.me, codeAddr, inData, gas, vm.price, value)
		} else {
			out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value)
		}
		*llvmGas = big2llvm(gas)
		if err == nil {
			copy(outData, out)
			return true
		}
	}

	return false
}

//export env_create
func env_create(_vm unsafe.Pointer, _gas unsafe.Pointer, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
	vm := (*JitVm)(_vm)

	value := llvm2big((*i256)(_value))
	initData := C.GoBytes(initDataPtr, C.int(initDataLen)) // TODO: Unnecessary if low balance
	result := (*i256)(_result)
	*result = i256{}

	llvmGas := (*i256)(_gas)
	gas := llvm2big(llvmGas)

	ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
	if suberr == nil {
		dataGas := big.NewInt(int64(len(ret))) // TODO: Nto the best design. env.Create can do it, it has the reference to gas counter
		dataGas.Mul(dataGas, GasCreateByte)
		gas.Sub(gas, dataGas)
		*result = hash2llvm(ref.Address())
	}
	*llvmGas = big2llvm(gas)
}

//export env_log
func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1 unsafe.Pointer, _topic2 unsafe.Pointer, _topic3 unsafe.Pointer, _topic4 unsafe.Pointer) {
	vm := (*JitVm)(_vm)

	data := C.GoBytes(dataPtr, C.int(dataLen))

	topics := make([][]byte, 0, 4)
	if _topic1 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic1)))
	}
	if _topic2 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic2)))
	}
	if _topic3 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic3)))
	}
	if _topic4 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic4)))
	}

	vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data))
}

//export env_extcode
func env_extcode(_vm unsafe.Pointer, _addr unsafe.Pointer, o_size *uint64) *byte {
	vm := (*JitVm)(_vm)
	addr := llvm2hash((*i256)(_addr))
	code := vm.Env().State().GetCode(addr)
	*o_size = uint64(len(code))
	return getDataPtr(code)
}
<commit_msg>Update EVM JIT runtime data layout<commit_after>// +build evmjit

package vm

/*
#include <stdint.h>
#include <stdlib.h>

struct evmjit_result
{
	int32_t  returnCode;
	uint64_t returnDataSize;
	void*    returnData;
};

struct evmjit_result evmjit_run(void* _data, void* _env);

// Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib
// More: https://github.com/ethereum/evmjit
#cgo LDFLAGS: -levmjit
*/
import "C"

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/state"
	"math/big"
	"unsafe"
)

type JitVm struct {
	env        Environment
	me         ContextRef
	callerAddr []byte
	price      *big.Int
	data       RuntimeData
}

type i256 [32]byte

type RuntimeData struct {
	gas          int64
	gasPrice     int64
	callData     *byte
	callDataSize uint64
	address      i256
	caller       i256
	origin       i256
	callValue    i256
	coinBase     i256
	difficulty   i256
	gasLimit     i256
	number       uint64
	timestamp    int64
	code         *byte
	codeSize     uint64
}

func hash2llvm(h []byte) i256 {
	var m i256
	copy(m[len(m)-len(h):], h) // right aligned copy
	return m
}

func llvm2hash(m *i256) []byte {
	return C.GoBytes(unsafe.Pointer(m), C.int(len(m)))
}

func llvm2hashRef(m *i256) []byte {
	return (*[1 << 30]byte)(unsafe.Pointer(m))[:len(m):len(m)]
}

func address2llvm(addr []byte) i256 {
	n := hash2llvm(addr)
	bswap(&n)
	return n
}

// bswap swap bytes of the 256-bit integer on LLVM side
// TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations
func bswap(m *i256) *i256 {
	for i, l := 0, len(m); i < l/2; i++ {
		m[i], m[l-i-1] = m[l-i-1], m[i]
	}
	return m
}

func trim(m []byte) []byte {
	skip := 0
	for i := 0; i < len(m); i++ {
		if m[i] == 0 {
			skip++
		} else {
			break
		}
	}
	return m[skip:]
}

func getDataPtr(m []byte) *byte {
	var p *byte
	if len(m) > 0 {
		p = &m[0]
	}
	return p
}

func big2llvm(n *big.Int) i256 {
	m := hash2llvm(n.Bytes())
	bswap(&m)
	return m
}

func llvm2big(m *i256) *big.Int {
	n := big.NewInt(0)
	for i := 0; i < len(m); i++ {
		b := big.NewInt(int64(m[i]))
		b.Lsh(b, uint(i)*8)
		n.Add(n, b)
	}
	return n
}

// llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC)
// User must asure that referenced memory is available to Go until the data is copied or not needed any more
func llvm2bytesRef(data *byte, length uint64) []byte {
	if length == 0 {
		return nil
	}
	if data == nil {
		panic("Unexpected nil data pointer")
	}
	return (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
}

func untested(condition bool, message string) {
	if condition {
		panic("Condition `" + message + "` tested. Remove assert.")
	}
}

func assert(condition bool, message string) {
	if !condition {
		panic("Assert `" + message + "` failed!")
	}
}

func NewJitVm(env Environment) *JitVm {
	return &JitVm{env: env}
}

func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
	// TODO: depth is increased but never checked by VM. VM should not know about it at all.
	self.env.SetDepth(self.env.Depth() + 1)

	// TODO: Move it to Env.Call() or sth
	if Precompiled[string(me.Address())] != nil {
		// if it's address of precopiled contract
		// fallback to standard VM
		stdVm := New(self.env)
		return stdVm.Run(me, caller, code, value, gas, price, callData)
	}

	if self.me != nil {
		panic("JitVm.Run() can be called only once per JitVm instance")
	}

	self.me = me
	self.callerAddr = caller.Address()
	self.price = price

	self.data.gas = gas.Int64()
	self.data.gasPrice = price.Int64()
	self.data.callData = getDataPtr(callData)
	self.data.callDataSize = uint64(len(callData))
	self.data.address = address2llvm(self.me.Address())
	self.data.caller = address2llvm(caller.Address())
	self.data.origin = address2llvm(self.env.Origin())
	self.data.callValue = big2llvm(value)
	self.data.coinBase = address2llvm(self.env.Coinbase())
	self.data.difficulty = big2llvm(self.env.Difficulty())
	self.data.gasLimit = big2llvm(self.env.GasLimit())
	self.data.number = self.env.BlockNumber().Uint64()
	self.data.timestamp = self.env.Time()
	self.data.code = getDataPtr(code)
	self.data.codeSize = uint64(len(code))

	result := C.evmjit_run(unsafe.Pointer(&self.data), unsafe.Pointer(self))

	if result.returnCode >= 100 {
		err = errors.New("OOG from JIT")
		gas.SetInt64(0) // Set gas to 0, JIT does not bother
	} else {
		gas.SetInt64(self.data.gas)
		if result.returnCode == 1 { // RETURN
			ret = C.GoBytes(result.returnData, C.int(result.returnDataSize))
			C.free(result.returnData)
		} else if result.returnCode == 2 { // SUICIDE
			// TODO: Suicide support logic should be moved to Env to be shared by VM implementations
			state := self.Env().State()
			receiverAddr := llvm2hashRef(bswap(&self.data.address))
			receiver := state.GetOrNewStateObject(receiverAddr)
			balance := state.GetBalance(me.Address())
			receiver.AddAmount(balance)
			state.Delete(me.Address())
		}
	}

	return
}

func (self *JitVm) Printf(format string, v ...interface{}) VirtualMachine {
	return self
}

func (self *JitVm) Endl() VirtualMachine {
	return self
}

func (self *JitVm) Env() Environment {
	return self.env
}

//export env_sha3
func env_sha3(dataPtr *byte, length uint64, resultPtr unsafe.Pointer) {
	data := llvm2bytesRef(dataPtr, length)
	hash := crypto.Sha3(data)
	result := (*i256)(resultPtr)
	*result = hash2llvm(hash)
}

//export env_sstore
func env_sstore(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, valuePtr unsafe.Pointer) {
	vm := (*JitVm)(vmPtr)
	index := llvm2hash(bswap((*i256)(indexPtr)))
	value := llvm2hash(bswap((*i256)(valuePtr)))
	value = trim(value)
	if len(value) == 0 {
		prevValue := vm.env.State().GetState(vm.me.Address(), index)
		if len(prevValue) != 0 {
			vm.Env().State().Refund(vm.callerAddr, GasSStoreRefund)
		}
	}

	vm.env.State().SetState(vm.me.Address(), index, value)
}

//export env_sload
func env_sload(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, resultPtr unsafe.Pointer) {
	vm := (*JitVm)(vmPtr)
	index := llvm2hash(bswap((*i256)(indexPtr)))
	value := vm.env.State().GetState(vm.me.Address(), index)
	result := (*i256)(resultPtr)
	*result = hash2llvm(value)
	bswap(result)
}

//export env_balance
func env_balance(_vm unsafe.Pointer, _addr unsafe.Pointer, _result unsafe.Pointer) {
	vm := (*JitVm)(_vm)
	addr := llvm2hash((*i256)(_addr))
	balance := vm.Env().State().GetBalance(addr)
	result := (*i256)(_result)
	*result = big2llvm(balance)
}

//export env_blockhash
func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Pointer) {
	vm := (*JitVm)(_vm)
	number := llvm2big((*i256)(_number))
	result := (*i256)(_result)

	currNumber := vm.Env().BlockNumber()
	limit := big.NewInt(0).Sub(currNumber, big.NewInt(256))
	if number.Cmp(limit) >= 0 && number.Cmp(currNumber) < 0 {
		hash := vm.Env().GetHash(uint64(number.Int64()))
		*result = hash2llvm(hash)
	} else {
		*result = i256{}
	}
}

//export env_call
func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
	vm := (*JitVm)(_vm)

	//fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("Recovered in env_call (depth %d, out %p %d): %s\n", vm.Env().Depth(), outDataPtr, outDataLen, r)
		}
	}()

	balance := vm.Env().State().GetBalance(vm.me.Address())
	value := llvm2big((*i256)(_value))

	if balance.Cmp(value) >= 0 {
		receiveAddr := llvm2hash((*i256)(_receiveAddr))
		inData := C.GoBytes(inDataPtr, C.int(inDataLen))
		outData := llvm2bytesRef(outDataPtr, outDataLen)
		codeAddr := llvm2hash((*i256)(_codeAddr))
		llvmGas := (*i256)(_gas)
		gas := llvm2big(llvmGas)
		var out []byte
		var err error
		if bytes.Equal(codeAddr, receiveAddr) {
			out, err = vm.env.Call(vm.me, codeAddr, inData, gas, vm.price, value)
		} else {
			out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value)
		}
		*llvmGas = big2llvm(gas)
		if err == nil {
			copy(outData, out)
			return true
		}
	}

	return false
}

//export env_create
func env_create(_vm unsafe.Pointer, _gas unsafe.Pointer, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
	vm := (*JitVm)(_vm)

	value := llvm2big((*i256)(_value))
	initData := C.GoBytes(initDataPtr, C.int(initDataLen)) // TODO: Unnecessary if low balance
	result := (*i256)(_result)
	*result = i256{}

	llvmGas := (*i256)(_gas)
	gas := llvm2big(llvmGas)

	ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
	if suberr == nil {
		dataGas := big.NewInt(int64(len(ret))) // TODO: Nto the best design. env.Create can do it, it has the reference to gas counter
		dataGas.Mul(dataGas, GasCreateByte)
		gas.Sub(gas, dataGas)
		*result = hash2llvm(ref.Address())
	}
	*llvmGas = big2llvm(gas)
}

//export env_log
func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1 unsafe.Pointer, _topic2 unsafe.Pointer, _topic3 unsafe.Pointer, _topic4 unsafe.Pointer) {
	vm := (*JitVm)(_vm)

	data := C.GoBytes(dataPtr, C.int(dataLen))

	topics := make([][]byte, 0, 4)
	if _topic1 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic1)))
	}
	if _topic2 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic2)))
	}
	if _topic3 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic3)))
	}
	if _topic4 != nil {
		topics = append(topics, llvm2hash((*i256)(_topic4)))
	}

	vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data))
}

//export env_extcode
func env_extcode(_vm unsafe.Pointer, _addr unsafe.Pointer, o_size *uint64) *byte {
	vm := (*JitVm)(_vm)
	addr := llvm2hash((*i256)(_addr))
	code := vm.Env().State().GetCode(addr)
	*o_size = uint64(len(code))
	return getDataPtr(code)
}
<|endoftext|>


<commit_before>package gengorums

var orderingVariables = `
{{$marshalAny := use "ptypes.MarshalAny" .GenFile}}
{{$unmarshalAny := use "ptypes.UnmarshalAny" .GenFile}}
{{$errorf := use "fmt.Errorf" .GenFile}}
{{$gorumsMsg := use "ordering.Message" .GenFile}}
`

var orderingPreamble = `
	{{- template "trace" .}}

	// get the ID which will be used to return the correct responses for a request
	msgID := c.mgr.nextMsgID()

	// set up a channel to collect replies
	replies := make(chan *orderingResult, c.n)
	c.mgr.putChan(msgID, replies)

	// remove the replies channel when we are done
	defer c.mgr.deleteChan(msgID)
`

var orderingLoop = `
{{if not (hasPerNodeArg .Method) -}}
	data, err := {{$marshalAny}}(in)
	if err != nil {
		return nil, {{$errorf}}("failed to marshal message: %w", err)
	}
	msg := &{{$gorumsMsg}}{
		ID: msgID,
		Method: "{{fullName .Method}}",
		Data: data,
	}
{{end -}}

	// push the message to the nodes
	expected := c.n
	for _, n := range c.nodes {
{{- if hasPerNodeArg .Method}}
		nodeArg := f(in, n.ID())
		if nodeArg == nil {
			expected--
			continue
		}
		data, err := {{$marshalAny}}(nodeArg)
		if err != nil {
			return nil, {{$errorf}}("failed to marshal message: %w", err)
		}
		msg := &{{$gorumsMsg}}{
			ID: msgID,
			Method: "{{fullName .Method}}",
			Data: data,
		}
		{{- end}}
		n.sendQ <- msg
	}
`

var orderingReply = `
	var (
		replyValues = make([]*{{$out}}, 0, expected)
		errs []GRPCError
		quorum      bool
	)

	for {
		select {
		case r := <-replies:
			if r.err != nil {
				errs = append(errs, GRPCError{r.nid, r.err})
				break
			}
			{{template "traceLazyLog"}}
			reply := new({{$out}})
			err := {{$unmarshalAny}}(r.reply, reply)
			if err != nil {
				errs = append(errs, GRPCError{r.nid, {{$errorf}}("failed to unmarshal reply: %w", err)})
				break
			}
			replyValues = append(replyValues, reply)
			if resp, quorum = c.qspec.{{$method}}QF({{withQFArg .Method "in, "}}replyValues); quorum {
				return resp, nil
			}
		case <-ctx.Done():
			return resp, QuorumCallError{ctx.Err().Error(), len(replyValues), errs}
		}

		if len(errs)+len(replyValues) == expected {
			return resp, QuorumCallError{"incomplete call", len(replyValues), errs}
		}
	}
}
`

var orderingHandler = `
// {{$method}}Handler is the server API for the {{$method}} rpc.
type {{$method}}Handler interface {
	{{$method}}(*{{$in}}) (*{{$out}})
}

// Register{{$method}}Handler sets the handler for {{$method}}.
func (s *GorumsServer) Register{{$method}}Handler(handler {{$method}}Handler) {
	s.srv.registerHandler("{{fullName .Method}}", func(in *{{$gorumsMsg}}) *{{$gorumsMsg}} {
		req := new({{$in}})
		err := {{$unmarshalAny}}(in.GetData(), req)
		// TODO: how to handle marshaling errors here
		if err != nil {
			return new({{$gorumsMsg}})
		}
		resp := handler.{{$method}}(req)
		data, err := {{$marshalAny}}(resp)
		if err != nil {
			return new({{$gorumsMsg}})
		}
		return &{{$gorumsMsg}}{Data: data, Method: in.GetMethod()}
	})
}
`

var orderingQC = commonVariables +
	quorumCallVariables +
	orderingVariables +
	quorumCallComment +
	quorumCallSignature +
	orderingPreamble +
	orderingLoop +
	orderingReply +
	orderingHandler
<commit_msg>removed indent on template to make more readable<commit_after>package gengorums

var orderingVariables = `
{{$marshalAny := use "ptypes.MarshalAny" .GenFile}}
{{$unmarshalAny := use "ptypes.UnmarshalAny" .GenFile}}
{{$errorf := use "fmt.Errorf" .GenFile}}
{{$gorumsMsg := use "ordering.Message" .GenFile}}
`

var orderingPreamble = `
	{{- template "trace" .}}

	// get the ID which will be used to return the correct responses for a request
	msgID := c.mgr.nextMsgID()

	// set up a channel to collect replies
	replies := make(chan *orderingResult, c.n)
	c.mgr.putChan(msgID, replies)

	// remove the replies channel when we are done
	defer c.mgr.deleteChan(msgID)
`

var orderingLoop = `
{{if not (hasPerNodeArg .Method) -}}
	data, err := {{$marshalAny}}(in)
	if err != nil {
		return nil, {{$errorf}}("failed to marshal message: %w", err)
	}
	msg := &{{$gorumsMsg}}{
		ID: msgID,
		Method: "{{fullName .Method}}",
		Data: data,
	}
{{end -}}

	// push the message to the nodes
	expected := c.n
	for _, n := range c.nodes {
{{- if hasPerNodeArg .Method}}
		nodeArg := f(in, n.ID())
		if nodeArg == nil {
			expected--
			continue
		}
		data, err := {{$marshalAny}}(nodeArg)
		if err != nil {
			return nil, {{$errorf}}("failed to marshal message: %w", err)
		}
		msg := &{{$gorumsMsg}}{
			ID: msgID,
			Method: "{{fullName .Method}}",
			Data: data,
		}
{{- end}}
		n.sendQ <- msg
	}
`

var orderingReply = `
	var (
		replyValues = make([]*{{$out}}, 0, expected)
		errs []GRPCError
		quorum      bool
	)

	for {
		select {
		case r := <-replies:
			if r.err != nil {
				errs = append(errs, GRPCError{r.nid, r.err})
				break
			}
			{{template "traceLazyLog"}}
			reply := new({{$out}})
			err := {{$unmarshalAny}}(r.reply, reply)
			if err != nil {
				errs = append(errs, GRPCError{r.nid, {{$errorf}}("failed to unmarshal reply: %w", err)})
				break
			}
			replyValues = append(replyValues, reply)
			if resp, quorum = c.qspec.{{$method}}QF({{withQFArg .Method "in, "}}replyValues); quorum {
				return resp, nil
			}
		case <-ctx.Done():
			return resp, QuorumCallError{ctx.Err().Error(), len(replyValues), errs}
		}

		if len(errs)+len(replyValues) == expected {
			return resp, QuorumCallError{"incomplete call", len(replyValues), errs}
		}
	}
}
`

var orderingHandler = `
// {{$method}}Handler is the server API for the {{$method}} rpc.
type {{$method}}Handler interface {
	{{$method}}(*{{$in}}) (*{{$out}})
}

// Register{{$method}}Handler sets the handler for {{$method}}.
func (s *GorumsServer) Register{{$method}}Handler(handler {{$method}}Handler) {
	s.srv.registerHandler("{{fullName .Method}}", func(in *{{$gorumsMsg}}) *{{$gorumsMsg}} {
		req := new({{$in}})
		err := {{$unmarshalAny}}(in.GetData(), req)
		// TODO: how to handle marshaling errors here
		if err != nil {
			return new({{$gorumsMsg}})
		}
		resp := handler.{{$method}}(req)
		data, err := {{$marshalAny}}(resp)
		if err != nil {
			return new({{$gorumsMsg}})
		}
		return &{{$gorumsMsg}}{Data: data, Method: in.GetMethod()}
	})
}
`

var orderingQC = commonVariables +
	quorumCallVariables +
	orderingVariables +
	quorumCallComment +
	quorumCallSignature +
	orderingPreamble +
	orderingLoop +
	orderingReply +
	orderingHandler
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/jmervine/env"
)

func init() {
	// set default port if not set
	env.GetOrSetInt("PORT", 3000)
	env.GetOrSetString("ADDR", "0.0.0.0")

	app := os.Getenv("APP_NAME")
	if app == "" {
		app = "noop-server"
	}

	log.SetPrefix("app=" + app + " ")
	log.SetOutput(os.Stdout)
	log.SetFlags(0)
}

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		begin := time.Now()
		status := http.StatusOK

		defer func() {
			logPrefix := fmt.Sprintf("at=main on=http.HandleFunc method=%s path=%s", r.Method, r.URL.Path)
			log.Printf("%s status=%d took=%v\n", logPrefix, status, time.Since(begin))
			if env.GetBool("VERBOSE") {
				log.Printf("%s headers:\n%s", r.Header)
				body, err := ioutil.ReadAll(r.Body)
				if err == nil {
					log.Printf("%s body:\n%s", string(body))
				}
			}
		}()

		statusHeader := r.Header.Get("X-HTTP-Status")
		if statusHeader != "" {
			i, e := strconv.ParseInt(statusHeader, 10, 16)
			if e == nil {
				status = int(i)
			} else {
				status = 500
			}
		}

		http.Error(w, fmt.Sprintf("%d %s", status, http.StatusText(status)), status)
	})

	log.Printf("at=main on=startup addr=%s port=%s\n", env.Get("ADDR"), env.Get("PORT"))
	log.Fatal(http.ListenAndServe(env.Get("ADDR")+":"+env.Get("PORT"), nil))
}
<commit_msg>simplify env args<commit_after>package main

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

var (
	port, addr, app string
	verbose         bool
)

func init() {
	port = os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}

	addr = os.Getenv("ADDR")
	if addr == "" {
		addr = "0.0.0.0"
	}

	app = os.Getenv("APP_NAME")
	if app == "" {
		app = "noop-server"
	}

	if os.Getenv("VERBOSE") != "" {
		verbose = true
	}

	log.SetPrefix("app=" + app + " ")
	log.SetOutput(os.Stdout)
	log.SetFlags(0)
}

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		begin := time.Now()
		status := http.StatusOK

		defer func() {
			logPrefix := fmt.Sprintf("at=main on=http.HandleFunc method=%s path=%s", r.Method, r.URL.Path)
			log.Printf("%s status=%d took=%v\n", logPrefix, status, time.Since(begin))
			if verbose {
				log.Printf("%s headers:\n%s", r.Header)
				body, err := ioutil.ReadAll(r.Body)
				if err == nil {
					log.Printf("%s body:\n%s", string(body))
				}
			}
		}()

		statusHeader := r.Header.Get("X-HTTP-Status")
		if statusHeader != "" {
			i, e := strconv.ParseInt(statusHeader, 10, 16)
			if e == nil {
				status = int(i)
			} else {
				status = 500
			}
		}

		http.Error(w, fmt.Sprintf("%d %s", status, http.StatusText(status)), status)
	})

	log.Printf("at=main on=startup addr=%s port=%s\n", addr, port)
	log.Fatal(http.ListenAndServe(addr+":"+port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/url"
	"strings"
	"text/template"

	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/host/types"
	tc "github.com/flynn/flynn/test/cluster"
	"github.com/flynn/flynn/updater/types"
	c "github.com/flynn/go-check"
)

type ReleaseSuite struct {
	Helper
}

var _ = c.ConcurrentSuite(&ReleaseSuite{})

func (s *ReleaseSuite) addReleaseHosts(t *c.C) *tc.BootResult {
	res, err := testCluster.AddReleaseHosts()
	t.Assert(err, c.IsNil)
	t.Assert(res.Instances, c.HasLen, 4)
	return res
}

var releaseScript = bytes.NewReader([]byte(`
export TUF_TARGETS_PASSPHRASE="flynn-test"
export TUF_SNAPSHOT_PASSPHRASE="flynn-test"
export TUF_TIMESTAMP_PASSPHRASE="flynn-test"

export GOPATH=~/go
src="${GOPATH}/src/github.com/flynn/flynn"

# send all output to stderr so only version.json is output to stdout
(

  # rebuild components.
  #
  # ideally we would use tup to do this, but it hangs waiting on the
  # FUSE socket after building, so for now we do it manually.
  #
  # See https://github.com/flynn/flynn/issues/949
  pushd "${src}" >/dev/null
  sed "s/{{TUF-ROOT-KEYS}}/$(tuf --dir test/release root-keys)/g" host/cli/root_keys.go.tmpl > host/cli/root_keys.go
  vpkg="github.com/flynn/flynn/pkg/version"
  go build -o host/bin/flynn-host -ldflags="-X ${vpkg}.commit notdev -X ${vpkg}.branch dev -X ${vpkg}.tag v20160707.0-test -X ${vpkg}.dirty false" ./host
  gzip -9 --keep --force host/bin/flynn-host
  sed "s/{{FLYNN-HOST-CHECKSUM}}/$(sha512sum host/bin/flynn-host.gz | cut -d " " -f 1)/g" script/install-flynn.tmpl > script/install-flynn

  # create new images
  test/scripts/wait-for-docker
  for name in $(docker images | grep ^flynn | awk '{print $1}'); do
    docker build -t $name - < <(echo -e "FROM $name\nRUN /bin/true")
  done

  util/release/flynn-release manifest util/release/version_template.json > version.json
  popd >/dev/null

  "${src}/script/export-components" --no-compress "${src}/test/release"
  "${src}/script/release-channel" --tuf-dir "${src}/test/release" --no-sync --no-changelog "stable" "v20160707.0-test"

  dir=$(mktemp --directory)
  ln -s "${src}/test/release/repository" "${dir}/tuf"
  ln -s "${src}/script/install-flynn" "${dir}/install-flynn"

  # create a slug for testing slug based app updates
  tar c -C "${src}/test/apps/http" . | docker run -i -a stdin -a stdout -a stderr flynn/slugbuilder - > "${dir}/slug.tgz"

  # start a file server to serve the exported components
  sudo start-stop-daemon \
    --start \
    --background \
    --chdir "${dir}" \
    --exec "${src}/test/bin/flynn-test-file-server"
) >&2

cat "${src}/version.json"
`))

var installScript = template.Must(template.New("install-script").Parse(`
# download to a tmp file so the script fails on download error rather than
# executing nothing and succeeding
curl -sL --fail http://{{ .Blobstore }}/install-flynn > /tmp/install-flynn
bash -e /tmp/install-flynn -r "http://{{ .Blobstore }}"
`))

var updateScript = template.Must(template.New("update-script").Parse(`
timeout --signal=QUIT --kill-after=10 10m bash -ex <<-SCRIPT
cd ~/go/src/github.com/flynn/flynn
tuf --dir test/release root-keys | tuf-client init --store /tmp/tuf.db http://{{ .Blobstore }}/tuf
echo stable | sudo tee /etc/flynn/channel.txt
flynn-host update --repository http://{{ .Blobstore }}/tuf --tuf-db /tmp/tuf.db
SCRIPT
`))

func (s *ReleaseSuite) TestReleaseImages(t *c.C) {
	if testCluster == nil {
		t.Skip("cannot boot release cluster")
	}

	// stream script output to t.Log
	logReader, logWriter := io.Pipe()
	defer logWriter.Close()
	go func() {
		buf := bufio.NewReader(logReader)
		for {
			line, err := buf.ReadString('\n')
			if err != nil {
				return
			}
			debug(t, line[0:len(line)-1])
		}
	}()

	// boot the release cluster, release components to a blobstore and output the new version.json
	releaseCluster := s.addReleaseHosts(t)
	buildHost := releaseCluster.Instances[0]
	var versionJSON bytes.Buffer
	t.Assert(buildHost.Run("bash -ex", &tc.Streams{Stdin: releaseScript, Stdout: &versionJSON, Stderr: logWriter}), c.IsNil)
	var versions map[string]string
	t.Assert(json.Unmarshal(versionJSON.Bytes(), &versions), c.IsNil)

	// install Flynn from the blobstore on the vanilla host
	blobstore := struct{ Blobstore string }{buildHost.IP + ":8080"}
	installHost := releaseCluster.Instances[3]
	var script bytes.Buffer
	installScript.Execute(&script, blobstore)
	var installOutput bytes.Buffer
	out := io.MultiWriter(logWriter, &installOutput)
	t.Assert(installHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check the flynn-host version is correct
	var hostVersion bytes.Buffer
	t.Assert(installHost.Run("flynn-host version", &tc.Streams{Stdout: &hostVersion}), c.IsNil)
	t.Assert(strings.TrimSpace(hostVersion.String()), c.Equals, "v20160707.0-test")

	// check rebuilt images were downloaded
	for name, id := range versions {
		expected := fmt.Sprintf("%s image %s downloaded", name, id)
		if !strings.Contains(installOutput.String(), expected) {
			t.Fatalf(`expected install to download %s %s`, name, id)
		}
	}

	// installing on an instance with Flynn running should not fail
	script.Reset()
	installScript.Execute(&script, blobstore)
	t.Assert(buildHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: logWriter, Stderr: logWriter}), c.IsNil)

	// create a controller client for the release cluster
	pin, err := base64.StdEncoding.DecodeString(releaseCluster.ControllerPin)
	t.Assert(err, c.IsNil)
	client, err := controller.NewClientWithConfig(
		"https://"+buildHost.IP,
		releaseCluster.ControllerKey,
		controller.Config{Pin: pin, Domain: releaseCluster.ControllerDomain},
	)
	t.Assert(err, c.IsNil)

	// deploy a slug based app
	slugApp := &ct.App{}
	t.Assert(client.CreateApp(slugApp), c.IsNil)
	gitreceive, err := client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	imageArtifact := &ct.Artifact{Type: host.ArtifactTypeDocker, URI: gitreceive.Env["SLUGRUNNER_IMAGE_URI"]}
	t.Assert(client.CreateArtifact(imageArtifact), c.IsNil)
	slugArtifact := &ct.Artifact{Type: host.ArtifactTypeFile, URI: fmt.Sprintf("http://%s:8080/slug.tgz", buildHost.IP)}
	t.Assert(client.CreateArtifact(slugArtifact), c.IsNil)
	release := &ct.Release{
		ArtifactIDs: []string{imageArtifact.ID, slugArtifact.ID},
		Processes:   map[string]ct.ProcessType{"web": {Cmd: []string{"bin/http"}}},
	}
	t.Assert(client.CreateRelease(release), c.IsNil)
	t.Assert(client.SetAppRelease(slugApp.ID, release.ID), c.IsNil)
	watcher, err := client.WatchJobEvents(slugApp.ID, release.ID)
	t.Assert(err, c.IsNil)
	defer watcher.Close()
	t.Assert(client.PutFormation(&ct.Formation{
		AppID:     slugApp.ID,
		ReleaseID: release.ID,
		Processes: map[string]int{"web": 1},
	}), c.IsNil)
	err = watcher.WaitFor(ct.JobEvents{"web": {ct.JobStateUp: 1}}, scaleTimeout, nil)
	t.Assert(err, c.IsNil)

	// run a cluster update from the blobstore
	updateHost := releaseCluster.Instances[1]
	script.Reset()
	updateScript.Execute(&script, blobstore)
	var updateOutput bytes.Buffer
	out = io.MultiWriter(logWriter, &updateOutput)
	t.Assert(updateHost.Run("bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check rebuilt images were downloaded
	for name := range versions {
		for _, host := range releaseCluster.Instances[0:2] {
			expected := fmt.Sprintf(`"pulled image" host=%s name=%s`, host.ID, name)
			if !strings.Contains(updateOutput.String(), expected) {
				t.Fatalf(`expected update to download %s on host %s`, name, host.ID)
			}
		}
	}

	assertImage := func(uri, image string) {
		u, err := url.Parse(uri)
		t.Assert(err, c.IsNil)
		t.Assert(u.Query().Get("id"), c.Equals, versions[image])
	}

	// check system apps were deployed correctly
	for _, app := range updater.SystemApps {
		if app.ImageOnly {
			continue // we don't deploy ImageOnly updates
		}
		if app.Image == "" {
			app.Image = "flynn/" + app.Name
		}
		debugf(t, "checking new %s release is using image %s", app.Name, versions[app.Image])
		expected := fmt.Sprintf(`"finished deploy of system app" name=%s`, app.Name)
		if !strings.Contains(updateOutput.String(), expected) {
			t.Fatalf(`expected update to deploy %s`, app.Name)
		}
		release, err := client.GetAppRelease(app.Name)
		t.Assert(err, c.IsNil)
		debugf(t, "new %s release ID: %s", app.Name, release.ID)
		artifact, err := client.GetArtifact(release.ImageArtifactID())
		t.Assert(err, c.IsNil)
		debugf(t, "new %s artifact: %+v", app.Name, artifact)
		assertImage(artifact.URI, app.Image)
	}

	// check gitreceive has the correct slug env vars
	gitreceive, err = client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	assertImage(gitreceive.Env["SLUGBUILDER_IMAGE_URI"], "flynn/slugbuilder")
	assertImage(gitreceive.Env["SLUGRUNNER_IMAGE_URI"], "flynn/slugrunner")

	// check slug based app was deployed correctly
	release, err = client.GetAppRelease(slugApp.Name)
	t.Assert(err, c.IsNil)
	imageArtifact, err = client.GetArtifact(release.ImageArtifactID())
	t.Assert(err, c.IsNil)
	assertImage(imageArtifact.URI, "flynn/slugrunner")
}
<commit_msg>test: Bump version in TestReleaseImages<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/url"
	"strings"
	"text/template"

	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/host/types"
	tc "github.com/flynn/flynn/test/cluster"
	"github.com/flynn/flynn/updater/types"
	c "github.com/flynn/go-check"
)

type ReleaseSuite struct {
	Helper
}

var _ = c.ConcurrentSuite(&ReleaseSuite{})

func (s *ReleaseSuite) addReleaseHosts(t *c.C) *tc.BootResult {
	res, err := testCluster.AddReleaseHosts()
	t.Assert(err, c.IsNil)
	t.Assert(res.Instances, c.HasLen, 4)
	return res
}

var releaseScript = bytes.NewReader([]byte(`
export TUF_TARGETS_PASSPHRASE="flynn-test"
export TUF_SNAPSHOT_PASSPHRASE="flynn-test"
export TUF_TIMESTAMP_PASSPHRASE="flynn-test"

export GOPATH=~/go
src="${GOPATH}/src/github.com/flynn/flynn"

# send all output to stderr so only version.json is output to stdout
(

  # rebuild components.
  #
  # ideally we would use tup to do this, but it hangs waiting on the
  # FUSE socket after building, so for now we do it manually.
  #
  # See https://github.com/flynn/flynn/issues/949
  pushd "${src}" >/dev/null
  sed "s/{{TUF-ROOT-KEYS}}/$(tuf --dir test/release root-keys)/g" host/cli/root_keys.go.tmpl > host/cli/root_keys.go
  vpkg="github.com/flynn/flynn/pkg/version"
  go build -o host/bin/flynn-host -ldflags="-X ${vpkg}.commit notdev -X ${vpkg}.branch dev -X ${vpkg}.tag v20160711.0-test -X ${vpkg}.dirty false" ./host
  gzip -9 --keep --force host/bin/flynn-host
  sed "s/{{FLYNN-HOST-CHECKSUM}}/$(sha512sum host/bin/flynn-host.gz | cut -d " " -f 1)/g" script/install-flynn.tmpl > script/install-flynn

  # create new images
  test/scripts/wait-for-docker
  for name in $(docker images | grep ^flynn | awk '{print $1}'); do
    docker build -t $name - < <(echo -e "FROM $name\nRUN /bin/true")
  done

  util/release/flynn-release manifest util/release/version_template.json > version.json
  popd >/dev/null

  "${src}/script/export-components" --no-compress "${src}/test/release"
  "${src}/script/release-channel" --tuf-dir "${src}/test/release" --no-sync --no-changelog "stable" "v20160711.0-test"

  dir=$(mktemp --directory)
  ln -s "${src}/test/release/repository" "${dir}/tuf"
  ln -s "${src}/script/install-flynn" "${dir}/install-flynn"

  # create a slug for testing slug based app updates
  tar c -C "${src}/test/apps/http" . | docker run -i -a stdin -a stdout -a stderr flynn/slugbuilder - > "${dir}/slug.tgz"

  # start a file server to serve the exported components
  sudo start-stop-daemon \
    --start \
    --background \
    --chdir "${dir}" \
    --exec "${src}/test/bin/flynn-test-file-server"
) >&2

cat "${src}/version.json"
`))

var installScript = template.Must(template.New("install-script").Parse(`
# download to a tmp file so the script fails on download error rather than
# executing nothing and succeeding
curl -sL --fail http://{{ .Blobstore }}/install-flynn > /tmp/install-flynn
bash -e /tmp/install-flynn -r "http://{{ .Blobstore }}"
`))

var updateScript = template.Must(template.New("update-script").Parse(`
timeout --signal=QUIT --kill-after=10 10m bash -ex <<-SCRIPT
cd ~/go/src/github.com/flynn/flynn
tuf --dir test/release root-keys | tuf-client init --store /tmp/tuf.db http://{{ .Blobstore }}/tuf
echo stable | sudo tee /etc/flynn/channel.txt
flynn-host update --repository http://{{ .Blobstore }}/tuf --tuf-db /tmp/tuf.db
SCRIPT
`))

func (s *ReleaseSuite) TestReleaseImages(t *c.C) {
	if testCluster == nil {
		t.Skip("cannot boot release cluster")
	}

	// stream script output to t.Log
	logReader, logWriter := io.Pipe()
	defer logWriter.Close()
	go func() {
		buf := bufio.NewReader(logReader)
		for {
			line, err := buf.ReadString('\n')
			if err != nil {
				return
			}
			debug(t, line[0:len(line)-1])
		}
	}()

	// boot the release cluster, release components to a blobstore and output the new version.json
	releaseCluster := s.addReleaseHosts(t)
	buildHost := releaseCluster.Instances[0]
	var versionJSON bytes.Buffer
	t.Assert(buildHost.Run("bash -ex", &tc.Streams{Stdin: releaseScript, Stdout: &versionJSON, Stderr: logWriter}), c.IsNil)
	var versions map[string]string
	t.Assert(json.Unmarshal(versionJSON.Bytes(), &versions), c.IsNil)

	// install Flynn from the blobstore on the vanilla host
	blobstore := struct{ Blobstore string }{buildHost.IP + ":8080"}
	installHost := releaseCluster.Instances[3]
	var script bytes.Buffer
	installScript.Execute(&script, blobstore)
	var installOutput bytes.Buffer
	out := io.MultiWriter(logWriter, &installOutput)
	t.Assert(installHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check the flynn-host version is correct
	var hostVersion bytes.Buffer
	t.Assert(installHost.Run("flynn-host version", &tc.Streams{Stdout: &hostVersion}), c.IsNil)
	t.Assert(strings.TrimSpace(hostVersion.String()), c.Equals, "v20160711.0-test")

	// check rebuilt images were downloaded
	for name, id := range versions {
		expected := fmt.Sprintf("%s image %s downloaded", name, id)
		if !strings.Contains(installOutput.String(), expected) {
			t.Fatalf(`expected install to download %s %s`, name, id)
		}
	}

	// installing on an instance with Flynn running should not fail
	script.Reset()
	installScript.Execute(&script, blobstore)
	t.Assert(buildHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: logWriter, Stderr: logWriter}), c.IsNil)

	// create a controller client for the release cluster
	pin, err := base64.StdEncoding.DecodeString(releaseCluster.ControllerPin)
	t.Assert(err, c.IsNil)
	client, err := controller.NewClientWithConfig(
		"https://"+buildHost.IP,
		releaseCluster.ControllerKey,
		controller.Config{Pin: pin, Domain: releaseCluster.ControllerDomain},
	)
	t.Assert(err, c.IsNil)

	// deploy a slug based app
	slugApp := &ct.App{}
	t.Assert(client.CreateApp(slugApp), c.IsNil)
	gitreceive, err := client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	imageArtifact := &ct.Artifact{Type: host.ArtifactTypeDocker, URI: gitreceive.Env["SLUGRUNNER_IMAGE_URI"]}
	t.Assert(client.CreateArtifact(imageArtifact), c.IsNil)
	slugArtifact := &ct.Artifact{Type: host.ArtifactTypeFile, URI: fmt.Sprintf("http://%s:8080/slug.tgz", buildHost.IP)}
	t.Assert(client.CreateArtifact(slugArtifact), c.IsNil)
	release := &ct.Release{
		ArtifactIDs: []string{imageArtifact.ID, slugArtifact.ID},
		Processes:   map[string]ct.ProcessType{"web": {Cmd: []string{"bin/http"}}},
	}
	t.Assert(client.CreateRelease(release), c.IsNil)
	t.Assert(client.SetAppRelease(slugApp.ID, release.ID), c.IsNil)
	watcher, err := client.WatchJobEvents(slugApp.ID, release.ID)
	t.Assert(err, c.IsNil)
	defer watcher.Close()
	t.Assert(client.PutFormation(&ct.Formation{
		AppID:     slugApp.ID,
		ReleaseID: release.ID,
		Processes: map[string]int{"web": 1},
	}), c.IsNil)
	err = watcher.WaitFor(ct.JobEvents{"web": {ct.JobStateUp: 1}}, scaleTimeout, nil)
	t.Assert(err, c.IsNil)

	// run a cluster update from the blobstore
	updateHost := releaseCluster.Instances[1]
	script.Reset()
	updateScript.Execute(&script, blobstore)
	var updateOutput bytes.Buffer
	out = io.MultiWriter(logWriter, &updateOutput)
	t.Assert(updateHost.Run("bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check rebuilt images were downloaded
	for name := range versions {
		for _, host := range releaseCluster.Instances[0:2] {
			expected := fmt.Sprintf(`"pulled image" host=%s name=%s`, host.ID, name)
			if !strings.Contains(updateOutput.String(), expected) {
				t.Fatalf(`expected update to download %s on host %s`, name, host.ID)
			}
		}
	}

	assertImage := func(uri, image string) {
		u, err := url.Parse(uri)
		t.Assert(err, c.IsNil)
		t.Assert(u.Query().Get("id"), c.Equals, versions[image])
	}

	// check system apps were deployed correctly
	for _, app := range updater.SystemApps {
		if app.ImageOnly {
			continue // we don't deploy ImageOnly updates
		}
		if app.Image == "" {
			app.Image = "flynn/" + app.Name
		}
		debugf(t, "checking new %s release is using image %s", app.Name, versions[app.Image])
		expected := fmt.Sprintf(`"finished deploy of system app" name=%s`, app.Name)
		if !strings.Contains(updateOutput.String(), expected) {
			t.Fatalf(`expected update to deploy %s`, app.Name)
		}
		release, err := client.GetAppRelease(app.Name)
		t.Assert(err, c.IsNil)
		debugf(t, "new %s release ID: %s", app.Name, release.ID)
		artifact, err := client.GetArtifact(release.ImageArtifactID())
		t.Assert(err, c.IsNil)
		debugf(t, "new %s artifact: %+v", app.Name, artifact)
		assertImage(artifact.URI, app.Image)
	}

	// check gitreceive has the correct slug env vars
	gitreceive, err = client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	assertImage(gitreceive.Env["SLUGBUILDER_IMAGE_URI"], "flynn/slugbuilder")
	assertImage(gitreceive.Env["SLUGRUNNER_IMAGE_URI"], "flynn/slugrunner")

	// check slug based app was deployed correctly
	release, err = client.GetAppRelease(slugApp.Name)
	t.Assert(err, c.IsNil)
	imageArtifact, err = client.GetArtifact(release.ImageArtifactID())
	t.Assert(err, c.IsNil)
	assertImage(imageArtifact.URI, "flynn/slugrunner")
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"log"
	"time"

	"github.com/jroimartin/gocui"
	"github.com/mephux/komanda-cli/komanda/client"
	"github.com/mephux/komanda-cli/komanda/ui"
)

type ConnectCmd struct {
	*MetadataTmpl
}

func (e *ConnectCmd) Metadata() CommandMetadata {
	return e
}

func (e *ConnectCmd) Exec(args []string) error {

	Server.Exec(client.StatusChannel, func(g *gocui.Gui, v *gocui.View, s *client.Server) error {

		if s.Client.Connected() {
			client.StatusMessage(v, "Already Connecting and/or Connected...")
			return nil
		}

		client.StatusMessage(v, "Connecting... please wait.")

		if err := s.Client.Connect(); err != nil {
			log.Fatal(err)
		}

		go func() {
			ticker := time.NewTicker(8000 * time.Microsecond)

			for {
				select {
				case <-ticker.C:
					Server.Exec(client.StatusChannel, func(g *gocui.Gui, v *gocui.View, s *client.Server) error {
						fmt.Fprint(v, ".")
						return nil
					})
				case msg := <-ui.LoadingChannel:
					if msg == "done" {
						fmt.Fprint(v, "\n")
						ticker.Stop()
					}
				}
			}
		}()

		return nil
	})

	return nil
}

func connectCmd() Command {
	return &ConnectCmd{
		MetadataTmpl: &MetadataTmpl{
			name: "connect",
			aliases: []string{
				"c",
			},
			description: "connect to irc using passed arguments",
		},
	}
}
<commit_msg>cleanup<commit_after>package command

import (
	"fmt"
	"log"
	"time"

	"github.com/jroimartin/gocui"
	"github.com/mephux/komanda-cli/komanda/client"
	"github.com/mephux/komanda-cli/komanda/ui"
)

type ConnectCmd struct {
	*MetadataTmpl
}

func (e *ConnectCmd) Metadata() CommandMetadata {
	return e
}

func (e *ConnectCmd) Exec(args []string) error {

	Server.Exec(client.StatusChannel, func(g *gocui.Gui, v *gocui.View, s *client.Server) error {

		if s.Client.Connected() {
			client.StatusMessage(v, "Already Connecting and/or Connected...")
			return nil
		}

		client.StatusMessage(v, "Connecting... please wait.")

		if err := s.Client.Connect(); err != nil {
			log.Fatal(err)
		}

		go func() {
			ticker := time.NewTicker(8000 * time.Microsecond)

			for {
				select {
				case <-ticker.C:
					fmt.Fprint(v, ".")
				case msg := <-ui.LoadingChannel:
					if msg == "done" {
						fmt.Fprint(v, "\n")
						ticker.Stop()
						close(ui.LoadingChannel)
						break
					}
				}
			}
		}()

		return nil
	})

	return nil
}

func connectCmd() Command {
	return &ConnectCmd{
		MetadataTmpl: &MetadataTmpl{
			name: "connect",
			aliases: []string{
				"c",
			},
			description: "connect to irc using passed arguments",
		},
	}
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package protocol

import (
	"net"
	"math/rand"
	"time"
	"runtime"
	"io"
	"errors"
	"sync"
	"github.com/winlinvip/go-srs/core"
)

var RtmpInChannelMsg = errors.New("put msg to channel failed")

type Conn struct {
	SrsId int
	Server *Server
	IoRw *net.TCPConn
	Logger core.Logger
	Rand *rand.Rand // the random to generate the handshake bytes.
	InChannel chan *RtmpMessage // the incoming messages channel
	OutChannel chan *RtmpMessage // the outgoing messages channel
	Protocol *Protocol // the protocol stack.
	Stage Stage // the stage of connection.
	Request RtmpRequest // the request of client
	// quit sync
	Quited bool
	QuitLock sync.Mutex
	QuitChannel chan int // the quit signal for connection serve cycle
}

func (conn *Conn) Serve() {
	defer func(){
		// any error for each connection must be recover
		if err := recover(); err != nil {
			const size = 64 << 10
			buf := make([]byte, size)
			buf = buf[:runtime.Stack(buf, false)]
			conn.Logger.Error("rtmp: panic serving %v\n%v\n%s", conn.IoRw.RemoteAddr(), err, buf)
		}

		// quit.
		func(){
			conn.QuitLock.Lock()
			defer conn.QuitLock.Unlock()

			conn.IoRw.Close()
			close(conn.InChannel)
			close(conn.OutChannel)
			close(conn.QuitChannel)
			conn.Quited = true
			conn.Logger.Info("conn quit")
		}()
	}()
	conn.Logger.Trace("serve client ip=%v", conn.IoRw.RemoteAddr().String())

	if err := conn.IoRw.SetNoDelay(false); err != nil {
		conn.Logger.Error("tcp SetNoDelay failed, err is %v", err)
		return
	}
	conn.Logger.Info("tcp SetNoDelay ok")

	hs := SimpleHandshake{}
	if err := hs.WithClient(conn); err != nil {
		conn.Logger.Error("handshake failed, err is %v", err)
		return
	}
	conn.Logger.Trace("simple handshake with client ok")

	// set stage to connect app.
	conn.Stage = conn.Server.Factory.NewConnectStage(conn)

	// pump and send message goroutine
	go conn.pumpMessage()
	go conn.sendMessage()

	// rtmp msg loop
	if err := conn.recvMessage(); err != nil {
		conn.Logger.Error("message cycle failed, err is %v", err)
		return
	}
	conn.Logger.Trace("serve conn ok")
}

func (conn *Conn) recvMessage() (err error) {
	for {
		select {
			// when got quit messgae
		case <- conn.QuitChannel:
			return
			// when incoming message, process it.
		case msg, ok := <-conn.InChannel:
			if !ok {
				return
			}
			conn.Logger.Info("consume received msg %v", msg)
			if err = conn.Stage.ConsumeMessage(msg); err != nil {
				return
			}
			continue
		}
	}
}

func (conn *Conn) sendMessage() (err error) {
	defer func(){
		// any error for each connection msg pump must be recover
		if err := recover(); err != nil {
			const size = 64 << 10
			buf := make([]byte, size)
			buf = buf[:runtime.Stack(buf, false)]
			conn.Logger.Error("rtmp: panic send message %v\n%v\n%s", conn.IoRw.RemoteAddr(), err, buf)
		}

		func(){
			conn.QuitLock.Lock()
			defer conn.QuitLock.Unlock()

			if !conn.Quited {
				conn.Logger.Info("send goroutine signal quit channel")
				conn.QuitChannel <- 101
			} else {
				conn.Logger.Info("send goroutine siliently quit")
			}
		}()

		conn.Logger.Info("stop send rtmp messages")
	}()
	conn.Logger.Info("start send rtmp messages")

	for {
		select {
			// when got msg to send, send it immeidately.
		case msg,ok := <- conn.OutChannel:
			if !ok {
				return
			}
			conn.Logger.Info("send msg %v", msg)
			if err = conn.Protocol.SendMessage(msg); err != nil {
				return
			}
			continue
		}
	}
}

func (conn *Conn) pumpMessage() {
	defer func(){
		// any error for each connection msg pump must be recover
		if err := recover(); err != nil {
			const size = 64 << 10
			buf := make([]byte, size)
			buf = buf[:runtime.Stack(buf, false)]
			conn.Logger.Error("rtmp: panic pump message %v\n%v\n%s", conn.IoRw.RemoteAddr(), err, buf)
		}

		func(){
			conn.QuitLock.Lock()
			defer conn.QuitLock.Unlock()

			if !conn.Quited {
				conn.Logger.Info("pump goroutine signal quit channel")
				conn.QuitChannel <- 100
			} else {
				conn.Logger.Info("pump goroutine siliently quit")
			}
		}()

		conn.Logger.Info("stop pump rtmp messages")
	}()
	conn.Logger.Info("start pump rtmp messages")

	for {
		var msg *RtmpMessage
		var err error
		if msg,err = conn.Protocol.PumpMessage(); err != nil {
			if err != io.EOF {
				conn.Logger.Error("pump message failed, err is %v", err)
			}
			return
		}

		if msg == nil {
			continue
		}

		if err = conn.EnqueueIncomingMessage(msg); err != nil {
			return
		}
	}
}

func (conn *Conn) EnqueueIncomingMessage(msg *RtmpMessage) (err error) {
	conn.QuitLock.Lock()
	defer conn.QuitLock.Unlock()

	// already quited, drop messgae
	if conn.Quited {
		conn.Logger.Info("drop incoming msg for quited")
		return
	}

	select {
	case conn.InChannel <- msg:
		break
	default:
		conn.Logger.Warn("drop incoming msg for channel full")
		break
	}
	return
}

func (conn *Conn) EnqueueOutgoingMessage(msg *RtmpMessage) (err error) {
	conn.QuitLock.Lock()
	defer conn.QuitLock.Unlock()

	// already quited, drop messgae
	if conn.Quited {
		conn.Logger.Info("drop outgoing msg for quited")
		return
	}

	select {
	case conn.OutChannel <- msg:
		break
	default:
		conn.Logger.Warn("drop message for channel full")
		break
	}
	return
}

func (conn *Conn) SetWindowAckSize(ackSize int) (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpSetWindowAckSizePacket(ackSize), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func (conn *Conn) SetPeerBandwidth(bandwidth, _type int) (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpSetPeerBandwidthPacket(bandwidth, _type), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func (conn *Conn) OnBwDone() (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpOnBWDonePacket(), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func (conn *Conn) ResponseConnectApp(objectEncoding int, serverIp string) (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpConnectAppResPacket(objectEncoding, serverIp, conn.SrsId), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func NewConn(svr *Server, conn *net.TCPConn) *Conn {
	v := &Conn{
		Server: svr,
		IoRw: conn,
		Rand: rand.New(rand.NewSource(time.Now().UnixNano())),
	}

	// the srs id
	v.SrsId = svr.Factory.SrsId()
	v.Logger = svr.Factory.CreateLogger("conn", v.SrsId)

	// TODO: FIXME: channel with buffer
	v.InChannel = make(chan *RtmpMessage)
	v.OutChannel = make(chan *RtmpMessage)

	// quit sync
	v.Quited = false
	v.QuitChannel = make(chan int, 2)

	// initialize the protocol stack.
	v.Protocol = NewProtocol(conn, v.Logger)

	// nil stage for handshake.
	v.Stage = nil

	return v
}
<commit_msg>remove the sync locker for channel.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package protocol

import (
	"net"
	"math/rand"
	"time"
	"runtime"
	"io"
	"errors"
	"github.com/winlinvip/go-srs/core"
)

var RtmpInChannelMsg = errors.New("put msg to channel failed")

type Conn struct {
	SrsId int
	Server *Server
	IoRw *net.TCPConn
	Logger core.Logger
	Rand *rand.Rand // the random to generate the handshake bytes.
	InChannel chan *RtmpMessage // the incoming messages channel
	OutChannel chan *RtmpMessage // the outgoing messages channel
	SendQuitChannel chan int // the quit signal for connection serve cycle
	Protocol *Protocol // the protocol stack.
	Stage Stage // the stage of connection.
	Request RtmpRequest // the request of client
}

func (conn *Conn) Serve() {
	defer func(){
		// any error for each connection must be recover
		if err := recover(); err != nil {
			const size = 64 << 10
			buf := make([]byte, size)
			buf = buf[:runtime.Stack(buf, false)]
			conn.Logger.Error("rtmp: panic serving %v\n%v\n%s", conn.IoRw.RemoteAddr(), err, buf)
		}

		// the out channel is write by this goroutine only
		close(conn.OutChannel)

		// quit.
		conn.IoRw.Close()
		conn.Logger.Info("conn quit")
	}()
	conn.Logger.Trace("serve client ip=%v", conn.IoRw.RemoteAddr().String())

	if err := conn.IoRw.SetNoDelay(false); err != nil {
		conn.Logger.Error("tcp SetNoDelay failed, err is %v", err)
		return
	}
	conn.Logger.Info("tcp SetNoDelay ok")

	hs := SimpleHandshake{}
	if err := hs.WithClient(conn); err != nil {
		conn.Logger.Error("handshake failed, err is %v", err)
		return
	}
	conn.Logger.Trace("simple handshake with client ok")

	// set stage to connect app.
	conn.Stage = conn.Server.Factory.NewConnectStage(conn)

	// pump and send message goroutine
	go conn.pumpMessage()
	go conn.sendMessage()

	// rtmp msg loop
	if err := conn.recvMessage(); err != nil {
		conn.Logger.Error("message cycle failed, err is %v", err)
		return
	}
	conn.Logger.Trace("serve conn ok")
}

func (conn *Conn) recvMessage() (err error) {
	for {
		select {
			// the send message goroutine will close this channel when error
		case <- conn.SendQuitChannel:
			return
			// when incoming message, process it.
			// the pump message goroutine will close this channel when error
		case msg, ok := <- conn.InChannel:
			if !ok {
				return
			}
			conn.Logger.Info("consume received msg %v", msg)
			if err = conn.Stage.ConsumeMessage(msg); err != nil {
				return
			}
			continue
		}
	}
}

func (conn *Conn) sendMessage() (err error) {
	defer func(){
		// any error for each connection msg pump must be recover
		if err := recover(); err != nil {
			const size = 64 << 10
			buf := make([]byte, size)
			buf = buf[:runtime.Stack(buf, false)]
			conn.Logger.Error("rtmp: panic send message %v\n%v\n%s", conn.IoRw.RemoteAddr(), err, buf)
		}

		// the quit channel is write by this goroutine only
		close(conn.SendQuitChannel)

		conn.Logger.Info("stop send rtmp messages")
	}()
	conn.Logger.Info("start send rtmp messages")

	for {
		select {
			// when got msg to send, send it immeidately.
		case msg,ok := <- conn.OutChannel:
			if !ok {
				return
			}
			conn.Logger.Info("send msg %v", msg)
			if err = conn.Protocol.SendMessage(msg); err != nil {
				return
			}
			continue
		}
	}
}

func (conn *Conn) pumpMessage() {
	defer func(){
		// any error for each connection msg pump must be recover
		if err := recover(); err != nil {
			const size = 64 << 10
			buf := make([]byte, size)
			buf = buf[:runtime.Stack(buf, false)]
			conn.Logger.Error("rtmp: panic pump message %v\n%v\n%s", conn.IoRw.RemoteAddr(), err, buf)
		}

		// the in channel is write by this goroutine only
		close(conn.InChannel)

		conn.Logger.Info("stop pump rtmp messages")
	}()
	conn.Logger.Info("start pump rtmp messages")

	for {
		var msg *RtmpMessage
		var err error
		if msg,err = conn.Protocol.PumpMessage(); err != nil {
			if err != io.EOF {
				conn.Logger.Error("pump message failed, err is %v", err)
			}
			return
		}

		if msg == nil {
			continue
		}

		select {
		case conn.InChannel <- msg:
			break
		default:
			conn.Logger.Warn("drop incoming msg for channel full")
			break
		}
	}
}

func (conn *Conn) EnqueueOutgoingMessage(msg *RtmpMessage) (err error) {
	select {
	case conn.OutChannel <- msg:
		break
	default:
		conn.Logger.Warn("drop message for channel full")
		break
	}
	return
}

func (conn *Conn) SetWindowAckSize(ackSize int) (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpSetWindowAckSizePacket(ackSize), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func (conn *Conn) SetPeerBandwidth(bandwidth, _type int) (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpSetPeerBandwidthPacket(bandwidth, _type), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func (conn *Conn) OnBwDone() (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpOnBWDonePacket(), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func (conn *Conn) ResponseConnectApp(objectEncoding int, serverIp string) (err error) {
	var msg *RtmpMessage
	if msg,err = conn.Protocol.EncodeMessage(NewRtmpConnectAppResPacket(objectEncoding, serverIp, conn.SrsId), 0); err != nil {
		return
	}
	return conn.EnqueueOutgoingMessage(msg)
}

func NewConn(svr *Server, conn *net.TCPConn) *Conn {
	v := &Conn{
		Server: svr,
		IoRw: conn,
		Rand: rand.New(rand.NewSource(time.Now().UnixNano())),
	}

	// the srs id
	v.SrsId = svr.Factory.SrsId()
	v.Logger = svr.Factory.CreateLogger("conn", v.SrsId)

	// TODO: FIXME: channel with buffer
	v.InChannel = make(chan *RtmpMessage, 1024)
	v.OutChannel = make(chan *RtmpMessage, 1024)
	v.SendQuitChannel = make(chan int)

	// initialize the protocol stack.
	v.Protocol = NewProtocol(conn, v.Logger)

	// nil stage for handshake.
	v.Stage = nil

	return v
}
<|endoftext|>


<commit_before>package nodesyncer

import (
	"reflect"
	"strings"

	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"

	"github.com/pkg/errors"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	nodehelper "github.com/rancher/rancher/pkg/node"
	"github.com/rancher/rancher/pkg/taints"
	"github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

func (m *nodesSyncer) syncTaints(key string, obj *v3.Node) (runtime.Object, error) {
	if obj == nil || obj.DeletionTimestamp != nil {
		return obj, nil
	}

	if !v32.NodeConditionRegistered.IsTrue(obj) {
		return obj, nil
	}

	if obj.Spec.UpdateTaintsFromAPI == nil {
		return obj, nil
	}
	node, err := nodehelper.GetNodeForMachine(obj, m.nodeLister)
	if err != nil {
		return obj, err
	}
	toAdd, toDel := taints.GetToDiffTaints(node.Spec.Taints, obj.Spec.DesiredNodeTaints)
	newObj := obj.DeepCopy()
	if len(toAdd) != 0 || len(toDel) != 0 {
		newNode := node.DeepCopy()
		var taintList []corev1.Taint
		for index, taint := range newNode.Spec.Taints {
			if _, ok := toDel[index]; !ok {
				taintList = append(taintList, taint)
			}
		}
		for _, taintStr := range toAdd {
			taintList = append(taintList, taintStr)
		}
		newNode.Spec.Taints = taintList
		if _, err := m.nodeClient.Update(newNode); err != nil && !isDuplicate(err) {
			return obj, errors.Wrapf(err, "failed to update corev1.Node %s from v3.Node %s in node taint controller", node.Name, obj.Name)
		} else if isDuplicate(err) {
			// If the node has duplicated taints, we should skip the error and set desired taints to nil and stop trying again.
			// The taints will be duplicated if they have same key and effect in k8s version >= 1.14, and same key only in version k8s <=1.13
			logrus.Errorf("failed to update corev1.Node %s from v3.Node %s in node taint controller, error: %s", node.Name, obj.Name, err.Error())
		} else if !reflect.DeepEqual(newObj.Spec.DesiredNodeTaints, newObj.Spec.InternalNodeSpec.Taints) {
			newObj.Spec.InternalNodeSpec.Taints = taintList
		}
	}
	newObj.Spec.DesiredNodeTaints = nil
	newObj.Spec.UpdateTaintsFromAPI = nil
	return m.machines.Update(newObj)
}

func isDuplicate(err error) bool {
	if err == nil {
		return false
	}
	return strings.Contains(err.Error(), "taints must be unique by key and effect pair")
}
<commit_msg>Don't crash with nil node in syncTaints https://github.com/rancher/rancher/issues/33478<commit_after>package nodesyncer

import (
	"reflect"
	"strings"

	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"

	"github.com/pkg/errors"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	nodehelper "github.com/rancher/rancher/pkg/node"
	"github.com/rancher/rancher/pkg/taints"
	"github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

func (m *nodesSyncer) syncTaints(key string, obj *v3.Node) (runtime.Object, error) {
	if obj == nil || obj.DeletionTimestamp != nil {
		return obj, nil
	}

	if !v32.NodeConditionRegistered.IsTrue(obj) {
		return obj, nil
	}

	if obj.Spec.UpdateTaintsFromAPI == nil {
		return obj, nil
	}
	node, err := nodehelper.GetNodeForMachine(obj, m.nodeLister)
	if err != nil || node == nil {
		return obj, err
	}
	toAdd, toDel := taints.GetToDiffTaints(node.Spec.Taints, obj.Spec.DesiredNodeTaints)
	newObj := obj.DeepCopy()
	if len(toAdd) != 0 || len(toDel) != 0 {
		newNode := node.DeepCopy()
		var taintList []corev1.Taint
		for index, taint := range newNode.Spec.Taints {
			if _, ok := toDel[index]; !ok {
				taintList = append(taintList, taint)
			}
		}
		for _, taintStr := range toAdd {
			taintList = append(taintList, taintStr)
		}
		newNode.Spec.Taints = taintList
		if _, err := m.nodeClient.Update(newNode); err != nil && !isDuplicate(err) {
			return obj, errors.Wrapf(err, "failed to update corev1.Node %s from v3.Node %s in node taint controller", node.Name, obj.Name)
		} else if isDuplicate(err) {
			// If the node has duplicated taints, we should skip the error and set desired taints to nil and stop trying again.
			// The taints will be duplicated if they have same key and effect in k8s version >= 1.14, and same key only in version k8s <=1.13
			logrus.Errorf("failed to update corev1.Node %s from v3.Node %s in node taint controller, error: %s", node.Name, obj.Name, err.Error())
		} else if !reflect.DeepEqual(newObj.Spec.DesiredNodeTaints, newObj.Spec.InternalNodeSpec.Taints) {
			newObj.Spec.InternalNodeSpec.Taints = taintList
		}
	}
	newObj.Spec.DesiredNodeTaints = nil
	newObj.Spec.UpdateTaintsFromAPI = nil
	return m.machines.Update(newObj)
}

func isDuplicate(err error) bool {
	if err == nil {
		return false
	}
	return strings.Contains(err.Error(), "taints must be unique by key and effect pair")
}
<|endoftext|>


<commit_before>package log

import "io"
import "sync"

type Sink interface {
	Log(*Record)
	Flush()
	IsEnabled(*Metadata) bool
}

type NopSink struct{}

func (NopSink) Log(*Record) {
}

func (NopSink) Flush() {
}
func (NopSink) IsEnabled(*Metadata) bool {
	return false
}

type LeveledSink struct {
	MaxLevel Level
	Target   Sink
}

func (l *LeveledSink) Log(r *Record) {
	l.Target.Log(r)
}

func (l *LeveledSink) Flush() {
}

func (l *LeveledSink) IsEnabled(m *Metadata) bool {
	return m.Level <= l.MaxLevel
}

type StreamSink struct {
	Formatter func(*Record) string
	Stream    io.Writer
}

func (s *StreamSink) Log(r *Record) {
	io.WriteString(s.Stream, s.Formatter(r))
}

func (s *StreamSink) Flush() {
}

func (s *StreamSink) IsEnabled(m *Metadata) bool {
	return true
}

type SyncedSink struct {
	m     sync.Mutex
	Inner Sink
}

func (s *SyncedSink) Log(r *Record) {
	s.m.Lock()
	defer s.m.Unlock()
	s.Inner.Log(r)
}

func (s *SyncedSink) Flush() {
	s.m.Lock()
	defer s.m.Unlock()
	s.Inner.Flush()
}

func (s *SyncedSink) IsEnabled(m *Metadata) bool {
	return s.Inner.IsEnabled(m)
}

type MultiSink []Sink

func (m MultiSink) Log(r *Record) {
	for _, c := range m {
		if c.IsEnabled(&r.Meta) {
			c.Log(r)
		}
	}
}

func (m MultiSink) Flush() {
	for _, c := range m {
		c.Flush()
	}
}

func (m MultiSink) IsEnabled(meta *Metadata) bool {
	for _, c := range m {
		if c.IsEnabled(meta) {
			return true
		}
	}
	return false
}

func CreateMultiSink(recs ...Sink) Sink {
	return MultiSink(recs)
}
<commit_msg>change: better consistency with inner sinks naming<commit_after>package log

import "io"
import "sync"

type Sink interface {
	Log(*Record)
	Flush()
	IsEnabled(*Metadata) bool
}

type NopSink struct{}

func (NopSink) Log(*Record) {
}

func (NopSink) Flush() {
}
func (NopSink) IsEnabled(*Metadata) bool {
	return false
}

type LeveledSink struct {
	MaxLevel Level
	Inner    Sink
}

func (l *LeveledSink) Log(r *Record) {
	l.Inner.Log(r)
}

func (l *LeveledSink) Flush() {
}

func (l *LeveledSink) IsEnabled(m *Metadata) bool {
	return m.Level <= l.MaxLevel
}

type StreamSink struct {
	Formatter func(*Record) string
	Stream    io.Writer
}

func (s *StreamSink) Log(r *Record) {
	io.WriteString(s.Stream, s.Formatter(r))
}

func (s *StreamSink) Flush() {
}

func (s *StreamSink) IsEnabled(m *Metadata) bool {
	return true
}

type SyncedSink struct {
	m     sync.Mutex
	Inner Sink
}

func (s *SyncedSink) Log(r *Record) {
	s.m.Lock()
	defer s.m.Unlock()
	s.Inner.Log(r)
}

func (s *SyncedSink) Flush() {
	s.m.Lock()
	defer s.m.Unlock()
	s.Inner.Flush()
}

func (s *SyncedSink) IsEnabled(m *Metadata) bool {
	return s.Inner.IsEnabled(m)
}

type MultiSink []Sink

func (m MultiSink) Log(r *Record) {
	for _, c := range m {
		if c.IsEnabled(&r.Meta) {
			c.Log(r)
		}
	}
}

func (m MultiSink) Flush() {
	for _, c := range m {
		c.Flush()
	}
}

func (m MultiSink) IsEnabled(meta *Metadata) bool {
	for _, c := range m {
		if c.IsEnabled(meta) {
			return true
		}
	}
	return false
}

func CreateMultiSink(recs ...Sink) Sink {
	return MultiSink(recs)
}
<|endoftext|>


<commit_before>package packet

/*
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/filter.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <poll.h>
#include <unistd.h>
*/
import "C"

import (
	"fmt"
	"github.com/Supernomad/quantum/common"
	"syscall"
	"unsafe"
)

const (
	rxRing = C.PACKET_RX_RING
	txRing = C.PACKET_TX_RING

	numBlocks      = 64
	frameSize      = 65536
	blockSize      = frameSize * numBlocks
	framesPerBlock = blockSize / frameSize
	totalSize      = framesPerBlock * numBlocks * frameSize
)

type Packet struct {
	rings map[int][]*RingBuffer
	cfg   *common.Config
	sa    *syscall.SockaddrLinklayer
}

type RingBuffer struct {
	queue  int
	buffer []byte
	poll   C.struct_pollfd
	offset int
}

var tpreq C.struct_tpacket_req
var bpfCode [5]C.struct_sock_filter
var filter C.struct_sock_fprog

func init() {
	tpreq.tp_block_size = C.uint(blockSize)
	tpreq.tp_block_nr = C.uint(numBlocks)
	tpreq.tp_frame_size = C.uint(frameSize)
	tpreq.tp_frame_nr = C.uint(framesPerBlock * numBlocks)

	bpfCode[0] = C.struct_sock_filter{
		code: 0x00,
		jt:   0,
		jf:   0,
		k:    0x00000000,
	}
	bpfCode[1] = C.struct_sock_filter{
		code: 0x30,
		jt:   0,
		jf:   0,
		k:    0x00000009,
	}
	bpfCode[2] = C.struct_sock_filter{
		code: 0x15,
		jt:   0,
		jf:   1,
		k:    0x0000008a,
	}
	bpfCode[3] = C.struct_sock_filter{
		code: 0x06,
		jt:   0,
		jf:   0,
		k:    0x00010000,
	}
	bpfCode[4] = C.struct_sock_filter{
		code: 0x06,
		jt:   0,
		jf:   0,
		k:    0x00000000,
	}
	filter.len = 5
	filter.filter = &bpfCode[0]
}

func (packet *Packet) poll(rtype int, queue int, events C.short) error {
	packet.rings[rtype][queue].poll.fd = C.int(packet.rings[rtype][queue].queue)
	packet.rings[rtype][queue].poll.events = C.short(events)
	packet.rings[rtype][queue].poll.revents = 0
	_, err := C.poll(&packet.rings[rtype][queue].poll, 1, -1)
	return err
}

func (packet *Packet) nextFrame(rtype int, queue int, status C.ulong, events C.short) (*C.struct_tpacket_hdr, []byte, error) {
	pos := packet.rings[rtype][queue].offset * frameSize
	tph := (*C.struct_tpacket_hdr)(unsafe.Pointer(&packet.rings[rtype][queue].buffer[pos]))

	for tph.tp_status&status != status {
		err := packet.poll(rtype, queue, events)
		if err != nil {
			return nil, nil, fmt.Errorf("Poll error: %s", err)
		}
	}

	packet.rings[rtype][queue].offset++
	if packet.rings[rtype][queue].offset >= framesPerBlock*numBlocks {
		packet.rings[rtype][queue].offset = 0
	}

	var start, end int
	switch rtype {
	case rxRing:
		start = pos + int(tph.tp_net)
		end = start + int(tph.tp_snaplen)
	case txRing:
		var sll C.struct_sockaddr_ll
		start = pos + C.TPACKET_HDRLEN - int(unsafe.Sizeof(sll))
		end = start + frameSize
	}
	return tph, packet.rings[rtype][queue].buffer[start:end], nil
}

func initPacket(rtype int, sa *syscall.SockaddrLinklayer) (int, []byte, error) {
	// create the socket
	queue, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, C.ETH_P_IP)
	if err != nil {
		return -1, nil, fmt.Errorf("Create socket error: %v", err)
	}

	// bind the socket to the public interface
	err = syscall.Bind(queue, sa)
	if err != nil {
		return -1, nil, fmt.Errorf("Bind socket error: %v", err)
	}

	// set the socket C.PACKET_FANOUT options
	fanoutVar := (C.PACKET_FANOUT_LB | C.PACKET_FANOUT_FLAG_ROLLOVER | C.PACKET_FANOUT_FLAG_DEFRAG) << 16
	err = syscall.SetsockoptInt(queue, syscall.SOL_PACKET, C.PACKET_FANOUT, fanoutVar)
	if err != nil {
		return -1, nil, fmt.Errorf("Fanout option error: %v", err)
	}

	// set the base bpf filter to only get quantum traffic
	_, err = C.setsockopt(C.int(queue), C.SOL_SOCKET, C.int(C.SO_ATTACH_FILTER), unsafe.Pointer(&filter), C.socklen_t(unsafe.Sizeof(filter)))
	if err != nil {
		return -1, nil, fmt.Errorf("Bpf option error: %v", err)
	}

	// setup the ring buffer
	_, err = C.setsockopt(C.int(queue), C.SOL_PACKET, C.int(rtype), unsafe.Pointer(&tpreq), C.socklen_t(unsafe.Sizeof(tpreq)))
	if err != nil {
		return -1, nil, fmt.Errorf("TxRing option error: %v", err)
	}

	// generate the actual memory buffer for the rx/tx ring buffers
	ring, err := syscall.Mmap(queue, 0, totalSize, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED)
	if err != nil {
		return -1, nil, fmt.Errorf("Mmap error: %v", err)
	}
	return queue, ring, nil
}

func (packet *Packet) GetFDs() []int {
	fds := make([]int, packet.cfg.NumWorkers*2)
	for i := 0; i < packet.cfg.NumWorkers; i++ {
		fds[i] = packet.rings[rxRing][i].queue
		fds[i+packet.cfg.NumWorkers] = packet.rings[txRing][i].queue
	}

	return fds
}

func (packet *Packet) Open() error {
	for i := 0; i < packet.cfg.NumWorkers; i++ {
		rxq, rxr, err := initPacket(rxRing, packet.sa)
		if err != nil {
			return fmt.Errorf("Init rx packet error: %s", err)
		}
		packet.rings[rxRing][i] = &RingBuffer{
			queue:  rxq,
			buffer: rxr,
			poll:   C.struct_pollfd{},
			offset: 0,
		}

		txq, txr, err := initPacket(txRing, packet.sa)
		if err != nil {
			return fmt.Errorf("Init tx packet error: %s", err)
		}
		packet.rings[txRing][i] = &RingBuffer{
			queue:  txq,
			buffer: txr,
			poll:   C.struct_pollfd{},
			offset: 0,
		}
	}
	return nil
}

func (packet *Packet) Close() error {
	for i := 0; i < packet.cfg.NumWorkers; i++ {
		if err := syscall.Munmap(packet.rings[rxRing][i].buffer); err != nil {
			return fmt.Errorf("Munmap error: %s", err)
		}
		if err := syscall.Close(packet.rings[rxRing][i].queue); err != nil {
			return fmt.Errorf("Close error: %s", err)
		}
		if err := syscall.Munmap(packet.rings[txRing][i].buffer); err != nil {
			return fmt.Errorf("Munmap error: %s", err)
		}
		if err := syscall.Close(packet.rings[txRing][i].queue); err != nil {
			return fmt.Errorf("Close error: %s", err)
		}
	}
	return nil
}

func (packet *Packet) Recv(buf []byte, queue int) error {
	tph, frame, err := packet.nextFrame(rxRing, queue, C.TP_STATUS_USER, C.POLLIN)
	if err != nil {
		return fmt.Errorf("Get next rx frame error: %s", err)
	}
	copy(buf[:], frame[:])
	tph.tp_status = C.TP_STATUS_KERNEL
	return nil
}

func (packet *Packet) Send(buf []byte, queue int) error {
	tph, frame, err := packet.nextFrame(txRing, queue, C.TP_STATUS_AVAILABLE, C.POLLOUT)
	if err != nil {
		return fmt.Errorf("Get next tx frame error: %s", err)
	}
	copy(frame[:], buf[:])
	tph.tp_len = C.uint(len(buf))
	tph.tp_status = C.TP_STATUS_SEND_REQUEST
	return nil
}

func (packet *Packet) Flush(queue int) error {
	return syscall.Sendto(packet.rings[txRing][queue].queue, nil, 0, packet.sa)
}

func New(cfg *common.Config) *Packet {
	rings := make(map[int][]*RingBuffer)
	rings[rxRing] = make([]*RingBuffer, cfg.NumWorkers)
	rings[txRing] = make([]*RingBuffer, cfg.NumWorkers)
	return &Packet{
		rings: rings,
		cfg:   cfg,
		sa: &syscall.SockaddrLinklayer{
			Protocol: uint16(C.htons(C.ETH_P_IP)),
			Ifindex:  cfg.PublicInterface,
			Pkttype:  C.PACKET_OTHERHOST,
		},
	}
}
<commit_msg>Fixed queuing issue<commit_after>package packet

/*
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/filter.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <poll.h>
#include <unistd.h>
*/
import "C"

import (
	"fmt"
	"github.com/Supernomad/quantum/common"
	"syscall"
	"unsafe"
)

const (
	rxRing = C.PACKET_RX_RING
	txRing = C.PACKET_TX_RING

	numBlocks      = 64
	frameSize      = 65536
	blockSize      = frameSize * numBlocks
	framesPerBlock = blockSize / frameSize
	totalSize      = framesPerBlock * numBlocks * frameSize
)

type Packet struct {
	rings map[int][]*RingBuffer
	cfg   *common.Config
	sa    *syscall.SockaddrLinklayer
}

type RingBuffer struct {
	queue  int
	buffer []byte
	poll   C.struct_pollfd
	offset int
}

var tpreq C.struct_tpacket_req
var bpfCode [5]C.struct_sock_filter
var filter C.struct_sock_fprog

func init() {
	tpreq.tp_block_size = C.uint(blockSize)
	tpreq.tp_block_nr = C.uint(numBlocks)
	tpreq.tp_frame_size = C.uint(frameSize)
	tpreq.tp_frame_nr = C.uint(framesPerBlock * numBlocks)

	bpfCode[0] = C.struct_sock_filter{
		code: 0x00,
		jt:   0,
		jf:   0,
		k:    0x00000000,
	}
	bpfCode[1] = C.struct_sock_filter{
		code: 0x30,
		jt:   0,
		jf:   0,
		k:    0x00000009,
	}
	bpfCode[2] = C.struct_sock_filter{
		code: 0x15,
		jt:   0,
		jf:   1,
		k:    0x0000008a,
	}
	bpfCode[3] = C.struct_sock_filter{
		code: 0x06,
		jt:   0,
		jf:   0,
		k:    0x00010000,
	}
	bpfCode[4] = C.struct_sock_filter{
		code: 0x06,
		jt:   0,
		jf:   0,
		k:    0x00000000,
	}
	filter.len = 5
	filter.filter = &bpfCode[0]
}

func (packet *Packet) poll(rtype int, queue int, events C.short) error {
	packet.rings[rtype][queue].poll.fd = C.int(packet.rings[rtype][queue].queue)
	packet.rings[rtype][queue].poll.events = C.short(events)
	packet.rings[rtype][queue].poll.revents = 0
	_, err := C.poll(&packet.rings[rtype][queue].poll, 1, -1)
	return err
}

func (packet *Packet) nextFrame(rtype int, queue int, status C.ulong, events C.short) (*C.struct_tpacket_hdr, []byte, error) {
	pos := packet.rings[rtype][queue].offset * frameSize
	tph := (*C.struct_tpacket_hdr)(unsafe.Pointer(&packet.rings[rtype][queue].buffer[pos]))

	for tph.tp_status&status != status {
		err := packet.poll(rtype, queue, events)
		if err != nil {
			return nil, nil, fmt.Errorf("Poll error: %s", err)
		}
	}

	packet.rings[rtype][queue].offset++
	if packet.rings[rtype][queue].offset >= framesPerBlock*numBlocks {
		packet.rings[rtype][queue].offset = 0
	}

	var start, end int
	switch rtype {
	case rxRing:
		start = pos + int(tph.tp_net)
		end = start + int(tph.tp_snaplen)
	case txRing:
		var sll C.struct_sockaddr_ll
		start = pos + C.TPACKET_HDRLEN - int(unsafe.Sizeof(sll))
		end = start + frameSize
	}
	return tph, packet.rings[rtype][queue].buffer[start:end], nil
}

func initPacket(rtype int, sa *syscall.SockaddrLinklayer) (int, []byte, error) {
	// create the socket
	queue, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, C.ETH_P_IP)
	if err != nil {
		return -1, nil, fmt.Errorf("Create socket error: %v", err)
	}

	if rtype == rxRing {
		// bind the socket to the public interface
		err = syscall.Bind(queue, sa)
		if err != nil {
			return -1, nil, fmt.Errorf("Bind socket error: %v", err)
		}

		// set the socket C.PACKET_FANOUT options
		fanoutVar := (C.PACKET_FANOUT_LB | C.PACKET_FANOUT_FLAG_ROLLOVER | C.PACKET_FANOUT_FLAG_DEFRAG) << 16
		err = syscall.SetsockoptInt(queue, syscall.SOL_PACKET, C.PACKET_FANOUT, fanoutVar)
		if err != nil {
			return -1, nil, fmt.Errorf("Fanout option error: %v", err)
		}

		// set the base bpf filter to only get quantum traffic
		_, err = C.setsockopt(C.int(queue), C.SOL_SOCKET, C.int(C.SO_ATTACH_FILTER), unsafe.Pointer(&filter), C.socklen_t(unsafe.Sizeof(filter)))
		if err != nil {
			return -1, nil, fmt.Errorf("Bpf option error: %v", err)
		}
	}

	// setup the ring buffer
	_, err = C.setsockopt(C.int(queue), C.SOL_PACKET, C.int(rtype), unsafe.Pointer(&tpreq), C.socklen_t(unsafe.Sizeof(tpreq)))
	if err != nil {
		return -1, nil, fmt.Errorf("Ring option error: %v", err)
	}

	// generate the actual memory buffer for the rx/tx ring buffers
	ring, err := syscall.Mmap(queue, 0, totalSize, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED)
	if err != nil {
		return -1, nil, fmt.Errorf("Mmap error: %v", err)
	}

	return queue, ring, nil
}

func (packet *Packet) GetFDs() []int {
	fds := make([]int, packet.cfg.NumWorkers*2)
	for i := 0; i < packet.cfg.NumWorkers; i++ {
		fds[i] = packet.rings[rxRing][i].queue
		fds[i+packet.cfg.NumWorkers] = packet.rings[txRing][i].queue
	}

	return fds
}

func (packet *Packet) Open() error {
	for i := 0; i < packet.cfg.NumWorkers; i++ {
		rxq, rxr, err := initPacket(rxRing, packet.sa)
		if err != nil {
			return fmt.Errorf("Init rx packet error: %s", err)
		}
		packet.rings[rxRing][i] = &RingBuffer{
			queue:  rxq,
			buffer: rxr,
			poll:   C.struct_pollfd{},
			offset: 0,
		}

		txq, txr, err := initPacket(txRing, packet.sa)
		if err != nil {
			return fmt.Errorf("Init tx packet error: %s", err)
		}
		packet.rings[txRing][i] = &RingBuffer{
			queue:  txq,
			buffer: txr,
			poll:   C.struct_pollfd{},
			offset: 0,
		}
	}
	return nil
}

func (packet *Packet) Close() error {
	for i := 0; i < packet.cfg.NumWorkers; i++ {
		if err := syscall.Munmap(packet.rings[rxRing][i].buffer); err != nil {
			return fmt.Errorf("Munmap error: %s", err)
		}
		if err := syscall.Close(packet.rings[rxRing][i].queue); err != nil {
			return fmt.Errorf("Close error: %s", err)
		}
		if err := syscall.Munmap(packet.rings[txRing][i].buffer); err != nil {
			return fmt.Errorf("Munmap error: %s", err)
		}
		if err := syscall.Close(packet.rings[txRing][i].queue); err != nil {
			return fmt.Errorf("Close error: %s", err)
		}
	}
	return nil
}

func (packet *Packet) Recv(buf []byte, queue int) error {
	tph, frame, err := packet.nextFrame(rxRing, queue, C.TP_STATUS_USER, C.POLLIN)
	if err != nil {
		return fmt.Errorf("Get next rx frame error: %s", err)
	}
	copy(buf[:], frame[:])
	tph.tp_status = C.TP_STATUS_KERNEL
	return nil
}

func (packet *Packet) Send(buf []byte, queue int) error {
	tph, frame, err := packet.nextFrame(txRing, queue, C.TP_STATUS_AVAILABLE, C.POLLOUT)
	if err != nil {
		return fmt.Errorf("Get next tx frame error: %s", err)
	}
	copy(frame[:], buf[:])
	tph.tp_len = C.uint(len(buf))
	tph.tp_status = C.TP_STATUS_SEND_REQUEST
	return nil
}

func (packet *Packet) Flush(queue int) error {
	return syscall.Sendto(packet.rings[txRing][queue].queue, nil, 0, packet.sa)
}

func New(cfg *common.Config) *Packet {
	rings := make(map[int][]*RingBuffer)
	rings[rxRing] = make([]*RingBuffer, cfg.NumWorkers)
	rings[txRing] = make([]*RingBuffer, cfg.NumWorkers)
	return &Packet{
		rings: rings,
		cfg:   cfg,
		sa: &syscall.SockaddrLinklayer{
			Protocol: uint16(C.htons(C.ETH_P_IP)),
			Ifindex:  cfg.PublicInterface,
			Pkttype:  C.PACKET_OTHERHOST,
		},
	}
}
<|endoftext|>


<commit_before>// Package plate provides a Recorder for testing Go's HTML templates.
package plate

import (
	"bytes"
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func New(tmpl Executor) *Recorder {
	return &Recorder{Template: tmpl}
}

func (r *Recorder) save(exec Execution) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = append(r.execs, exec)
}

// Execute executes the wrapped template,
// saving information into the Recorder.
func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.Execute(writer, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// ExecuteTemplate is like Execute, but for named teplates.
func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.ExecuteTemplate(writer, name, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// Executions returns all executions that have occured
// since the construction of a Recorder (or since Reset()).
func (r *Recorder) Executions() []Execution {
	tmpExecs := make([]Execution, len(r.execs))
	// We do a copy, because callee may mess around with internal []Execution
	// and we do not want this.
	r.mu.RLock()
	defer r.mu.RUnlock()
	copy(tmpExecs, r.execs)
	return tmpExecs
}

// LastExecution returns the information of the latest execution.
// It panics if no executions have occured yet.
func (r *Recorder) LastExecution() Execution {
	if len(r.execs) < 1 {
		panic("No executions are available yet.")
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.execs[len(r.execs)-1]
}

// TimesExecuted returns the count of times
// template has been executed
// since construction or calling Reset().
func (r *Recorder) TimesExecuted() int {
	return len(r.execs)
}

// FailedExecutions returns all executions that have Error != nil
func (r *Recorder) FailedExecutions() []Execution {
	failedExecs := make([]Execution, 0)
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, exec := range r.execs {
		if exec.Error != nil {
			failedExecs = append(failedExecs, exec)
		}
	}

	return failedExecs
}

// Reset clears all executions. Recorder is thus restored to its initial state.
func (r *Recorder) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = make([]Execution, 0)
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<commit_msg>Documentation for New()<commit_after>// Package plate provides a Recorder for testing Go's HTML templates.
package plate

import (
	"bytes"
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

// New() returns a new Recorder wrapping the given template.
// It is equivalent to:
//    &Recorder{Template: tmpl}
func New(tmpl Executor) *Recorder {
	return &Recorder{Template: tmpl}
}

func (r *Recorder) save(exec Execution) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = append(r.execs, exec)
}

// Execute executes the wrapped template,
// saving information into the Recorder.
func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.Execute(writer, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// ExecuteTemplate is like Execute, but for named teplates.
func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	exec := Execution{Context: data}

	// Substitute the reader
	buf := &bytes.Buffer{}
	writer := io.MultiWriter(buf, wr)

	// Execute and fill out the results
	err := r.Template.ExecuteTemplate(writer, name, data)
	exec.Output = buf.Bytes()
	exec.Error = err

	r.save(exec)
	return err
}

// Executions returns all executions that have occured
// since the construction of a Recorder (or since Reset()).
func (r *Recorder) Executions() []Execution {
	tmpExecs := make([]Execution, len(r.execs))
	// We do a copy, because callee may mess around with internal []Execution
	// and we do not want this.
	r.mu.RLock()
	defer r.mu.RUnlock()
	copy(tmpExecs, r.execs)
	return tmpExecs
}

// LastExecution returns the information of the latest execution.
// It panics if no executions have occured yet.
func (r *Recorder) LastExecution() Execution {
	if len(r.execs) < 1 {
		panic("No executions are available yet.")
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.execs[len(r.execs)-1]
}

// TimesExecuted returns the count of times
// template has been executed
// since construction or calling Reset().
func (r *Recorder) TimesExecuted() int {
	return len(r.execs)
}

// FailedExecutions returns all executions that have Error != nil
func (r *Recorder) FailedExecutions() []Execution {
	failedExecs := make([]Execution, 0)
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, exec := range r.execs {
		if exec.Error != nil {
			failedExecs = append(failedExecs, exec)
		}
	}

	return failedExecs
}

// Reset clears all executions. Recorder is thus restored to its initial state.
func (r *Recorder) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.execs = make([]Execution, 0)
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<|endoftext|>