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

package runtime

import (
	"unsafe"
)

type sliceStruct struct {
	array unsafe.Pointer
	len   int
	cap   int
}

// TODO: take uintptrs instead of int64s?
func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
	// but it produces a 'len out of range' error instead of a 'cap out of range' error
	// when someone does make([]T, bignumber). 'cap out of range' is true too,
	// but since the cap is only being supplied implicitly, saying len is clearer.
	// See issue 4085.
	len := int(len64)
	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && len > int(maxMem/uintptr(t.elem.size)) {
		panic(errorString("makeslice: len out of range"))
	}
	cap := int(cap64)
	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && cap > int(maxMem/uintptr(t.elem.size)) {
		panic(errorString("makeslice: cap out of range"))
	}
	p := newarray(t.elem, uintptr(cap))
	return sliceStruct{p, len, cap}
}

// TODO: take uintptr instead of int64?
func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
	if n < 1 {
		panic(errorString("growslice: invalid n"))
	}

	cap64 := int64(old.cap) + n
	cap := int(cap64)

	if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && cap > int(maxMem/uintptr(t.elem.size)) {
		panic(errorString("growslice: cap out of range"))
	}

	if raceenabled {
		callerpc := gogetcallerpc(unsafe.Pointer(&t))
		fn := growslice
		pc := **(**uintptr)(unsafe.Pointer(&fn))
		racereadrangepc(old.array, old.len*int(t.elem.size), callerpc, pc)
	}

	et := t.elem
	if et.size == 0 {
		return sliceStruct{old.array, old.len, cap}
	}

	newcap := old.cap
	if newcap+newcap < cap {
		newcap = cap
	} else {
		for {
			if old.len < 1024 {
				newcap += newcap
			} else {
				newcap += newcap / 4
			}
			if newcap >= cap {
				break
			}
		}
	}

	if newcap >= int(maxMem/uintptr(et.size)) {
		panic(errorString("growslice: cap out of range"))
	}
	lenmem := uintptr(old.len) * uintptr(et.size)
	capmem := goroundupsize(uintptr(newcap) * uintptr(et.size))
	newcap = int(capmem / uintptr(et.size))
	var p unsafe.Pointer
	if et.kind&kindNoPointers != 0 {
		p = rawmem(capmem)
		memclr(add(p, lenmem), capmem-lenmem)
	} else {
		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory
		p = newarray(et, uintptr(newcap))
	}
	memmove(p, old.array, lenmem)

	return sliceStruct{p, old.len, newcap}
}

func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int {
	if fm.len == 0 || to.len == 0 || width == 0 {
		return 0
	}

	n := fm.len
	if to.len < n {
		n = to.len
	}

	if raceenabled {
		callerpc := gogetcallerpc(unsafe.Pointer(&to))
		fn := slicecopy
		pc := **(**uintptr)(unsafe.Pointer(&fn))
		racewriterangepc(to.array, n*int(width), callerpc, pc)
		racereadrangepc(fm.array, n*int(width), callerpc, pc)
	}

	size := uintptr(n) * width
	if size == 1 { // common case worth about 2x to do here
		// TODO: is this still worth it with new memmove impl?
		*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
	} else {
		memmove(to.array, fm.array, size)
	}
	return int(n)
}

func slicestringcopy(to []byte, fm string) int {
	if len(fm) == 0 || len(to) == 0 {
		return 0
	}

	n := len(fm)
	if len(to) < n {
		n = len(to)
	}

	if raceenabled {
		callerpc := gogetcallerpc(unsafe.Pointer(&to))
		fn := slicestringcopy
		pc := **(**uintptr)(unsafe.Pointer(&fn))
		racewriterangepc(unsafe.Pointer(&to[0]), n, callerpc, pc)
	}

	memmove(unsafe.Pointer(&to[0]), unsafe.Pointer((*stringStruct)(unsafe.Pointer(&fm)).str), uintptr(n))
	return n
}

var printslice_m byte

func printslice(a sliceStruct) {
	mp := acquirem()
	mp.ptrarg[0] = a.array
	mp.scalararg[0] = uint(a.len)
	mp.scalararg[1] = uint(a.cap)
	mcall(&printslice_m)
	releasem(mp)
}
<commit_msg>runtime: fix 32 bit build.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import (
	"unsafe"
)

type sliceStruct struct {
	array unsafe.Pointer
	len   int
	cap   int
}

// TODO: take uintptrs instead of int64s?
func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
	// but it produces a 'len out of range' error instead of a 'cap out of range' error
	// when someone does make([]T, bignumber). 'cap out of range' is true too,
	// but since the cap is only being supplied implicitly, saying len is clearer.
	// See issue 4085.
	len := int(len64)
	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxMem/uintptr(t.elem.size) {
		panic(errorString("makeslice: len out of range"))
	}
	cap := int(cap64)
	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxMem/uintptr(t.elem.size) {
		panic(errorString("makeslice: cap out of range"))
	}
	p := newarray(t.elem, uintptr(cap))
	return sliceStruct{p, len, cap}
}

// TODO: take uintptr instead of int64?
func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
	if n < 1 {
		panic(errorString("growslice: invalid n"))
	}

	cap64 := int64(old.cap) + n
	cap := int(cap64)

	if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > maxMem/uintptr(t.elem.size) {
		panic(errorString("growslice: cap out of range"))
	}

	if raceenabled {
		callerpc := gogetcallerpc(unsafe.Pointer(&t))
		fn := growslice
		pc := **(**uintptr)(unsafe.Pointer(&fn))
		racereadrangepc(old.array, old.len*int(t.elem.size), callerpc, pc)
	}

	et := t.elem
	if et.size == 0 {
		return sliceStruct{old.array, old.len, cap}
	}

	newcap := old.cap
	if newcap+newcap < cap {
		newcap = cap
	} else {
		for {
			if old.len < 1024 {
				newcap += newcap
			} else {
				newcap += newcap / 4
			}
			if newcap >= cap {
				break
			}
		}
	}

	if uintptr(newcap) >= maxMem/uintptr(et.size) {
		panic(errorString("growslice: cap out of range"))
	}
	lenmem := uintptr(old.len) * uintptr(et.size)
	capmem := goroundupsize(uintptr(newcap) * uintptr(et.size))
	newcap = int(capmem / uintptr(et.size))
	var p unsafe.Pointer
	if et.kind&kindNoPointers != 0 {
		p = rawmem(capmem)
		memclr(add(p, lenmem), capmem-lenmem)
	} else {
		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory
		p = newarray(et, uintptr(newcap))
	}
	memmove(p, old.array, lenmem)

	return sliceStruct{p, old.len, newcap}
}

func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int {
	if fm.len == 0 || to.len == 0 || width == 0 {
		return 0
	}

	n := fm.len
	if to.len < n {
		n = to.len
	}

	if raceenabled {
		callerpc := gogetcallerpc(unsafe.Pointer(&to))
		fn := slicecopy
		pc := **(**uintptr)(unsafe.Pointer(&fn))
		racewriterangepc(to.array, n*int(width), callerpc, pc)
		racereadrangepc(fm.array, n*int(width), callerpc, pc)
	}

	size := uintptr(n) * width
	if size == 1 { // common case worth about 2x to do here
		// TODO: is this still worth it with new memmove impl?
		*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
	} else {
		memmove(to.array, fm.array, size)
	}
	return int(n)
}

func slicestringcopy(to []byte, fm string) int {
	if len(fm) == 0 || len(to) == 0 {
		return 0
	}

	n := len(fm)
	if len(to) < n {
		n = len(to)
	}

	if raceenabled {
		callerpc := gogetcallerpc(unsafe.Pointer(&to))
		fn := slicestringcopy
		pc := **(**uintptr)(unsafe.Pointer(&fn))
		racewriterangepc(unsafe.Pointer(&to[0]), n, callerpc, pc)
	}

	memmove(unsafe.Pointer(&to[0]), unsafe.Pointer((*stringStruct)(unsafe.Pointer(&fm)).str), uintptr(n))
	return n
}

var printslice_m byte

func printslice(a sliceStruct) {
	mp := acquirem()
	mp.ptrarg[0] = a.array
	mp.scalararg[0] = uint(a.len)
	mp.scalararg[1] = uint(a.cap)
	mcall(&printslice_m)
	releasem(mp)
}
<|endoftext|>


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

package runtime

import "unsafe"

// Declarations for runtime services implemented in C or assembly.
// C implementations of these functions are in stubs.goc.
// Assembly implementations are in various files, see comments with
// each function.

const (
	ptrSize = unsafe.Sizeof((*byte)(nil))
)

//go:noescape
func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)

//go:noescape
func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)

//go:noescape
func racereadrangepc(addr unsafe.Pointer, len int, callpc, pc uintptr)

//go:noescape
func racewriterangepc(addr unsafe.Pointer, len int, callpc, pc uintptr)

//go:noescape
func raceacquire(addr unsafe.Pointer)

//go:noescape
func racerelease(addr unsafe.Pointer)

//go:noescape
func raceacquireg(gp *g, addr unsafe.Pointer)

//go:noescape
func racereleaseg(gp *g, addr unsafe.Pointer)

// Should be a built-in for unsafe.Pointer?
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
	return unsafe.Pointer(uintptr(p) + x)
}

// n must be a power of 2
func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer {
	delta := -uintptr(p) & (n - 1)
	return unsafe.Pointer(uintptr(p) + delta)
}

// in stubs.goc
func getg() *g
func acquirem() *m
func releasem(mp *m)
func gomcache() *mcache

// An mFunction represents a C function that runs on the M stack.  It
// can be called from Go using mcall or onM.  Through the magic of
// linking, an mFunction variable and the corresponding C code entry
// point live at the same address.
type mFunction byte

// in asm_*.s
func mcall(fn *mFunction)
func onM(fn *mFunction)

// C functions that run on the M stack.  Call these like
//   mcall(&mcacheRefill_m)
// Arguments should be passed in m->scalararg[x] and
// m->ptrarg[x].  Return values can be passed in those
// same slots.
var (
	mcacheRefill_m,
	largeAlloc_m,
	mprofMalloc_m,
	gc_m,
	setFinalizer_m,
	markallocated_m,
	unrollgcprog_m,
	unrollgcproginplace_m,
	gosched_m,
	setgcpercent_m,
	setmaxthreads_m,
	ready_m,
	park_m,
	notewakeup_m,
	notetsleepg_m mFunction
)

func blockevent(int64, int32)

// memclr clears n bytes starting at ptr.
// in memclr_*.s
//go:noescape
func memclr(ptr unsafe.Pointer, n uintptr)

func racemalloc(p unsafe.Pointer, size uintptr)
func tracealloc(p unsafe.Pointer, size uintptr, typ *_type)

// memmove copies n bytes from "from" to "to".
// in memmove_*.s
//go:noescape
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)

// in asm_*.s
func fastrand2() uint32

const (
	gcpercentUnknown = -2
	concurrentSweep  = true
)

func gosched()
func starttheworld()
func stoptheworld()
func clearpools()

// exported value for testing
var hashLoad = loadFactor

// in asm_*.s
//go:noescape
func memeq(a, b unsafe.Pointer, size uintptr) bool

// Code pointers for the nohash/noequal algorithms. Used for producing better error messages.
var nohashcode uintptr
var noequalcode uintptr

// Go version of runtime.throw.
// in panic.c
func gothrow(s string)

// Return the Go equivalent of the C Alg structure.
// TODO: at some point Go will hold the truth for the layout
// of runtime structures and C will be derived from it (if
// needed at all).  At that point this function can go away.
type goalgtype struct {
	// function for hashing objects of this type
	// (ptr to object, size, seed) -> hash
	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B, size) -> ==?
	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
}

func goalg(a *alg) *goalgtype {
	return (*goalgtype)(unsafe.Pointer(a))
}

// noescape hides a pointer from escape analysis.  noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input.  noescape is inlined and currently
// compiles down to a single xor instruction.
// USE CAREFULLY!
func noescape(p unsafe.Pointer) unsafe.Pointer {
	x := uintptr(p)
	return unsafe.Pointer(x ^ 0)
}

func exitsyscall()

func goroutineheader(gp *g)
func traceback(pc, sp, lr uintptr, gp *g)
func tracebackothers(gp *g)

func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
func gogo(buf *gobuf)
func gosave(buf *gobuf)
func open(name *byte, mode, perm int32) int32
func read(fd int32, p unsafe.Pointer, n int32) int32
func write(fd uintptr, p unsafe.Pointer, n int32) int32
func close(fd int32) int32
func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
func jmpdefer(fv *funcval, argp unsafe.Pointer)
func exit1(code int32)
func asminit()
func setg(gg *g)
func exit(code int32)
func breakpoint()
func asmcgocall(fn, arg unsafe.Pointer)
func nanotime() int64
func usleep(usec uint32)
func cputicks() int64
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
func munmap(addr unsafe.Pointer, n uintptr)
func madvise(addr unsafe.Pointer, n uintptr, flags int32)
func newstackcall(fv *funcval, addr unsafe.Pointer, size uint32)
func procyield(cycles uint32)
func osyield()
func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr)
func cmpstring(s1, s2 string) int
func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer
func readgogc() int32
func notetsleepg(n *note, ns int64)
func notetsleep(n *note, ns int64)
func notewakeup(n *note)
func notesleep(n *note)
func noteclear(n *note)
func lock(lk *mutex)
func unlock(lk *mutex)

//go:noescape
func cas(ptr *uint32, old, new uint32) bool

//go:noescape
func cas64(ptr *uint64, old, new uint64) bool

//go:noescape
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool

//go:noescape
func casuintptr(ptr *uintptr, old, new uintptr) bool

//go:noescape
func xadd(ptr *uint32, delta int32) uint32

//go:noescape
func xadd64(ptr *uint64, delta int64) uint64

//go:noescape
func xchg(ptr *uint32, new uint32) uint32

//go:noescape
func xchg64(ptr *uint64, new uint64) uint64

//go:noescape
func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer

//go:noescape
func atomicstore(ptr *uint32, val uint32)

//go:noescape
func atomicstore64(ptr *uint64, val uint64)

//go:noescape
func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer)

//go:noescape
func atomicload(ptr *uint32) uint32

//go:noescape
func atomicload64(ptr *uint64) uint64

//go:noescape
func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer

//go:noescape
func atomicor8(ptr *uint8, val uint8)

//go:noescape
func setcallerpc(argp unsafe.Pointer, pc uintptr)

//go:noescape
func getcallerpc(argp unsafe.Pointer) uintptr

//go:noescape
func getcallersp(argp unsafe.Pointer) uintptr
<commit_msg>runtime: fix arm build<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// Declarations for runtime services implemented in C or assembly.
// C implementations of these functions are in stubs.goc.
// Assembly implementations are in various files, see comments with
// each function.

const (
	ptrSize = unsafe.Sizeof((*byte)(nil))
)

//go:noescape
func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)

//go:noescape
func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)

//go:noescape
func racereadrangepc(addr unsafe.Pointer, len int, callpc, pc uintptr)

//go:noescape
func racewriterangepc(addr unsafe.Pointer, len int, callpc, pc uintptr)

//go:noescape
func raceacquire(addr unsafe.Pointer)

//go:noescape
func racerelease(addr unsafe.Pointer)

//go:noescape
func raceacquireg(gp *g, addr unsafe.Pointer)

//go:noescape
func racereleaseg(gp *g, addr unsafe.Pointer)

// Should be a built-in for unsafe.Pointer?
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
	return unsafe.Pointer(uintptr(p) + x)
}

// n must be a power of 2
func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer {
	delta := -uintptr(p) & (n - 1)
	return unsafe.Pointer(uintptr(p) + delta)
}

// in stubs.goc
func getg() *g
func acquirem() *m
func releasem(mp *m)
func gomcache() *mcache

// An mFunction represents a C function that runs on the M stack.  It
// can be called from Go using mcall or onM.  Through the magic of
// linking, an mFunction variable and the corresponding C code entry
// point live at the same address.
type mFunction byte

// in asm_*.s
func mcall(fn *mFunction)
func onM(fn *mFunction)

// C functions that run on the M stack.  Call these like
//   mcall(&mcacheRefill_m)
// Arguments should be passed in m->scalararg[x] and
// m->ptrarg[x].  Return values can be passed in those
// same slots.
var (
	mcacheRefill_m,
	largeAlloc_m,
	mprofMalloc_m,
	gc_m,
	setFinalizer_m,
	markallocated_m,
	unrollgcprog_m,
	unrollgcproginplace_m,
	gosched_m,
	setgcpercent_m,
	setmaxthreads_m,
	ready_m,
	park_m,
	notewakeup_m,
	notetsleepg_m mFunction
)

func blockevent(int64, int32)

// memclr clears n bytes starting at ptr.
// in memclr_*.s
//go:noescape
func memclr(ptr unsafe.Pointer, n uintptr)

func racemalloc(p unsafe.Pointer, size uintptr)
func tracealloc(p unsafe.Pointer, size uintptr, typ *_type)

// memmove copies n bytes from "from" to "to".
// in memmove_*.s
//go:noescape
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)

// in asm_*.s
func fastrand2() uint32

const (
	gcpercentUnknown = -2
	concurrentSweep  = true
)

func gosched()
func starttheworld()
func stoptheworld()
func clearpools()

// exported value for testing
var hashLoad = loadFactor

// in asm_*.s
//go:noescape
func memeq(a, b unsafe.Pointer, size uintptr) bool

// Code pointers for the nohash/noequal algorithms. Used for producing better error messages.
var nohashcode uintptr
var noequalcode uintptr

// Go version of runtime.throw.
// in panic.c
func gothrow(s string)

// Return the Go equivalent of the C Alg structure.
// TODO: at some point Go will hold the truth for the layout
// of runtime structures and C will be derived from it (if
// needed at all).  At that point this function can go away.
type goalgtype struct {
	// function for hashing objects of this type
	// (ptr to object, size, seed) -> hash
	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B, size) -> ==?
	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
}

func goalg(a *alg) *goalgtype {
	return (*goalgtype)(unsafe.Pointer(a))
}

// noescape hides a pointer from escape analysis.  noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input.  noescape is inlined and currently
// compiles down to a single xor instruction.
// USE CAREFULLY!
func noescape(p unsafe.Pointer) unsafe.Pointer {
	x := uintptr(p)
	return unsafe.Pointer(x ^ 0)
}

func exitsyscall()

func goroutineheader(gp *g)
func traceback(pc, sp, lr uintptr, gp *g)
func tracebackothers(gp *g)

func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
func gogo(buf *gobuf)
func gosave(buf *gobuf)
func open(name *byte, mode, perm int32) int32
func read(fd int32, p unsafe.Pointer, n int32) int32
func write(fd uintptr, p unsafe.Pointer, n int32) int32
func close(fd int32) int32
func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
func jmpdefer(fv *funcval, argp unsafe.Pointer)
func exit1(code int32)
func asminit()
func setg(gg *g)
func exit(code int32)
func breakpoint()
func asmcgocall(fn, arg unsafe.Pointer)
func nanotime() int64
func usleep(usec uint32)
func cputicks() int64
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
func munmap(addr unsafe.Pointer, n uintptr)
func madvise(addr unsafe.Pointer, n uintptr, flags int32)
func newstackcall(fv *funcval, addr unsafe.Pointer, size uint32)
func procyield(cycles uint32)
func osyield()
func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr)
func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer
func readgogc() int32
func notetsleepg(n *note, ns int64)
func notetsleep(n *note, ns int64)
func notewakeup(n *note)
func notesleep(n *note)
func noteclear(n *note)
func lock(lk *mutex)
func unlock(lk *mutex)

//go:noescape
func cas(ptr *uint32, old, new uint32) bool

//go:noescape
func cas64(ptr *uint64, old, new uint64) bool

//go:noescape
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool

//go:noescape
func casuintptr(ptr *uintptr, old, new uintptr) bool

//go:noescape
func xadd(ptr *uint32, delta int32) uint32

//go:noescape
func xadd64(ptr *uint64, delta int64) uint64

//go:noescape
func xchg(ptr *uint32, new uint32) uint32

//go:noescape
func xchg64(ptr *uint64, new uint64) uint64

//go:noescape
func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer

//go:noescape
func atomicstore(ptr *uint32, val uint32)

//go:noescape
func atomicstore64(ptr *uint64, val uint64)

//go:noescape
func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer)

//go:noescape
func atomicload(ptr *uint32) uint32

//go:noescape
func atomicload64(ptr *uint64) uint64

//go:noescape
func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer

//go:noescape
func atomicor8(ptr *uint8, val uint8)

//go:noescape
func setcallerpc(argp unsafe.Pointer, pc uintptr)

//go:noescape
func getcallerpc(argp unsafe.Pointer) uintptr

//go:noescape
func getcallersp(argp unsafe.Pointer) uintptr
<|endoftext|>


<commit_before>package sider

import (
	"database/sql"
	"fmt"
	"log"

	"github.com/artonge/Tamalou/Queries"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

// Init DB Connection
func init() {
	var err error
	db, err = sql.Open("mysql", "gmd-read:esial@tcp(neptune.telecomnancy.univ-lorraine.fr:3306)/gmd")
	if err != nil {
		log.Fatal("Error init Sider MySQL connector init: ", err)
	}
}

func QueryMeddra(query Queries.DBQuery) ([]*Meddra, error) {
	fullQuery := "SELECT * FROM meddra WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider (meddra): %v", err)
	}
	defer rows.Close()

	var results = make([]*Meddra, 0, 100)

	for rows.Next() {
		tmpMeddra := new(Meddra)
		err := rows.Scan(&tmpMeddra.CUI, &tmpMeddra.ConceptType, &tmpMeddra.MeddraID, &tmpMeddra.Label)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddra)
	}
	return results, nil
}

func QueryMeddraAllIndications(query Queries.DBQuery) ([]*MeddraAllIndications, error) {
	fullQuery := "SELECT * FROM meddra_all_indications WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider: ", err)
	}
	defer rows.Close()

	var results = make([]*MeddraAllIndications, 0, 100)

	for rows.Next() {
		tmpMeddraAllIndications := new(MeddraAllIndications)
		err := rows.Scan(&tmpMeddraAllIndications.StitchCompoundID, &tmpMeddraAllIndications.CUI, &tmpMeddraAllIndications.MethodOfDetection, &tmpMeddraAllIndications.ConceptName, &tmpMeddraAllIndications.MeddraConceptType, &tmpMeddraAllIndications.CUIOfMeddraTerm, &tmpMeddraAllIndications.MeddraConceptName)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddraAllIndications)
	}
	return results, nil
}

func QueryMeddraAllSe(query Queries.DBQuery) ([]*MeddraAllSe, error) {
	fullQuery := "SELECT * FROM meddra_all_se WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider (meddra_all_se): ", err)
	}
	defer rows.Close()

	var results = make([]*MeddraAllSe, 0, 100)

	for rows.Next() {
		tmpMeddraAllSe := new(MeddraAllSe)
		err := rows.Scan(&tmpMeddraAllSe.StitchCompoundID1, &tmpMeddraAllSe.StitchCompoundID2, &tmpMeddraAllSe.CUI, &tmpMeddraAllSe.MeddraConceptType, &tmpMeddraAllSe.CUIOfMeddraTerm, &tmpMeddraAllSe.SideEffectName)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddraAllSe)
	}
	return results, nil
}

func QueryMeddraFreq(query Queries.DBQuery) ([]*MeddraFreq, error) {
	fullQuery := "SELECT * FROM meddra_freq WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider: ", err)
	}
	defer rows.Close()

	var results = make([]*MeddraFreq, 0, 100)

	for rows.Next() {
		tmpMeddraFreq := new(MeddraFreq)
		err := rows.Scan(&tmpMeddraFreq.StitchCompoundID1, &tmpMeddraFreq.StitchCompoundID2, &tmpMeddraFreq.CUI, &tmpMeddraFreq.Placebo, &tmpMeddraFreq.FrequencyDescription, &tmpMeddraFreq.FreqLowerBound, &tmpMeddraFreq.FreqUpperBound, &tmpMeddraFreq.MeddraConceptType, &tmpMeddraFreq.MeddraConceptID, &tmpMeddraFreq.SideEffectName)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddraFreq)
	}
	return results, nil
}
<commit_msg>Fix error in sider.go<commit_after>package sider

import (
	"database/sql"
	"fmt"
	"log"

	"github.com/artonge/Tamalou/Queries"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

// Init DB Connection
func init() {
	var err error
	db, err = sql.Open("mysql", "gmd-read:esial@tcp(neptune.telecomnancy.univ-lorraine.fr:3306)/gmd")
	if err != nil {
		log.Fatal("Error init Sider MySQL connector init: ", err)
	}
}

func QueryMeddra(query Queries.DBQuery) ([]*Meddra, error) {
	fullQuery := "SELECT * FROM meddra WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider (meddra): %v", err)
	}
	defer rows.Close()

	var results = make([]*Meddra, 0, 100)

	for rows.Next() {
		tmpMeddra := new(Meddra)
		err := rows.Scan(&tmpMeddra.CUI, &tmpMeddra.ConceptType, &tmpMeddra.MeddraID, &tmpMeddra.Label)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddra)
	}
	return results, nil
}

func QueryMeddraAllIndications(query Queries.DBQuery) ([]*MeddraAllIndications, error) {
	fullQuery := "SELECT * FROM meddra_all_indications WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider: %v", err)
	}
	defer rows.Close()

	var results = make([]*MeddraAllIndications, 0, 100)

	for rows.Next() {
		tmpMeddraAllIndications := new(MeddraAllIndications)
		err := rows.Scan(&tmpMeddraAllIndications.StitchCompoundID, &tmpMeddraAllIndications.CUI, &tmpMeddraAllIndications.MethodOfDetection, &tmpMeddraAllIndications.ConceptName, &tmpMeddraAllIndications.MeddraConceptType, &tmpMeddraAllIndications.CUIOfMeddraTerm, &tmpMeddraAllIndications.MeddraConceptName)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddraAllIndications)
	}
	return results, nil
}

func QueryMeddraAllSe(query Queries.DBQuery) ([]*MeddraAllSe, error) {
	fullQuery := "SELECT * FROM meddra_all_se WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider (meddra_all_se): %v", err)
	}
	defer rows.Close()

	var results = make([]*MeddraAllSe, 0, 100)

	for rows.Next() {
		tmpMeddraAllSe := new(MeddraAllSe)
		err := rows.Scan(&tmpMeddraAllSe.StitchCompoundID1, &tmpMeddraAllSe.StitchCompoundID2, &tmpMeddraAllSe.CUI, &tmpMeddraAllSe.MeddraConceptType, &tmpMeddraAllSe.CUIOfMeddraTerm, &tmpMeddraAllSe.SideEffectName)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddraAllSe)
	}
	return results, nil
}

func QueryMeddraFreq(query Queries.DBQuery) ([]*MeddraFreq, error) {
	fullQuery := "SELECT * FROM meddra_freq WHERE " + Queries.BuildSQLQuery(query, "")

	// Make the query
	rows, err := db.Query(fullQuery)
	if err != nil {
		return nil, fmt.Errorf("Error while querying sider: %v", err)
	}
	defer rows.Close()

	var results = make([]*MeddraFreq, 0, 100)

	for rows.Next() {
		tmpMeddraFreq := new(MeddraFreq)
		err := rows.Scan(&tmpMeddraFreq.StitchCompoundID1, &tmpMeddraFreq.StitchCompoundID2, &tmpMeddraFreq.CUI, &tmpMeddraFreq.Placebo, &tmpMeddraFreq.FrequencyDescription, &tmpMeddraFreq.FreqLowerBound, &tmpMeddraFreq.FreqUpperBound, &tmpMeddraFreq.MeddraConceptType, &tmpMeddraFreq.MeddraConceptID, &tmpMeddraFreq.SideEffectName)
		if err != nil {
			return results, err
		}
		results = append(results, tmpMeddraFreq)
	}
	return results, nil
}
<|endoftext|>


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

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

var testData uint32

func checkSymbols(t *testing.T, nmoutput []byte) {
	switch runtime.GOOS {
	case "linux", "darwin", "solaris":
		t.Skip("skipping test; see http://golang.org/issue/7829")
	}
	var checkSymbolsFound, testDataFound bool
	scanner := bufio.NewScanner(bytes.NewBuffer(nmoutput))
	for scanner.Scan() {
		f := strings.Fields(scanner.Text())
		if len(f) < 3 {
			t.Error("nm must have at least 3 columns")
			continue
		}
		switch f[2] {
		case "cmd/nm.checkSymbols":
			checkSymbolsFound = true
			addr := "0x" + f[0]
			if addr != fmt.Sprintf("%p", checkSymbols) {
				t.Errorf("nm shows wrong address %v for checkSymbols (%p)", addr, checkSymbols)
			}
		case "cmd/nm.testData":
			testDataFound = true
			addr := "0x" + f[0]
			if addr != fmt.Sprintf("%p", &testData) {
				t.Errorf("nm shows wrong address %v for testData (%p)", addr, &testData)
			}
		}
	}
	if err := scanner.Err(); err != nil {
		t.Errorf("error while reading symbols: %v", err)
		return
	}
	if !checkSymbolsFound {
		t.Error("nm shows no checkSymbols symbol")
	}
	if !testDataFound {
		t.Error("nm shows no testData symbol")
	}
}

func TestNM(t *testing.T) {
	out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput()
	if err != nil {
		t.Fatalf("go build -o testnm.exe cmd/nm: %v\n%s", err, string(out))
	}
	defer os.Remove("testnm.exe")

	testfiles := []string{
		"elf/testdata/gcc-386-freebsd-exec",
		"elf/testdata/gcc-amd64-linux-exec",
		"macho/testdata/gcc-386-darwin-exec",
		"macho/testdata/gcc-amd64-darwin-exec",
		"pe/testdata/gcc-amd64-mingw-exec",
		"pe/testdata/gcc-386-mingw-exec",
		"plan9obj/testdata/amd64-plan9-exec",
		"plan9obj/testdata/386-plan9-exec",
	}
	for _, f := range testfiles {
		exepath := filepath.Join(runtime.GOROOT(), "src", "pkg", "debug", f)
		cmd := exec.Command("./testnm.exe", exepath)
		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out))
		}
	}

	cmd := exec.Command("./testnm.exe", os.Args[0])
	out, err = cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
	}
	checkSymbols(t, out)
}
<commit_msg>cmd/nm: do not fail TestNM if symbol has less then 3 columns in nm output<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

var testData uint32

func checkSymbols(t *testing.T, nmoutput []byte) {
	var checkSymbolsFound, testDataFound bool
	scanner := bufio.NewScanner(bytes.NewBuffer(nmoutput))
	for scanner.Scan() {
		f := strings.Fields(scanner.Text())
		if len(f) < 3 {
			continue
		}
		switch f[2] {
		case "cmd/nm.checkSymbols":
			checkSymbolsFound = true
			addr := "0x" + f[0]
			if addr != fmt.Sprintf("%p", checkSymbols) {
				t.Errorf("nm shows wrong address %v for checkSymbols (%p)", addr, checkSymbols)
			}
		case "cmd/nm.testData":
			testDataFound = true
			addr := "0x" + f[0]
			if addr != fmt.Sprintf("%p", &testData) {
				t.Errorf("nm shows wrong address %v for testData (%p)", addr, &testData)
			}
		}
	}
	if err := scanner.Err(); err != nil {
		t.Errorf("error while reading symbols: %v", err)
		return
	}
	if !checkSymbolsFound {
		t.Error("nm shows no checkSymbols symbol")
	}
	if !testDataFound {
		t.Error("nm shows no testData symbol")
	}
}

func TestNM(t *testing.T) {
	out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput()
	if err != nil {
		t.Fatalf("go build -o testnm.exe cmd/nm: %v\n%s", err, string(out))
	}
	defer os.Remove("testnm.exe")

	testfiles := []string{
		"elf/testdata/gcc-386-freebsd-exec",
		"elf/testdata/gcc-amd64-linux-exec",
		"macho/testdata/gcc-386-darwin-exec",
		"macho/testdata/gcc-amd64-darwin-exec",
		"pe/testdata/gcc-amd64-mingw-exec",
		"pe/testdata/gcc-386-mingw-exec",
		"plan9obj/testdata/amd64-plan9-exec",
		"plan9obj/testdata/386-plan9-exec",
	}
	for _, f := range testfiles {
		exepath := filepath.Join(runtime.GOROOT(), "src", "pkg", "debug", f)
		cmd := exec.Command("./testnm.exe", exepath)
		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out))
		}
	}

	cmd := exec.Command("./testnm.exe", os.Args[0])
	out, err = cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
	}
	checkSymbols(t, out)
}
<|endoftext|>


<commit_before>// See https://blog.filippo.io/building-python-modules-with-go-1-5/#thecompletedemosource
// TBD<commit_msg>wip on python module, not much time, contraction time<commit_after>// See https://blog.filippo.io/building-python-modules-with-go-1-5/#thecompletedemosource
// and https://gopy.qur.me/extensions/examples.html

package main

import (
	"bufio"
	"dealer"
	"encoding/json"
	"fmt"
  "gopy"
	"net"
	"strconv"
	"time"
)

struct PySocket {
  socket  dealer.Socket
  port    string
  address string
}

func Connect(s *PySocket, args *py.Tuple)(err Error) {
  // Parse python arguments
  var o py.Object
  if err := py.ParseTuple(args, "O", &o); err != nil {
    fmt.Println("Error parsing arguments")
  }

  // Connect dealer
  s.socket = dealer.Socket{}
  if err = s.socket.Connect( o[0], o[1]); err != nil {
    fmt.Println("Error creating the socket")
  }
}

func Read(s * PySocket, list *py.List) (error Error){
  // TODO: Ben
  // We need to grab the ID here, and do a ReadJSON on the dealer socket
}

func Send(s * PySocket, list *py.List) (error Error){
  // TODO: Ben
}

func Close(s *PySocket) {
  s.socket.Close()
}
<|endoftext|>


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

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package socktest

import "syscall"

// Socket wraps syscall.Socket.
func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) {
	sw.once.Do(sw.init)

	so := &Status{Cookie: cookie(family, sotype, proto)}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterSocket]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return -1, err
	}
	s, so.Err = syscall.Socket(family, sotype, proto)
	if err = af.apply(so); err != nil {
		if so.Err == nil {
			syscall.Close(s)
		}
		return -1, err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).OpenFailed++
		return -1, so.Err
	}
	nso := sw.addLocked(s, family, sotype, proto)
	sw.stats.getLocked(nso.Cookie).Opened++
	return s, nil
}

// Close wraps syscall.Close.
func (sw *Switch) Close(s int) (err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Close(s)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterClose]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return err
	}
	so.Err = syscall.Close(s)
	if err = af.apply(so); err != nil {
		return err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).CloseFailed++
		return so.Err
	}
	delete(sw.sotab, s)
	sw.stats.getLocked(so.Cookie).Closed++
	return nil
}

// Connect wraps syscall.Connect.
func (sw *Switch) Connect(s int, sa syscall.Sockaddr) (err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Connect(s, sa)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterConnect]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return err
	}
	so.Err = syscall.Connect(s, sa)
	if err = af.apply(so); err != nil {
		return err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).ConnectFailed++
		return so.Err
	}
	sw.stats.getLocked(so.Cookie).Connected++
	return nil
}

// Listen wraps syscall.Listen.
func (sw *Switch) Listen(s, backlog int) (err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Listen(s, backlog)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterListen]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return err
	}
	so.Err = syscall.Listen(s, backlog)
	if err = af.apply(so); err != nil {
		return err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).ListenFailed++
		return so.Err
	}
	sw.stats.getLocked(so.Cookie).Listened++
	return nil
}

// Accept wraps syscall.Accept.
func (sw *Switch) Accept(s int) (ns int, sa syscall.Sockaddr, err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Accept(s)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterAccept]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return -1, nil, err
	}
	ns, sa, so.Err = syscall.Accept(s)
	if err = af.apply(so); err != nil {
		if so.Err == nil {
			syscall.Close(ns)
		}
		return -1, nil, err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).AcceptFailed++
		return -1, nil, so.Err
	}
	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
	sw.stats.getLocked(nso.Cookie).Accepted++
	return ns, sa, nil
}

// GetsockoptInt wraps syscall.GetsockoptInt.
func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.GetsockoptInt(s, level, opt)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterGetsockoptInt]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return -1, err
	}
	soerr, so.Err = syscall.GetsockoptInt(s, level, opt)
	so.SocketErr = syscall.Errno(soerr)
	if err = af.apply(so); err != nil {
		return -1, err
	}

	if so.Err != nil {
		return -1, so.Err
	}
	if opt == syscall.SO_ERROR && (so.SocketErr == syscall.Errno(0) || so.SocketErr == syscall.EISCONN) {
		sw.smu.Lock()
		sw.stats.getLocked(so.Cookie).Connected++
		sw.smu.Unlock()
	}
	return soerr, nil
}
<commit_msg>net/internal/socktest: build sys_unix.go on AIX<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package socktest

import "syscall"

// Socket wraps syscall.Socket.
func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) {
	sw.once.Do(sw.init)

	so := &Status{Cookie: cookie(family, sotype, proto)}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterSocket]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return -1, err
	}
	s, so.Err = syscall.Socket(family, sotype, proto)
	if err = af.apply(so); err != nil {
		if so.Err == nil {
			syscall.Close(s)
		}
		return -1, err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).OpenFailed++
		return -1, so.Err
	}
	nso := sw.addLocked(s, family, sotype, proto)
	sw.stats.getLocked(nso.Cookie).Opened++
	return s, nil
}

// Close wraps syscall.Close.
func (sw *Switch) Close(s int) (err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Close(s)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterClose]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return err
	}
	so.Err = syscall.Close(s)
	if err = af.apply(so); err != nil {
		return err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).CloseFailed++
		return so.Err
	}
	delete(sw.sotab, s)
	sw.stats.getLocked(so.Cookie).Closed++
	return nil
}

// Connect wraps syscall.Connect.
func (sw *Switch) Connect(s int, sa syscall.Sockaddr) (err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Connect(s, sa)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterConnect]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return err
	}
	so.Err = syscall.Connect(s, sa)
	if err = af.apply(so); err != nil {
		return err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).ConnectFailed++
		return so.Err
	}
	sw.stats.getLocked(so.Cookie).Connected++
	return nil
}

// Listen wraps syscall.Listen.
func (sw *Switch) Listen(s, backlog int) (err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Listen(s, backlog)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterListen]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return err
	}
	so.Err = syscall.Listen(s, backlog)
	if err = af.apply(so); err != nil {
		return err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).ListenFailed++
		return so.Err
	}
	sw.stats.getLocked(so.Cookie).Listened++
	return nil
}

// Accept wraps syscall.Accept.
func (sw *Switch) Accept(s int) (ns int, sa syscall.Sockaddr, err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.Accept(s)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterAccept]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return -1, nil, err
	}
	ns, sa, so.Err = syscall.Accept(s)
	if err = af.apply(so); err != nil {
		if so.Err == nil {
			syscall.Close(ns)
		}
		return -1, nil, err
	}

	sw.smu.Lock()
	defer sw.smu.Unlock()
	if so.Err != nil {
		sw.stats.getLocked(so.Cookie).AcceptFailed++
		return -1, nil, so.Err
	}
	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
	sw.stats.getLocked(nso.Cookie).Accepted++
	return ns, sa, nil
}

// GetsockoptInt wraps syscall.GetsockoptInt.
func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) {
	so := sw.sockso(s)
	if so == nil {
		return syscall.GetsockoptInt(s, level, opt)
	}
	sw.fmu.RLock()
	f, _ := sw.fltab[FilterGetsockoptInt]
	sw.fmu.RUnlock()

	af, err := f.apply(so)
	if err != nil {
		return -1, err
	}
	soerr, so.Err = syscall.GetsockoptInt(s, level, opt)
	so.SocketErr = syscall.Errno(soerr)
	if err = af.apply(so); err != nil {
		return -1, err
	}

	if so.Err != nil {
		return -1, so.Err
	}
	if opt == syscall.SO_ERROR && (so.SocketErr == syscall.Errno(0) || so.SocketErr == syscall.EISCONN) {
		sw.smu.Lock()
		sw.stats.getLocked(so.Cookie).Connected++
		sw.smu.Unlock()
	}
	return soerr, nil
}
<|endoftext|>


<commit_before>package rest

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

type RestHandler interface {
	Handler(http.ResponseWriter, *http.Request)
	ServeRest(params map[string][]string) (interface{}, *RestError)
	Context() string
}

type RestHandlerBase struct {
	context string
	rh      RestHandler
}

func NewRestHandlerBase(context string, rh RestHandler) *RestHandlerBase {
	rhb := new(RestHandlerBase)
	rhb.context = context
	rhb.rh = rh
	return rhb
}

func (rhb *RestHandlerBase) Handler(rw http.ResponseWriter, r *http.Request) {
	e0 := r.ParseForm()
	if e0 != nil {
		io.WriteString(rw, ErrorMessages[REQUEST_PARSE])
		return
	}
	content, e1 := rhb.rh.ServeRest(r.Form)
	if e1 != nil {
		io.WriteString(rw, ErrorMessages[GENERIC_SERVER])
		return
	}
	byteArr, e2 := json.Marshal(content)
	if e2 != nil {
		io.WriteString(rw, ErrorMessages[JSON_MARSHALLING])
		return
	}
	rw.Write(byteArr)
}

func (rhb *RestHandlerBase) Context() string {
	return rhb.context
}
<commit_msg>substantial simplifications<commit_after>package rest

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
)

type APIProvider func() HandlerSpec

type RestHandler func(map[string][]string) (interface{}, *RestError)

type HandlerSpec struct {
	Context   string
	ServeRest RestHandler
}

type HttpHandler func(http.ResponseWriter, *http.Request)

func MuxHandler(hs HandlerSpec) HttpHandler {
	return func(rw http.ResponseWriter, r *http.Request) {
		e0 := r.ParseForm()
		if e0 != nil {
			io.WriteString(rw, ErrorMessages[REQUEST_PARSE])
			return
		}
		content, e1 := hs.ServeRest(r.Form)
		if e1 != nil {
			io.WriteString(rw, ErrorMessages[GENERIC_SERVER])
			return
		}
		byteArr, e2 := json.Marshal(content)
		if e2 != nil {
			io.WriteString(rw, ErrorMessages[JSON_MARSHALLING])
			return
		}
		rw.Header().Add("Content-Type", "application/json")
		rw.WriteHeader(http.StatusOK)
		rw.Write(byteArr)
	}
}

func AcceptRequests(restAPI interface{}) {
	mux := http.NewServeMux()
	raValue := reflect.ValueOf(restAPI)
	for i := 0; i < raValue.NumMethod(); i++ {
		spec := raValue.Method(i).Call([]reflect.Value{})
		specIF := spec[0].Interface()
		hs := specIF.(HandlerSpec)
		handler := MuxHandler(hs)
		fmt.Println("handling ", hs.Context)
		mux.HandleFunc(hs.Context, handler)
	}
	fmt.Println("Listening...")
	http.ListenAndServe(":9090", mux)
}
<|endoftext|>


<commit_before>package influxdb_output

import (
	"context"
	"crypto/tls"
	"encoding/json"
	"io/ioutil"
	"log"
	"math"
	"strings"
	"time"

	influxdb2 "github.com/influxdata/influxdb-client-go/v2"
	"github.com/karimra/gnmic/formatters"
	"github.com/karimra/gnmic/outputs"
	"github.com/openconfig/gnmi/proto/gnmi"
	"github.com/prometheus/client_golang/prometheus"
	"google.golang.org/protobuf/proto"
)

const (
	defaultURL               = "http://localhost:8086"
	defaultBatchSize         = 1000
	defaultFlushTimer        = 10 * time.Second
	defaultHealthCheckPeriod = 30 * time.Second

	numWorkers    = 1
	loggingPrefix = "[influxdb_output] "
)

func init() {
	outputs.Register("influxdb", func() outputs.Output {
		return &InfluxDBOutput{
			Cfg:       &Config{},
			eventChan: make(chan *formatters.EventMsg),
			reset:     make(chan struct{}),
			startSig:  make(chan struct{}),
			logger:    log.New(ioutil.Discard, loggingPrefix, log.LstdFlags|log.Lmicroseconds),
		}
	})
}

type InfluxDBOutput struct {
	Cfg       *Config
	client    influxdb2.Client
	logger    *log.Logger
	cancelFn  context.CancelFunc
	eventChan chan *formatters.EventMsg
	reset     chan struct{}
	startSig  chan struct{}
	wasUP     bool
	evps      []formatters.EventProcessor
	dbVersion string
}
type Config struct {
	URL                string        `mapstructure:"url,omitempty"`
	Org                string        `mapstructure:"org,omitempty"`
	Bucket             string        `mapstructure:"bucket,omitempty"`
	Token              string        `mapstructure:"token,omitempty"`
	BatchSize          uint          `mapstructure:"batch-size,omitempty"`
	FlushTimer         time.Duration `mapstructure:"flush-timer,omitempty"`
	UseGzip            bool          `mapstructure:"use-gzip,omitempty"`
	EnableTLS          bool          `mapstructure:"enable-tls,omitempty"`
	HealthCheckPeriod  time.Duration `mapstructure:"health-check-period,omitempty"`
	Debug              bool          `mapstructure:"debug,omitempty"`
	EventProcessors    []string      `mapstructure:"event-processors,omitempty"`
	EnableMetrics      bool          `mapstructure:"enable-metrics,omitempty"`
	OverrideTimestamps bool          `mapstructure:"override-timestamps,omitempty"`
}

func (k *InfluxDBOutput) String() string {
	b, err := json.Marshal(k)
	if err != nil {
		return ""
	}
	return string(b)
}

func (i *InfluxDBOutput) SetLogger(logger *log.Logger) {
	if logger != nil && i.logger != nil {
		i.logger.SetOutput(logger.Writer())
		i.logger.SetFlags(logger.Flags())
	}
}

func (i *InfluxDBOutput) SetEventProcessors(ps map[string]map[string]interface{}, logger *log.Logger, tcs map[string]interface{}) {
	for _, epName := range i.Cfg.EventProcessors {
		if epCfg, ok := ps[epName]; ok {
			epType := ""
			for k := range epCfg {
				epType = k
				break
			}
			if in, ok := formatters.EventProcessors[epType]; ok {
				ep := in()
				err := ep.Init(epCfg[epType], formatters.WithLogger(logger), formatters.WithTargets(tcs))
				if err != nil {
					i.logger.Printf("failed initializing event processor '%s' of type='%s': %v", epName, epType, err)
					continue
				}
				i.evps = append(i.evps, ep)
				i.logger.Printf("added event processor '%s' of type=%s to influxdb output", epName, epType)
				continue
			}
			i.logger.Printf("%q event processor has an unknown type=%q", epName, epType)
			continue
		}
		i.logger.Printf("%q event processor not found!", epName)
	}
}

func (i *InfluxDBOutput) Init(ctx context.Context, name string, cfg map[string]interface{}, opts ...outputs.Option) error {
	err := outputs.DecodeConfig(cfg, i.Cfg)
	if err != nil {
		return err
	}
	for _, opt := range opts {
		opt(i)
	}
	if i.Cfg.URL == "" {
		i.Cfg.URL = defaultURL
	}
	if i.Cfg.BatchSize == 0 {
		i.Cfg.BatchSize = defaultBatchSize
	}
	if i.Cfg.FlushTimer == 0 {
		i.Cfg.FlushTimer = defaultFlushTimer
	}
	if i.Cfg.HealthCheckPeriod == 0 {
		i.Cfg.HealthCheckPeriod = defaultHealthCheckPeriod
	}

	iopts := influxdb2.DefaultOptions().
		SetUseGZip(i.Cfg.UseGzip).
		SetBatchSize(i.Cfg.BatchSize).
		SetFlushInterval(uint(i.Cfg.FlushTimer.Milliseconds()))
	if i.Cfg.EnableTLS {
		iopts.SetTLSConfig(&tls.Config{
			InsecureSkipVerify: true,
		})
	}
	if i.Cfg.Debug {
		iopts.SetLogLevel(3)
	}
	ctx, i.cancelFn = context.WithCancel(ctx)
CRCLIENT:
	i.client = influxdb2.NewClientWithOptions(i.Cfg.URL, i.Cfg.Token, iopts)
	// start influx health check
	err = i.health(ctx)
	if err != nil {
		i.logger.Printf("failed to check influxdb health: %v", err)
		time.Sleep(10 * time.Second)
		goto CRCLIENT
	}
	i.wasUP = true
	go i.healthCheck(ctx)
	i.logger.Printf("initialized influxdb client: %s", i.String())

	for k := 0; k < numWorkers; k++ {
		go i.worker(ctx, k)
	}
	go func() {
		<-ctx.Done()
		i.Close()
	}()
	return nil
}

func (i *InfluxDBOutput) Write(ctx context.Context, rsp proto.Message, meta outputs.Meta) {
	if rsp == nil {
		return
	}
	switch rsp := rsp.(type) {
	case *gnmi.SubscribeResponse:
		measName := "default"
		if subName, ok := meta["subscription-name"]; ok {
			measName = subName
		}
		events, err := formatters.ResponseToEventMsgs(measName, rsp, meta, i.evps...)
		if err != nil {
			i.logger.Printf("failed to convert message to event: %v", err)
			return
		}
		for _, ev := range events {
			select {
			case <-ctx.Done():
				return
			case <-i.reset:
				return
			case i.eventChan <- ev:
			}
		}
	}
}

func (i *InfluxDBOutput) WriteEvent(ctx context.Context, ev *formatters.EventMsg) {}

func (i *InfluxDBOutput) Close() error {
	i.logger.Printf("closing client...")
	i.cancelFn()
	i.logger.Printf("closed.")
	return nil
}
func (i *InfluxDBOutput) RegisterMetrics(reg *prometheus.Registry) {}

func (i *InfluxDBOutput) healthCheck(ctx context.Context) {
	ticker := time.NewTicker(i.Cfg.HealthCheckPeriod)
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			i.health(ctx)
		}
	}
}

func (i *InfluxDBOutput) health(ctx context.Context) error {
	res, err := i.client.Health(ctx)
	if err != nil {
		i.logger.Printf("failed health check: %v", err)
		if i.wasUP {
			close(i.reset)
			i.reset = make(chan struct{})
		}
		return err
	}
	if res != nil {
		if res.Version != nil {
			i.dbVersion = *res.Version
		}
		b, err := json.Marshal(res)
		if err != nil {
			i.logger.Printf("failed to marshal health check result: %v", err)
			i.logger.Printf("health check result: %+v", res)
			if i.wasUP {
				close(i.reset)
				i.reset = make(chan struct{})
			}
			return err
		}
		i.wasUP = true
		close(i.startSig)
		i.startSig = make(chan struct{})
		i.logger.Printf("health check result: %s", string(b))
		return nil
	}
	i.wasUP = true
	close(i.startSig)
	i.startSig = make(chan struct{})
	i.logger.Print("health check result is nil")
	return nil
}

func (i *InfluxDBOutput) worker(ctx context.Context, idx int) {
	firstStart := true
START:
	if !firstStart {
		i.logger.Printf("worker-%d waiting for client recovery", idx)
		<-i.startSig
	}
	i.logger.Printf("starting worker-%d", idx)
	writer := i.client.WriteAPI(i.Cfg.Org, i.Cfg.Bucket)
	//defer writer.Flush()
	for {
		select {
		case <-ctx.Done():
			if ctx.Err() != nil {
				i.logger.Printf("worker-%d err=%v", idx, ctx.Err())
			}
			i.logger.Printf("worker-%d terminating...", idx)
			return
		case ev := <-i.eventChan:
			for n, v := range ev.Values {
				switch v := v.(type) {
				case *gnmi.Decimal64:
					ev.Values[n] = float64(v.Digits) / math.Pow10(int(v.Precision))
				}
			}
			if ev.Timestamp == 0 || i.Cfg.OverrideTimestamps {
				ev.Timestamp = time.Now().UnixNano()
			}
			i.convertUints(ev)
			writer.WritePoint(influxdb2.NewPoint(ev.Name, ev.Tags, ev.Values, time.Unix(0, ev.Timestamp)))
		case <-i.reset:
			firstStart = false
			i.logger.Printf("resetting worker-%d...", idx)
			goto START
		case err := <-writer.Errors():
			i.logger.Printf("worker-%d write error: %v", idx, err)
		}
	}
}

func (i *InfluxDBOutput) SetName(name string)        {}
func (i *InfluxDBOutput) SetClusterName(name string) {}

func (i *InfluxDBOutput) convertUints(ev *formatters.EventMsg) {
	if !strings.HasPrefix(i.dbVersion, "1.8") {
		return
	}
	for k, v := range ev.Values {
		switch v := v.(type) {
		case uint:
			ev.Values[k] = int(v)
		}
	}
}
<commit_msg>fix uint conv<commit_after>package influxdb_output

import (
	"context"
	"crypto/tls"
	"encoding/json"
	"io/ioutil"
	"log"
	"math"
	"strings"
	"time"

	influxdb2 "github.com/influxdata/influxdb-client-go/v2"
	"github.com/karimra/gnmic/formatters"
	"github.com/karimra/gnmic/outputs"
	"github.com/openconfig/gnmi/proto/gnmi"
	"github.com/prometheus/client_golang/prometheus"
	"google.golang.org/protobuf/proto"
)

const (
	defaultURL               = "http://localhost:8086"
	defaultBatchSize         = 1000
	defaultFlushTimer        = 10 * time.Second
	defaultHealthCheckPeriod = 30 * time.Second

	numWorkers    = 1
	loggingPrefix = "[influxdb_output] "
)

func init() {
	outputs.Register("influxdb", func() outputs.Output {
		return &InfluxDBOutput{
			Cfg:       &Config{},
			eventChan: make(chan *formatters.EventMsg),
			reset:     make(chan struct{}),
			startSig:  make(chan struct{}),
			logger:    log.New(ioutil.Discard, loggingPrefix, log.LstdFlags|log.Lmicroseconds),
		}
	})
}

type InfluxDBOutput struct {
	Cfg       *Config
	client    influxdb2.Client
	logger    *log.Logger
	cancelFn  context.CancelFunc
	eventChan chan *formatters.EventMsg
	reset     chan struct{}
	startSig  chan struct{}
	wasUP     bool
	evps      []formatters.EventProcessor
	dbVersion string
}
type Config struct {
	URL                string        `mapstructure:"url,omitempty"`
	Org                string        `mapstructure:"org,omitempty"`
	Bucket             string        `mapstructure:"bucket,omitempty"`
	Token              string        `mapstructure:"token,omitempty"`
	BatchSize          uint          `mapstructure:"batch-size,omitempty"`
	FlushTimer         time.Duration `mapstructure:"flush-timer,omitempty"`
	UseGzip            bool          `mapstructure:"use-gzip,omitempty"`
	EnableTLS          bool          `mapstructure:"enable-tls,omitempty"`
	HealthCheckPeriod  time.Duration `mapstructure:"health-check-period,omitempty"`
	Debug              bool          `mapstructure:"debug,omitempty"`
	EventProcessors    []string      `mapstructure:"event-processors,omitempty"`
	EnableMetrics      bool          `mapstructure:"enable-metrics,omitempty"`
	OverrideTimestamps bool          `mapstructure:"override-timestamps,omitempty"`
}

func (k *InfluxDBOutput) String() string {
	b, err := json.Marshal(k)
	if err != nil {
		return ""
	}
	return string(b)
}

func (i *InfluxDBOutput) SetLogger(logger *log.Logger) {
	if logger != nil && i.logger != nil {
		i.logger.SetOutput(logger.Writer())
		i.logger.SetFlags(logger.Flags())
	}
}

func (i *InfluxDBOutput) SetEventProcessors(ps map[string]map[string]interface{}, logger *log.Logger, tcs map[string]interface{}) {
	for _, epName := range i.Cfg.EventProcessors {
		if epCfg, ok := ps[epName]; ok {
			epType := ""
			for k := range epCfg {
				epType = k
				break
			}
			if in, ok := formatters.EventProcessors[epType]; ok {
				ep := in()
				err := ep.Init(epCfg[epType], formatters.WithLogger(logger), formatters.WithTargets(tcs))
				if err != nil {
					i.logger.Printf("failed initializing event processor '%s' of type='%s': %v", epName, epType, err)
					continue
				}
				i.evps = append(i.evps, ep)
				i.logger.Printf("added event processor '%s' of type=%s to influxdb output", epName, epType)
				continue
			}
			i.logger.Printf("%q event processor has an unknown type=%q", epName, epType)
			continue
		}
		i.logger.Printf("%q event processor not found!", epName)
	}
}

func (i *InfluxDBOutput) Init(ctx context.Context, name string, cfg map[string]interface{}, opts ...outputs.Option) error {
	err := outputs.DecodeConfig(cfg, i.Cfg)
	if err != nil {
		return err
	}
	for _, opt := range opts {
		opt(i)
	}
	if i.Cfg.URL == "" {
		i.Cfg.URL = defaultURL
	}
	if i.Cfg.BatchSize == 0 {
		i.Cfg.BatchSize = defaultBatchSize
	}
	if i.Cfg.FlushTimer == 0 {
		i.Cfg.FlushTimer = defaultFlushTimer
	}
	if i.Cfg.HealthCheckPeriod == 0 {
		i.Cfg.HealthCheckPeriod = defaultHealthCheckPeriod
	}

	iopts := influxdb2.DefaultOptions().
		SetUseGZip(i.Cfg.UseGzip).
		SetBatchSize(i.Cfg.BatchSize).
		SetFlushInterval(uint(i.Cfg.FlushTimer.Milliseconds()))
	if i.Cfg.EnableTLS {
		iopts.SetTLSConfig(&tls.Config{
			InsecureSkipVerify: true,
		})
	}
	if i.Cfg.Debug {
		iopts.SetLogLevel(3)
	}
	ctx, i.cancelFn = context.WithCancel(ctx)
CRCLIENT:
	i.client = influxdb2.NewClientWithOptions(i.Cfg.URL, i.Cfg.Token, iopts)
	// start influx health check
	err = i.health(ctx)
	if err != nil {
		i.logger.Printf("failed to check influxdb health: %v", err)
		time.Sleep(10 * time.Second)
		goto CRCLIENT
	}
	i.wasUP = true
	go i.healthCheck(ctx)
	i.logger.Printf("initialized influxdb client: %s", i.String())

	for k := 0; k < numWorkers; k++ {
		go i.worker(ctx, k)
	}
	go func() {
		<-ctx.Done()
		i.Close()
	}()
	return nil
}

func (i *InfluxDBOutput) Write(ctx context.Context, rsp proto.Message, meta outputs.Meta) {
	if rsp == nil {
		return
	}
	switch rsp := rsp.(type) {
	case *gnmi.SubscribeResponse:
		measName := "default"
		if subName, ok := meta["subscription-name"]; ok {
			measName = subName
		}
		events, err := formatters.ResponseToEventMsgs(measName, rsp, meta, i.evps...)
		if err != nil {
			i.logger.Printf("failed to convert message to event: %v", err)
			return
		}
		for _, ev := range events {
			select {
			case <-ctx.Done():
				return
			case <-i.reset:
				return
			case i.eventChan <- ev:
			}
		}
	}
}

func (i *InfluxDBOutput) WriteEvent(ctx context.Context, ev *formatters.EventMsg) {}

func (i *InfluxDBOutput) Close() error {
	i.logger.Printf("closing client...")
	i.cancelFn()
	i.logger.Printf("closed.")
	return nil
}
func (i *InfluxDBOutput) RegisterMetrics(reg *prometheus.Registry) {}

func (i *InfluxDBOutput) healthCheck(ctx context.Context) {
	ticker := time.NewTicker(i.Cfg.HealthCheckPeriod)
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			i.health(ctx)
		}
	}
}

func (i *InfluxDBOutput) health(ctx context.Context) error {
	res, err := i.client.Health(ctx)
	if err != nil {
		i.logger.Printf("failed health check: %v", err)
		if i.wasUP {
			close(i.reset)
			i.reset = make(chan struct{})
		}
		return err
	}
	if res != nil {
		if res.Version != nil {
			i.dbVersion = *res.Version
		}
		b, err := json.Marshal(res)
		if err != nil {
			i.logger.Printf("failed to marshal health check result: %v", err)
			i.logger.Printf("health check result: %+v", res)
			if i.wasUP {
				close(i.reset)
				i.reset = make(chan struct{})
			}
			return err
		}
		i.wasUP = true
		close(i.startSig)
		i.startSig = make(chan struct{})
		i.logger.Printf("health check result: %s", string(b))
		return nil
	}
	i.wasUP = true
	close(i.startSig)
	i.startSig = make(chan struct{})
	i.logger.Print("health check result is nil")
	return nil
}

func (i *InfluxDBOutput) worker(ctx context.Context, idx int) {
	firstStart := true
START:
	if !firstStart {
		i.logger.Printf("worker-%d waiting for client recovery", idx)
		<-i.startSig
	}
	i.logger.Printf("starting worker-%d", idx)
	writer := i.client.WriteAPI(i.Cfg.Org, i.Cfg.Bucket)
	//defer writer.Flush()
	for {
		select {
		case <-ctx.Done():
			if ctx.Err() != nil {
				i.logger.Printf("worker-%d err=%v", idx, ctx.Err())
			}
			i.logger.Printf("worker-%d terminating...", idx)
			return
		case ev := <-i.eventChan:
			for n, v := range ev.Values {
				switch v := v.(type) {
				case *gnmi.Decimal64:
					ev.Values[n] = float64(v.Digits) / math.Pow10(int(v.Precision))
				}
			}
			if ev.Timestamp == 0 || i.Cfg.OverrideTimestamps {
				ev.Timestamp = time.Now().UnixNano()
			}
			i.convertUints(ev)
			writer.WritePoint(influxdb2.NewPoint(ev.Name, ev.Tags, ev.Values, time.Unix(0, ev.Timestamp)))
		case <-i.reset:
			firstStart = false
			i.logger.Printf("resetting worker-%d...", idx)
			goto START
		case err := <-writer.Errors():
			i.logger.Printf("worker-%d write error: %v", idx, err)
		}
	}
}

func (i *InfluxDBOutput) SetName(name string)        {}
func (i *InfluxDBOutput) SetClusterName(name string) {}

func (i *InfluxDBOutput) convertUints(ev *formatters.EventMsg) {
	if !strings.HasPrefix(i.dbVersion, "1.8") {
		return
	}
	for k, v := range ev.Values {
		switch v := v.(type) {
		case uint:
			ev.Values[k] = int(v)
		case uint8:
			ev.Values[k] = int(v)
		case uint16:
			ev.Values[k] = int(v)
		case uint32:
			ev.Values[k] = int(v)
		case uint64:
			ev.Values[k] = int(v)
		}
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/WatchBeam/clock"
	kitlog "github.com/go-kit/kit/log"
	kitprometheus "github.com/go-kit/kit/metrics/prometheus"
	"github.com/kolide/kolide-ose/server/config"
	"github.com/kolide/kolide-ose/server/datastore"
	"github.com/kolide/kolide-ose/server/kolide"
	"github.com/kolide/kolide-ose/server/mail"
	"github.com/kolide/kolide-ose/server/service"
	"github.com/kolide/kolide-ose/server/version"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

func createServeCmd(configManager config.Manager) *cobra.Command {
	var devMode bool = false

	serveCmd := &cobra.Command{
		Use:   "serve",
		Short: "Launch the kolide server",
		Long: `
Launch the kolide server

Use kolide serve to run the main HTTPS server. The Kolide server bundles
together all static assets and dependent libraries into a statically linked go
binary (which you're executing right now). Use the options below to customize
the way that the kolide server works.
`,
		Run: func(cmd *cobra.Command, args []string) {
			var (
				httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
				ctx      = context.Background()
				logger   kitlog.Logger
			)
			flag.Parse()

			config := configManager.LoadConfig()

			logger = kitlog.NewLogfmtLogger(os.Stderr)
			logger = kitlog.NewContext(logger).With("ts", kitlog.DefaultTimestampUTC)

			var mailService kolide.MailService
			if devMode {
				mailService = devMailService{}
			} else {
				mailService = mail.NewService(config.SMTP)
			}

			var ds kolide.Datastore
			var err error
			if devMode {
				fmt.Println(
					"Dev mode enabled, using in-memory DB.\n",
					"Warning: Changes will not be saved across process restarts. This should NOT be used in production.",
				)
				ds, err = datastore.New("inmem", "")
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			} else {
				connString := datastore.GetMysqlConnectionString(config.Mysql)
				ds, err = datastore.New("gorm-mysql", connString)
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			}

			svc, err := service.NewService(ds, logger, config, mailService, clock.C)
			if err != nil {
				initFatal(err, "initializing service")
			}

			if devMode {
				// Bootstrap a few users when using the in-memory database.
				// Each user's default password will just be their username.
				users := []kolide.User{
					{
						Name:     "Admin User",
						Username: "admin",
						Email:    "admin@kolide.co",
						Position: "Director of Security",
						Admin:    true,
						Enabled:  true,
					},
					{
						Name:     "Normal User",
						Username: "user",
						Email:    "user@kolide.co",
						Position: "Security Engineer",
						Admin:    false,
						Enabled:  true,
					},
				}

				for _, user := range users {
					user := user
					err := user.SetPassword(user.Username, config.Auth.SaltKeySize, config.Auth.BcryptCost)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
					_, err = ds.NewUser(&user)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
				}
				devOrgInfo := &kolide.OrgInfo{
					OrgName:    "Kolide",
					OrgLogoURL: fmt.Sprintf("%s/logo.png", config.Server.Address),
				}
				_, err := svc.NewOrgInfo(ctx, kolide.OrgInfoPayload{
					OrgName:    &devOrgInfo.OrgName,
					OrgLogoURL: &devOrgInfo.OrgLogoURL,
				})
				if err != nil {
					initFatal(err, "creating fake org info")
				}
			}

			fieldKeys := []string{"method", "error"}
			requestCount := kitprometheus.NewCounterFrom(prometheus.CounterOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_count",
				Help:      "Number of requests received.",
			}, fieldKeys)
			requestLatency := kitprometheus.NewSummaryFrom(prometheus.SummaryOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_latency_microseconds",
				Help:      "Total duration of requests in microseconds.",
			}, fieldKeys)

			svcLogger := kitlog.NewContext(logger).With("component", "service")
			svc = service.NewLoggingService(svc, svcLogger)
			svc = service.NewMetricsService(svc, requestCount, requestLatency)

			httpLogger := kitlog.NewContext(logger).With("component", "http")

			apiHandler := service.MakeHandler(ctx, svc, config.Auth.JwtKey, httpLogger)
			http.Handle("/api/", accessControl(apiHandler))
			http.Handle("/version", version.Handler())
			http.Handle("/metrics", prometheus.Handler())
			http.Handle("/assets/", service.ServeStaticAssets("/assets/"))
			http.Handle("/", service.ServeFrontend())

			errs := make(chan error, 2)
			go func() {
				if !config.Server.TLS || (devMode && !configManager.IsSet("server.tls")) {
					logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServe(*httpAddr, nil)
				} else {
					logger.Log("transport", "https", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServeTLS(
						*httpAddr,
						config.Server.Cert,
						config.Server.Key,
						nil,
					)
				}
			}()
			go func() {
				c := make(chan os.Signal)
				signal.Notify(c, syscall.SIGINT)
				errs <- fmt.Errorf("%s", <-c)
			}()

			logger.Log("terminated", <-errs)
		},
	}

	serveCmd.PersistentFlags().BoolVar(&devMode, "dev", false, "Use dev settings (in-mem DB, etc.)")

	return serveCmd
}

// used in devMode to print an email
// which would otherwise be sent via SMTP
type devMailService struct{}

func (devMailService) SendEmail(e kolide.Email) error {
	fmt.Println("---dev mode: printing email---")
	defer fmt.Println("---dev mode: email printed---")
	msg, err := e.Msg.Message()
	if err != nil {
		return err
	}
	fmt.Printf("From: %q To: %q \n", e.From, e.To)
	_, err = os.Stdout.Write(msg)
	return err

}

// cors headers
func accessControl(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")

		if r.Method == "OPTIONS" {
			return
		}

		h.ServeHTTP(w, r)
	})
}
<commit_msg>remove unused cors headers (#296)<commit_after>package cli

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/WatchBeam/clock"
	kitlog "github.com/go-kit/kit/log"
	kitprometheus "github.com/go-kit/kit/metrics/prometheus"
	"github.com/kolide/kolide-ose/server/config"
	"github.com/kolide/kolide-ose/server/datastore"
	"github.com/kolide/kolide-ose/server/kolide"
	"github.com/kolide/kolide-ose/server/mail"
	"github.com/kolide/kolide-ose/server/service"
	"github.com/kolide/kolide-ose/server/version"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

func createServeCmd(configManager config.Manager) *cobra.Command {
	var devMode bool = false

	serveCmd := &cobra.Command{
		Use:   "serve",
		Short: "Launch the kolide server",
		Long: `
Launch the kolide server

Use kolide serve to run the main HTTPS server. The Kolide server bundles
together all static assets and dependent libraries into a statically linked go
binary (which you're executing right now). Use the options below to customize
the way that the kolide server works.
`,
		Run: func(cmd *cobra.Command, args []string) {
			var (
				httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
				ctx      = context.Background()
				logger   kitlog.Logger
			)
			flag.Parse()

			config := configManager.LoadConfig()

			logger = kitlog.NewLogfmtLogger(os.Stderr)
			logger = kitlog.NewContext(logger).With("ts", kitlog.DefaultTimestampUTC)

			var mailService kolide.MailService
			if devMode {
				mailService = devMailService{}
			} else {
				mailService = mail.NewService(config.SMTP)
			}

			var ds kolide.Datastore
			var err error
			if devMode {
				fmt.Println(
					"Dev mode enabled, using in-memory DB.\n",
					"Warning: Changes will not be saved across process restarts. This should NOT be used in production.",
				)
				ds, err = datastore.New("inmem", "")
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			} else {
				connString := datastore.GetMysqlConnectionString(config.Mysql)
				ds, err = datastore.New("gorm-mysql", connString)
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			}

			svc, err := service.NewService(ds, logger, config, mailService, clock.C)
			if err != nil {
				initFatal(err, "initializing service")
			}

			if devMode {
				// Bootstrap a few users when using the in-memory database.
				// Each user's default password will just be their username.
				users := []kolide.User{
					{
						Name:     "Admin User",
						Username: "admin",
						Email:    "admin@kolide.co",
						Position: "Director of Security",
						Admin:    true,
						Enabled:  true,
					},
					{
						Name:     "Normal User",
						Username: "user",
						Email:    "user@kolide.co",
						Position: "Security Engineer",
						Admin:    false,
						Enabled:  true,
					},
				}

				for _, user := range users {
					user := user
					err := user.SetPassword(user.Username, config.Auth.SaltKeySize, config.Auth.BcryptCost)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
					_, err = ds.NewUser(&user)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
				}
				devOrgInfo := &kolide.OrgInfo{
					OrgName:    "Kolide",
					OrgLogoURL: fmt.Sprintf("%s/logo.png", config.Server.Address),
				}
				_, err := svc.NewOrgInfo(ctx, kolide.OrgInfoPayload{
					OrgName:    &devOrgInfo.OrgName,
					OrgLogoURL: &devOrgInfo.OrgLogoURL,
				})
				if err != nil {
					initFatal(err, "creating fake org info")
				}
			}

			fieldKeys := []string{"method", "error"}
			requestCount := kitprometheus.NewCounterFrom(prometheus.CounterOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_count",
				Help:      "Number of requests received.",
			}, fieldKeys)
			requestLatency := kitprometheus.NewSummaryFrom(prometheus.SummaryOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_latency_microseconds",
				Help:      "Total duration of requests in microseconds.",
			}, fieldKeys)

			svcLogger := kitlog.NewContext(logger).With("component", "service")
			svc = service.NewLoggingService(svc, svcLogger)
			svc = service.NewMetricsService(svc, requestCount, requestLatency)

			httpLogger := kitlog.NewContext(logger).With("component", "http")

			apiHandler := service.MakeHandler(ctx, svc, config.Auth.JwtKey, httpLogger)
			http.Handle("/api/", apiHandler)
			http.Handle("/version", version.Handler())
			http.Handle("/metrics", prometheus.Handler())
			http.Handle("/assets/", service.ServeStaticAssets("/assets/"))
			http.Handle("/", service.ServeFrontend())

			errs := make(chan error, 2)
			go func() {
				if !config.Server.TLS || (devMode && !configManager.IsSet("server.tls")) {
					logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServe(*httpAddr, nil)
				} else {
					logger.Log("transport", "https", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServeTLS(
						*httpAddr,
						config.Server.Cert,
						config.Server.Key,
						nil,
					)
				}
			}()
			go func() {
				c := make(chan os.Signal)
				signal.Notify(c, syscall.SIGINT)
				errs <- fmt.Errorf("%s", <-c)
			}()

			logger.Log("terminated", <-errs)
		},
	}

	serveCmd.PersistentFlags().BoolVar(&devMode, "dev", false, "Use dev settings (in-mem DB, etc.)")

	return serveCmd
}

// used in devMode to print an email
// which would otherwise be sent via SMTP
type devMailService struct{}

func (devMailService) SendEmail(e kolide.Email) error {
	fmt.Println("---dev mode: printing email---")
	defer fmt.Println("---dev mode: email printed---")
	msg, err := e.Msg.Message()
	if err != nil {
		return err
	}
	fmt.Printf("From: %q To: %q \n", e.From, e.To)
	_, err = os.Stdout.Write(msg)
	return err

}
<|endoftext|>


<commit_before>// A memcached binary protocol client.
package memcached

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"sync"

	"github.com/dustin/gomemcached"
)

const bufsize = 1024

// The Client itself.
type Client struct {
	conn    io.ReadWriteCloser
	healthy bool

	hdrBuf []byte
}

// Connect to a memcached server.
func Connect(prot, dest string) (rv *Client, err error) {
	conn, err := net.Dial(prot, dest)
	if err != nil {
		return nil, err
	}
	return Wrap(conn)
}

// Wrap an existing transport.
func Wrap(rwc io.ReadWriteCloser) (rv *Client, err error) {
	return &Client{
		conn:    rwc,
		healthy: true,
		hdrBuf:  make([]byte, gomemcached.HDR_LEN),
	}, nil
}

// Close the connection when you're done.
func (c *Client) Close() {
	c.conn.Close()
}

// Return false if this client has had issues communicating.
//
// This is useful for connection pools where we want to
// non-destructively determine that a connection may be reused.
func (c Client) IsHealthy() bool {
	return c.healthy
}

// Send a custom request and get the response.
func (client *Client) Send(req *gomemcached.MCRequest) (rv *gomemcached.MCResponse, err error) {
	err = transmitRequest(client.conn, req)
	if err != nil {
		client.healthy = false
		return
	}
	resp, err := getResponse(client.conn, client.hdrBuf)
	if err != nil {
		client.healthy = false
	}
	return resp, err
}

// Send a request, but do not wait for a response.
func (client *Client) Transmit(req *gomemcached.MCRequest) error {
	err := transmitRequest(client.conn, req)
	if err != nil {
		client.healthy = false
	}
	return err
}

// Receive a response
func (client *Client) Receive() (*gomemcached.MCResponse, error) {
	resp, err := getResponse(client.conn, client.hdrBuf)
	if err != nil {
		client.healthy = false
	}
	return resp, err
}

// Get the value for a key.
func (client *Client) Get(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.GET,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

// Delete a key.
func (client *Client) Del(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.DELETE,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

// List auth mechanisms
func (client *Client) AuthList() (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.SASL_LIST_MECHS,
		VBucket: 0,
		Key:     []byte{},
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

func (client *Client) Auth(user, pass string) (*gomemcached.MCResponse, error) {
	res, err := client.AuthList()

	if err != nil {
		return res, err
	}

	authMech := string(res.Body)
	if strings.Index(authMech, "PLAIN") != -1 {
		return client.Send(&gomemcached.MCRequest{
			Opcode:  gomemcached.SASL_AUTH,
			VBucket: 0,
			Key:     []byte("PLAIN"),
			Cas:     0,
			Opaque:  0,
			Extras:  []byte{},
			Body:    []byte(fmt.Sprintf("\x00%s\x00%s", user, pass))})
	}
	return res, fmt.Errorf("Auth mechanism PLAIN not supported")
}

func (client *Client) store(opcode gomemcached.CommandCode, vb uint16,
	key string, flags int, exp int, body []byte) (*gomemcached.MCResponse, error) {

	req := &gomemcached.MCRequest{
		Opcode:  opcode,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
		Body:    body}

	binary.BigEndian.PutUint64(req.Extras, uint64(flags)<<32|uint64(exp))
	return client.Send(req)
}

// Increment a value.
func (client *Client) Incr(vb uint16, key string,
	amt, def uint64, exp int) (uint64, error) {

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.INCREMENT,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  make([]byte, 8+8+4),
		Body:    []byte{}}
	binary.BigEndian.PutUint64(req.Extras[:8], amt)
	binary.BigEndian.PutUint64(req.Extras[8:16], def)
	binary.BigEndian.PutUint32(req.Extras[16:20], uint32(exp))

	resp, err := client.Send(req)
	if err != nil {
		return 0, err
	}

	return binary.BigEndian.Uint64(resp.Body), nil
}

// Add a value for a key (store if not exists).
func (client *Client) Add(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.ADD, vb, key, flags, exp, body)
}

// Set the value for a key.
func (client *Client) Set(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.SET, vb, key, flags, exp, body)
}

// Get keys in bulk
func (client *Client) GetBulk(vb uint16, keys []string) (map[string]*gomemcached.MCResponse, error) {
	terminalOpaque := uint32(len(keys) + 5)
	rv := map[string]*gomemcached.MCResponse{}
	wg := sync.WaitGroup{}
	going := true

	defer func() {
		going = false
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for going {
			res, err := client.Receive()
			if err != nil {
				return
			}
			if res.Opaque == terminalOpaque {
				return
			}
			if res.Opcode != gomemcached.GETQ {
				log.Panicf("Unexpected opcode in GETQ response: %+v",
					res)
			}
			rv[keys[res.Opaque]] = res
		}
	}()

	for i, k := range keys {
		err := client.Transmit(&gomemcached.MCRequest{
			Opcode:  gomemcached.GETQ,
			VBucket: vb,
			Key:     []byte(k),
			Cas:     0,
			Opaque:  uint32(i),
			Extras:  []byte{},
			Body:    []byte{}})
		if err != nil {
			return rv, err
		}
	}

	err := client.Transmit(&gomemcached.MCRequest{
		Opcode: gomemcached.NOOP,
		Key:    []byte{},
		Cas:    0,
		Extras: []byte{},
		Body:   []byte{},
		Opaque: terminalOpaque})
	if err != nil {
		return rv, err
	}

	wg.Wait()

	return rv, nil
}

// Operation to perform on this CAS loop.
type CasOp uint8

const (
	// Store the new value normally
	CASStore = CasOp(iota)
	// Stop attempting to CAS, leave value untouched
	CASQuit
	// Delete the current value
	CASDelete
)

// User specified termination is returned as an error.
func (c CasOp) Error() string {
	switch c {
	case CASStore:
		return "CAS store"
	case CASQuit:
		return "CAS quit"
	case CASDelete:
		return "CAS delete"
	}
	panic("Unhandled value")
}

// A function to perform a CAS transform
type CasFunc func(current []byte) ([]byte, CasOp)

// Perform a CAS transform with the given function.
//
// If the value does not exist, an empty byte string will be sent to f
func (client *Client) CAS(vb uint16, k string, f CasFunc,
	initexp int) (rv *gomemcached.MCResponse, err error) {

	flags := 0
	exp := 0

	for {
		orig, err := client.Get(vb, k)
		if err != nil && (orig == nil || orig.Status != gomemcached.KEY_ENOENT) {
			return rv, err
		}

		if orig.Status == gomemcached.KEY_ENOENT {
			init, operation := f([]byte{})
			if operation == CASQuit || operation == CASDelete {
				return nil, operation
			}
			// If it doesn't exist, add it
			resp, err := client.Add(vb, k, 0, initexp, init)
			if err == nil && resp.Status != gomemcached.KEY_EEXISTS {
				return rv, err
			}
		} else {
			var req *gomemcached.MCRequest
			newValue, operation := f(orig.Body)

			switch operation {
			case CASQuit:
				return nil, operation
			case CASStore:
				req = &gomemcached.MCRequest{
					Opcode:  gomemcached.SET,
					VBucket: vb,
					Key:     []byte(k),
					Cas:     orig.Cas,
					Opaque:  0,
					Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
					Body:    newValue}

				binary.BigEndian.PutUint64(req.Extras,
					uint64(flags)<<32|uint64(exp))
			case CASDelete:
				req = &gomemcached.MCRequest{
					Opcode:  gomemcached.DELETE,
					VBucket: vb,
					Key:     []byte(k),
					Cas:     orig.Cas}
			}
			resp, err := client.Send(req)
			if err == nil {
				return resp, nil
			}
		}
	}
	panic("Unreachable")
}

// Stats returns a slice of these.
type StatValue struct {
	// The stat key
	Key string
	// The stat value
	Val string
}

// Get stats from the server
// use "" as the stat key for toplevel stats.
func (client *Client) Stats(key string) ([]StatValue, error) {
	rv := make([]StatValue, 0, 128)

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.STAT,
		VBucket: 0,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  918494,
		Extras:  []byte{}}

	err := transmitRequest(client.conn, req)
	if err != nil {
		return rv, err
	}

	for {
		res, err := getResponse(client.conn, client.hdrBuf)
		if err != nil {
			return rv, err
		}
		k := string(res.Key)
		if k == "" {
			break
		}
		rv = append(rv, StatValue{
			Key: k,
			Val: string(res.Body),
		})
	}

	return rv, nil
}

// Get the stats from the server as a map
func (client *Client) StatsMap(key string) (map[string]string, error) {
	rv := make(map[string]string)
	st, err := client.Stats(key)
	if err != nil {
		return rv, err
	}
	for _, sv := range st {
		rv[sv.Key] = sv.Val
	}
	return rv, nil
}
<commit_msg>CAS callback should get nil for nonexistent value<commit_after>// A memcached binary protocol client.
package memcached

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"sync"

	"github.com/dustin/gomemcached"
)

const bufsize = 1024

// The Client itself.
type Client struct {
	conn    io.ReadWriteCloser
	healthy bool

	hdrBuf []byte
}

// Connect to a memcached server.
func Connect(prot, dest string) (rv *Client, err error) {
	conn, err := net.Dial(prot, dest)
	if err != nil {
		return nil, err
	}
	return Wrap(conn)
}

// Wrap an existing transport.
func Wrap(rwc io.ReadWriteCloser) (rv *Client, err error) {
	return &Client{
		conn:    rwc,
		healthy: true,
		hdrBuf:  make([]byte, gomemcached.HDR_LEN),
	}, nil
}

// Close the connection when you're done.
func (c *Client) Close() {
	c.conn.Close()
}

// Return false if this client has had issues communicating.
//
// This is useful for connection pools where we want to
// non-destructively determine that a connection may be reused.
func (c Client) IsHealthy() bool {
	return c.healthy
}

// Send a custom request and get the response.
func (client *Client) Send(req *gomemcached.MCRequest) (rv *gomemcached.MCResponse, err error) {
	err = transmitRequest(client.conn, req)
	if err != nil {
		client.healthy = false
		return
	}
	resp, err := getResponse(client.conn, client.hdrBuf)
	if err != nil {
		client.healthy = false
	}
	return resp, err
}

// Send a request, but do not wait for a response.
func (client *Client) Transmit(req *gomemcached.MCRequest) error {
	err := transmitRequest(client.conn, req)
	if err != nil {
		client.healthy = false
	}
	return err
}

// Receive a response
func (client *Client) Receive() (*gomemcached.MCResponse, error) {
	resp, err := getResponse(client.conn, client.hdrBuf)
	if err != nil {
		client.healthy = false
	}
	return resp, err
}

// Get the value for a key.
func (client *Client) Get(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.GET,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

// Delete a key.
func (client *Client) Del(vb uint16, key string) (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.DELETE,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

// List auth mechanisms
func (client *Client) AuthList() (*gomemcached.MCResponse, error) {
	return client.Send(&gomemcached.MCRequest{
		Opcode:  gomemcached.SASL_LIST_MECHS,
		VBucket: 0,
		Key:     []byte{},
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{},
		Body:    []byte{}})
}

func (client *Client) Auth(user, pass string) (*gomemcached.MCResponse, error) {
	res, err := client.AuthList()

	if err != nil {
		return res, err
	}

	authMech := string(res.Body)
	if strings.Index(authMech, "PLAIN") != -1 {
		return client.Send(&gomemcached.MCRequest{
			Opcode:  gomemcached.SASL_AUTH,
			VBucket: 0,
			Key:     []byte("PLAIN"),
			Cas:     0,
			Opaque:  0,
			Extras:  []byte{},
			Body:    []byte(fmt.Sprintf("\x00%s\x00%s", user, pass))})
	}
	return res, fmt.Errorf("Auth mechanism PLAIN not supported")
}

func (client *Client) store(opcode gomemcached.CommandCode, vb uint16,
	key string, flags int, exp int, body []byte) (*gomemcached.MCResponse, error) {

	req := &gomemcached.MCRequest{
		Opcode:  opcode,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
		Body:    body}

	binary.BigEndian.PutUint64(req.Extras, uint64(flags)<<32|uint64(exp))
	return client.Send(req)
}

// Increment a value.
func (client *Client) Incr(vb uint16, key string,
	amt, def uint64, exp int) (uint64, error) {

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.INCREMENT,
		VBucket: vb,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  0,
		Extras:  make([]byte, 8+8+4),
		Body:    []byte{}}
	binary.BigEndian.PutUint64(req.Extras[:8], amt)
	binary.BigEndian.PutUint64(req.Extras[8:16], def)
	binary.BigEndian.PutUint32(req.Extras[16:20], uint32(exp))

	resp, err := client.Send(req)
	if err != nil {
		return 0, err
	}

	return binary.BigEndian.Uint64(resp.Body), nil
}

// Add a value for a key (store if not exists).
func (client *Client) Add(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.ADD, vb, key, flags, exp, body)
}

// Set the value for a key.
func (client *Client) Set(vb uint16, key string, flags int, exp int,
	body []byte) (*gomemcached.MCResponse, error) {
	return client.store(gomemcached.SET, vb, key, flags, exp, body)
}

// Get keys in bulk
func (client *Client) GetBulk(vb uint16, keys []string) (map[string]*gomemcached.MCResponse, error) {
	terminalOpaque := uint32(len(keys) + 5)
	rv := map[string]*gomemcached.MCResponse{}
	wg := sync.WaitGroup{}
	going := true

	defer func() {
		going = false
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for going {
			res, err := client.Receive()
			if err != nil {
				return
			}
			if res.Opaque == terminalOpaque {
				return
			}
			if res.Opcode != gomemcached.GETQ {
				log.Panicf("Unexpected opcode in GETQ response: %+v",
					res)
			}
			rv[keys[res.Opaque]] = res
		}
	}()

	for i, k := range keys {
		err := client.Transmit(&gomemcached.MCRequest{
			Opcode:  gomemcached.GETQ,
			VBucket: vb,
			Key:     []byte(k),
			Cas:     0,
			Opaque:  uint32(i),
			Extras:  []byte{},
			Body:    []byte{}})
		if err != nil {
			return rv, err
		}
	}

	err := client.Transmit(&gomemcached.MCRequest{
		Opcode: gomemcached.NOOP,
		Key:    []byte{},
		Cas:    0,
		Extras: []byte{},
		Body:   []byte{},
		Opaque: terminalOpaque})
	if err != nil {
		return rv, err
	}

	wg.Wait()

	return rv, nil
}

// Operation to perform on this CAS loop.
type CasOp uint8

const (
	// Store the new value normally
	CASStore = CasOp(iota)
	// Stop attempting to CAS, leave value untouched
	CASQuit
	// Delete the current value
	CASDelete
)

// User specified termination is returned as an error.
func (c CasOp) Error() string {
	switch c {
	case CASStore:
		return "CAS store"
	case CASQuit:
		return "CAS quit"
	case CASDelete:
		return "CAS delete"
	}
	panic("Unhandled value")
}

// A function to perform a CAS transform.
// Input is the current value, or nil if no value exists.
// The function should return the new value (if any) to set, and the store/quit/delete operation.
type CasFunc func(current []byte) ([]byte, CasOp)

// Perform a CAS transform with the given function.
//
// If the value does not exist, a nil current value will be sent to f.
func (client *Client) CAS(vb uint16, k string, f CasFunc,
	initexp int) (*gomemcached.MCResponse, error) {

	flags := 0
	exp := 0

	for {
		orig, err := client.Get(vb, k)
		if err != nil && (orig == nil || orig.Status != gomemcached.KEY_ENOENT) {
			return nil, err
		}

		if orig.Status == gomemcached.KEY_ENOENT {
			init, operation := f(nil)
			if operation == CASQuit || operation == CASDelete {
				return nil, operation
			}
			// If it doesn't exist, add it
			resp, err := client.Add(vb, k, 0, initexp, init)
			if err == nil && resp.Status != gomemcached.KEY_EEXISTS {
				return nil, err
			}
		} else {
			var req *gomemcached.MCRequest
			newValue, operation := f(orig.Body)

			switch operation {
			case CASQuit:
				return nil, operation
			case CASStore:
				req = &gomemcached.MCRequest{
					Opcode:  gomemcached.SET,
					VBucket: vb,
					Key:     []byte(k),
					Cas:     orig.Cas,
					Opaque:  0,
					Extras:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
					Body:    newValue}

				binary.BigEndian.PutUint64(req.Extras,
					uint64(flags)<<32|uint64(exp))
			case CASDelete:
				req = &gomemcached.MCRequest{
					Opcode:  gomemcached.DELETE,
					VBucket: vb,
					Key:     []byte(k),
					Cas:     orig.Cas}
			}
			resp, err := client.Send(req)
			if err == nil {
				return resp, nil
			}
		}
	}
	panic("Unreachable")
}

// Stats returns a slice of these.
type StatValue struct {
	// The stat key
	Key string
	// The stat value
	Val string
}

// Get stats from the server
// use "" as the stat key for toplevel stats.
func (client *Client) Stats(key string) ([]StatValue, error) {
	rv := make([]StatValue, 0, 128)

	req := &gomemcached.MCRequest{
		Opcode:  gomemcached.STAT,
		VBucket: 0,
		Key:     []byte(key),
		Cas:     0,
		Opaque:  918494,
		Extras:  []byte{}}

	err := transmitRequest(client.conn, req)
	if err != nil {
		return rv, err
	}

	for {
		res, err := getResponse(client.conn, client.hdrBuf)
		if err != nil {
			return rv, err
		}
		k := string(res.Key)
		if k == "" {
			break
		}
		rv = append(rv, StatValue{
			Key: k,
			Val: string(res.Body),
		})
	}

	return rv, nil
}

// Get the stats from the server as a map
func (client *Client) StatsMap(key string) (map[string]string, error) {
	rv := make(map[string]string)
	st, err := client.Stats(key)
	if err != nil {
		return rv, err
	}
	for _, sv := range st {
		rv[sv.Key] = sv.Val
	}
	return rv, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/progrium/envy/pkg/hterm"
)

func githubAuth(user, passwd string) bool {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.github.com", nil)
	req.SetBasicAuth(user, passwd)
	resp, _ := client.Do(req)
	return resp.StatusCode == 200
}

func main() {
	http.HandleFunc("/u/", func(w http.ResponseWriter, r *http.Request) {
		parts := strings.Split(r.URL.Path, "/")
		if len(parts) < 3 {
			http.NotFound(w, r)
			return
		}
		pathUser := parts[2]
		var pathEnv, sshUser string
		if len(parts) > 3 && parts[3] != "hterm" {
			if parts[3] != "-" {
				pathEnv = parts[3]
			}
			sshUser = pathUser + "+" + pathEnv
		} else {
			sshUser = pathUser
		}
		// passthrough auth for hterm. use cookie to do this right
		if !strings.Contains(r.URL.Path, "hterm") {
			user, passwd, ok := r.BasicAuth()
			if !ok || user != pathUser || !githubAuth(user, passwd) {
				w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", pathUser))
				http.Error(w, "Unauthorized", http.StatusUnauthorized)
				return
			}
		}
		w.Header().Set("Hterm-Title", "Envy Term")
		hterm.Handle(w, r, func(args string) *hterm.Pty {
			cmd := exec.Command("/bin/enterenv", parts[2])
			cmd.Env = os.Environ()
			cmd.Env = append(cmd.Env, fmt.Sprintf("USER=%s", sshUser))
			pty, err := hterm.NewPty(cmd)
			if err != nil {
				log.Fatal(err)
			}
			return pty
		})
	})
	log.Fatal(http.ListenAndServe(":80", nil))
}
<commit_msg>Support for http://envy.host/gh/user/project<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/progrium/envy/pkg/hterm"
)

func githubAuth(user, passwd string) bool {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.github.com", nil)
	req.SetBasicAuth(user, passwd)
	resp, _ := client.Do(req)
	return resp.StatusCode == 200
}

func main() {
	http.HandleFunc("/u/", func(w http.ResponseWriter, r *http.Request) {
		parts := strings.Split(r.URL.Path, "/")
		if len(parts) < 3 {
			http.NotFound(w, r)
			return
		}
		pathUser := parts[2]
		var pathEnv, sshUser string
		if len(parts) > 3 && parts[3] != "hterm" {
			if parts[3] != "-" {
				pathEnv = parts[3]
			}
			sshUser = pathUser + "+" + pathEnv
		} else {
			sshUser = pathUser
		}
		// passthrough auth for hterm. use cookie to do this right
		if !strings.Contains(r.URL.Path, "hterm") {
			user, passwd, ok := r.BasicAuth()
			if !ok || user != pathUser || !githubAuth(user, passwd) {
				w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", pathUser))
				http.Error(w, "Unauthorized", http.StatusUnauthorized)
				return
			}
		}
		w.Header().Set("Hterm-Title", "Envy Term")
		hterm.Handle(w, r, func(args string) *hterm.Pty {
			cmd := exec.Command("/bin/enterenv", parts[2])
			cmd.Env = os.Environ()
			cmd.Env = append(cmd.Env, fmt.Sprintf("USER=%s", sshUser))
			pty, err := hterm.NewPty(cmd)
			if err != nil {
				log.Fatal(err)
			}
			return pty
		})
	})
	http.HandleFunc("/gh/", func(w http.ResponseWriter, r *http.Request) {
		user, passwd, ok := r.BasicAuth()
		if !ok || !githubAuth(user, passwd) {
			w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=\"%s\"", user))
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		parts := strings.Split(r.URL.Path, "/")
		if len(parts) < 4 {
			http.NotFound(w, r)
			return
		}
		sshUser := user + "+github.com/" + parts[2] + "/" + parts[3]
		w.Header().Set("Hterm-Title", "Envy Term")
		hterm.Handle(w, r, func(args string) *hterm.Pty {
			cmd := exec.Command("/bin/enterenv", parts[2])
			cmd.Env = os.Environ()
			cmd.Env = append(cmd.Env, fmt.Sprintf("USER=%s", sshUser))
			pty, err := hterm.NewPty(cmd)
			if err != nil {
				log.Fatal(err)
			}
			return pty
		})
	})
	log.Fatal(http.ListenAndServe(":80", nil))
}
<|endoftext|>