<commit_before>package server

import (
	"os"
	"sync"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/router"
	"github.com/micro/go-micro/server"
	"github.com/micro/go-micro/transport"
	"github.com/micro/go-micro/transport/grpc"
	"github.com/micro/go-micro/util/log"
)

var (
	// Name of the server
	Name = "go.micro.server"
	// Address to bind to
	Address = ":8083"
	// Network address to bind to
	Network = ":9093"
	// Router address to bind to
	Router = ":9094"
)

type srv struct {
	exit    chan struct{}
	service micro.Service
	router  router.Router
	network server.Server
	wg      *sync.WaitGroup
}

func newServer(s micro.Service, r router.Router) *srv {
	// NOTE: this will end up being QUIC transport
	t := grpc.NewTransport(transport.Addrs(Network))
	n := server.NewServer(server.Transport(t))

	return &srv{
		exit:    make(chan struct{}),
		service: s,
		router:  r,
		network: n,
		wg:      &sync.WaitGroup{},
	}
}

func (s *srv) start() error {
	log.Log("[server] starting")

	s.wg.Add(1)
	go s.watch()

	return nil
}

func (s *srv) watch() {
	log.Logf("[server] starting local registry watcher")

	defer s.wg.Done()
	w, err := s.service.Client().Options().Registry.Watch()
	if err != nil {
		log.Logf("[server] failed to create registry watch: %v", err)
		return
	}

	s.wg.Add(1)
	go func() {
		defer s.wg.Done()
		<-s.exit
		log.Logf("[server] stopping local registry watcher")
		w.Stop()
	}()

	// watch for changes to services
	for {
		res, err := w.Next()
		if err == registry.ErrWatcherStopped {
			log.Logf("[server] watcher stopped")
			return
		}

		if err != nil {
			log.Logf("[server] error watching registry: %s", err)
			return
		}

		switch res.Action {
		case "create":
			if len(res.Service.Nodes) > 0 {
				log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name)
			}
		case "delete":
			log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name)
		}
	}
}

func (s *srv) stop() error {
	log.Log("[server] stopping")

	// notify all goroutines to finish
	close(s.exit)

	// wait for all goroutines to finish
	s.wg.Wait()

	return nil
}

func run(ctx *cli.Context, srvOpts ...micro.Option) {
	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("network")) > 0 {
		Network = ctx.String("network")
	}
	if len(ctx.String("router")) > 0 {
		Router = ctx.String("router")
	}

	// Initialise service
	service := micro.NewService(
		micro.Name(Name),
		micro.Address(Address),
		micro.RegisterTTL(time.Duration(ctx.GlobalInt("register_ttl"))*time.Second),
		micro.RegisterInterval(time.Duration(ctx.GlobalInt("register_interval"))*time.Second),
	)

	// create new router
	r := router.NewRouter(
		router.Address(Router),
		router.Network(Network),
	)

	// create new server and start it
	s := newServer(service, r)

	if err := s.start(); err != nil {
		log.Logf("error starting server: %v", err)
		os.Exit(1)
	}

	// Run service
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	// stop the server
	if err := s.stop(); err != nil {
		log.Logf("error stopping server: %v", err)
		os.Exit(1)
	}
}

func Commands(options ...micro.Option) []cli.Command {
	command := cli.Command{
		Name:  "server",
		Usage: "Run the micro network server",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the micro server address :8083",
				EnvVar: "MICRO_SERVER_ADDRESS",
			},
			cli.StringFlag{
				Name:   "network",
				Usage:  "Set the micro network address :9093",
				EnvVar: "MICRO_NETWORK_ADDRESS",
			},
			cli.StringFlag{
				Name:   "router",
				Usage:  "Set the micro router address :9094",
				EnvVar: "MICRO_ROUTER_ADDRESS",
			},
		},
		Action: func(ctx *cli.Context) {
			run(ctx, options...)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<commit_msg>Added better logging statements.<commit_after>package server

import (
	"os"
	"sync"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/router"
	"github.com/micro/go-micro/server"
	"github.com/micro/go-micro/transport"
	"github.com/micro/go-micro/transport/grpc"
	"github.com/micro/go-micro/util/log"
)

var (
	// Name of the server
	Name = "go.micro.server"
	// Address to bind to
	Address = ":8083"
	// Network address to bind to
	Network = ":9093"
	// Router address to bind to
	Router = ":9094"
)

type srv struct {
	exit    chan struct{}
	service micro.Service
	router  router.Router
	network server.Server
	wg      *sync.WaitGroup
}

func newServer(s micro.Service, r router.Router) *srv {
	// NOTE: this will end up being QUIC transport
	t := grpc.NewTransport(transport.Addrs(Network))
	n := server.NewServer(server.Transport(t))

	return &srv{
		exit:    make(chan struct{}),
		service: s,
		router:  r,
		network: n,
		wg:      &sync.WaitGroup{},
	}
}

func (s *srv) start() error {
	log.Log("[server] starting")

	s.wg.Add(1)
	go s.watch()

	return nil
}

func (s *srv) watch() {
	log.Logf("[server] starting local registry watcher")

	defer s.wg.Done()
	w, err := s.service.Client().Options().Registry.Watch()
	if err != nil {
		log.Logf("[server] failed to create registry watch: %v", err)
		return
	}

	s.wg.Add(1)
	go func() {
		defer s.wg.Done()
		<-s.exit
		log.Logf("[server] stopping local registry watcher")
		w.Stop()
	}()

	// watch for changes to services
	for {
		res, err := w.Next()
		if err == registry.ErrWatcherStopped {
			log.Logf("[server] registry watcher stopped")
			return
		}

		if err != nil {
			log.Logf("[server] error watching registry: %s", err)
			return
		}

		switch res.Action {
		case "create":
			if len(res.Service.Nodes) > 0 {
				log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name)
			}
		case "delete":
			log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name)
		}
	}
}

func (s *srv) stop() error {
	log.Log("[server] attempting to stop")

	// notify all goroutines to finish
	close(s.exit)

	// wait for all goroutines to finish
	s.wg.Wait()

	return nil
}

func run(ctx *cli.Context, srvOpts ...micro.Option) {
	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("network")) > 0 {
		Network = ctx.String("network")
	}
	if len(ctx.String("router")) > 0 {
		Router = ctx.String("router")
	}

	// Initialise service
	service := micro.NewService(
		micro.Name(Name),
		micro.Address(Address),
		micro.RegisterTTL(time.Duration(ctx.GlobalInt("register_ttl"))*time.Second),
		micro.RegisterInterval(time.Duration(ctx.GlobalInt("register_interval"))*time.Second),
	)

	// create new router
	r := router.NewRouter(
		router.Address(Router),
		router.Network(Network),
	)

	// create new server and start it
	s := newServer(service, r)

	if err := s.start(); err != nil {
		log.Logf("error starting server: %v", err)
		os.Exit(1)
	}

	// Run service
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	// stop the server
	if err := s.stop(); err != nil {
		log.Logf("error stopping server: %v", err)
		os.Exit(1)
	}

	log.Logf("[server] successfully stopped")
}

func Commands(options ...micro.Option) []cli.Command {
	command := cli.Command{
		Name:  "server",
		Usage: "Run the micro network server",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the micro server address :8083",
				EnvVar: "MICRO_SERVER_ADDRESS",
			},
			cli.StringFlag{
				Name:   "network",
				Usage:  "Set the micro network address :9093",
				EnvVar: "MICRO_NETWORK_ADDRESS",
			},
			cli.StringFlag{
				Name:   "router",
				Usage:  "Set the micro router address :9094",
				EnvVar: "MICRO_ROUTER_ADDRESS",
			},
		},
		Action: func(ctx *cli.Context) {
			run(ctx, options...)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/codegangsta/martini-contrib/binding"
	"github.com/codegangsta/martini-contrib/cors"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/go-martini/martini"
	goauth2 "github.com/golang/oauth2"
	"github.com/martini-contrib/oauth2"
	"github.com/martini-contrib/sessions"
	"github.com/rolandjudd/thingstodo/config"
	"github.com/rolandjudd/thingstodo/controllers"
	"github.com/rolandjudd/thingstodo/db"
	"github.com/rolandjudd/thingstodo/models"
)

func NewServer(databaseName string) *martini.ClassicMartini {

	m := martini.Classic()
	c := config.GetConfig()

	// Setup middleware
	m.Use(db.DB(databaseName))
	m.Use(render.Renderer())
	m.Use(cors.Allow(&cors.Options{
		AllowOrigins:     []string{"http://localhost*"},
		AllowMethods:     []string{"POST", "GET"},
		AllowHeaders:     []string{"Origin"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
	}))

	// Google OAuth
	m.Use(sessions.Sessions("my_session", sessions.NewCookieStore([]byte(c.Cookie_Auth),
		[]byte(c.Cookie_Enc))))

	m.Use(oauth2.Google(
		goauth2.Client(c.Client_Id, c.Client_Secret),
		goauth2.RedirectURL(c.OAuth_Callback),
		goauth2.Scope("profile"),
	))

	// Static Assets
	m.Use(martini.Static("frontend/dist"))

	// Setup event routes
	m.Get(`/events`, controllers.GetAllEvents)
	m.Get(`/events/:id`, controllers.GetEvent)
	m.Post(`/events`, oauth2.LoginRequired, binding.Json(models.Event{}), binding.ErrorHandler, controllers.AddEvent)

	// Setup comment routes
	m.Get(`/events/:event_id/comments`, controllers.GetAllComments)
	m.Post(`/events/:event_id/comments`, binding.Json(models.Comment{}), binding.ErrorHandler, controllers.AddComment)

	// TODO Update, Delete for events
	//m.Put(`/events/:id`, UpdateEvent)
	//m.Delete(`/events/:id`, DeleteEvent)

	// Add the router action

	return m
}
<commit_msg>Add route for OAuth2 testing<commit_after>package server

import (
	"github.com/codegangsta/martini-contrib/binding"
	"github.com/codegangsta/martini-contrib/cors"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/go-martini/martini"
	goauth2 "github.com/golang/oauth2"
	"github.com/martini-contrib/oauth2"
	"github.com/martini-contrib/sessions"
	"github.com/rolandjudd/thingstodo/config"
	"github.com/rolandjudd/thingstodo/controllers"
	"github.com/rolandjudd/thingstodo/db"
	"github.com/rolandjudd/thingstodo/models"
)

func NewServer(databaseName string) *martini.ClassicMartini {

	m := martini.Classic()
	c := config.GetConfig()

	// Setup middleware
	m.Use(db.DB(databaseName))
	m.Use(render.Renderer())
	m.Use(cors.Allow(&cors.Options{
		AllowOrigins:     []string{"http://localhost*"},
		AllowMethods:     []string{"POST", "GET"},
		AllowHeaders:     []string{"Origin"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
	}))

	// Google OAuth
	m.Use(sessions.Sessions("my_session", sessions.NewCookieStore([]byte(c.Cookie_Auth),
		[]byte(c.Cookie_Enc))))

	m.Use(oauth2.Google(
		goauth2.Client(c.Client_Id, c.Client_Secret),
		goauth2.RedirectURL(c.OAuth_Callback),
		goauth2.Scope("profile"),
	))

	// Static Assets
	m.Use(martini.Static("frontend/dist"))

	// Setup event routes
	m.Get(`/events`, controllers.GetAllEvents)
	m.Get(`/events/:id`, controllers.GetEvent)
	m.Post(`/events`, oauth2.LoginRequired, binding.Json(models.Event{}), binding.ErrorHandler, controllers.AddEvent)

	// Setup comment routes
	m.Get(`/events/:event_id/comments`, controllers.GetAllComments)
	m.Post(`/events/:event_id/comments`, binding.Json(models.Comment{}), binding.ErrorHandler, controllers.AddComment)

	// Temporary route for oauth testing
	m.Get("/users", oauth2.LoginRequired, func(tokens oauth2.Tokens) string {
		return tokens.Access()
	})

	// TODO Update, Delete for events
	//m.Put(`/events/:id`, UpdateEvent)
	//m.Delete(`/events/:id`, DeleteEvent)

	// Add the router action

	return m
}
<|endoftext|>


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

// This implements the write barrier buffer. The write barrier itself
// is gcWriteBarrier and is implemented in assembly.
//
// See mbarrier.go for algorithmic details on the write barrier. This
// file deals only with the buffer.
//
// The write barrier has a fast path and a slow path. The fast path
// simply enqueues to a per-P write barrier buffer. It's written in
// assembly and doesn't clobber any general purpose registers, so it
// doesn't have the usual overheads of a Go call.
//
// When the buffer fills up, the write barrier invokes the slow path
// (wbBufFlush) to flush the buffer to the GC work queues. In this
// path, since the compiler didn't spill registers, we spill *all*
// registers and disallow any GC safe points that could observe the
// stack frame (since we don't know the types of the spilled
// registers).

package runtime

import (
	"runtime/internal/atomic"
	"runtime/internal/sys"
	"unsafe"
)

// testSmallBuf forces a small write barrier buffer to stress write
// barrier flushing.
const testSmallBuf = false

// wbBuf is a per-P buffer of pointers queued by the write barrier.
// This buffer is flushed to the GC workbufs when it fills up and on
// various GC transitions.
//
// This is closely related to a "sequential store buffer" (SSB),
// except that SSBs are usually used for maintaining remembered sets,
// while this is used for marking.
type wbBuf struct {
	// next points to the next slot in buf. It must not be a
	// pointer type because it can point past the end of buf and
	// must be updated without write barriers.
	//
	// This is a pointer rather than an index to optimize the
	// write barrier assembly.
	next uintptr

	// end points to just past the end of buf. It must not be a
	// pointer type because it points past the end of buf and must
	// be updated without write barriers.
	end uintptr

	// buf stores a series of pointers to execute write barriers
	// on. This must be a multiple of wbBufEntryPointers because
	// the write barrier only checks for overflow once per entry.
	buf [wbBufEntryPointers * wbBufEntries]uintptr

	// debugGen causes the write barrier buffer to flush after
	// every write barrier if equal to gcWorkPauseGen. This is for
	// debugging #27993. This is only set if debugCachedWork is
	// set.
	debugGen uint32
}

const (
	// wbBufEntries is the number of write barriers between
	// flushes of the write barrier buffer.
	//
	// This trades latency for throughput amortization. Higher
	// values amortize flushing overhead more, but increase the
	// latency of flushing. Higher values also increase the cache
	// footprint of the buffer.
	//
	// TODO: What is the latency cost of this? Tune this value.
	wbBufEntries = 256

	// wbBufEntryPointers is the number of pointers added to the
	// buffer by each write barrier.
	wbBufEntryPointers = 2
)

// reset empties b by resetting its next and end pointers.
func (b *wbBuf) reset() {
	start := uintptr(unsafe.Pointer(&b.buf[0]))
	b.next = start
	if writeBarrier.cgo || (debugCachedWork && (throwOnGCWork || b.debugGen == atomic.Load(&gcWorkPauseGen))) {
		// Effectively disable the buffer by forcing a flush
		// on every barrier.
		b.end = uintptr(unsafe.Pointer(&b.buf[wbBufEntryPointers]))
	} else if testSmallBuf {
		// For testing, allow two barriers in the buffer. If
		// we only did one, then barriers of non-heap pointers
		// would be no-ops. This lets us combine a buffered
		// barrier with a flush at a later time.
		b.end = uintptr(unsafe.Pointer(&b.buf[2*wbBufEntryPointers]))
	} else {
		b.end = start + uintptr(len(b.buf))*unsafe.Sizeof(b.buf[0])
	}

	if (b.end-b.next)%(wbBufEntryPointers*unsafe.Sizeof(b.buf[0])) != 0 {
		throw("bad write barrier buffer bounds")
	}
}

// discard resets b's next pointer, but not its end pointer.
//
// This must be nosplit because it's called by wbBufFlush.
//
//go:nosplit
func (b *wbBuf) discard() {
	b.next = uintptr(unsafe.Pointer(&b.buf[0]))
}

// empty reports whether b contains no pointers.
func (b *wbBuf) empty() bool {
	return b.next == uintptr(unsafe.Pointer(&b.buf[0]))
}

// putFast adds old and new to the write barrier buffer and returns
// false if a flush is necessary. Callers should use this as:
//
//     buf := &getg().m.p.ptr().wbBuf
//     if !buf.putFast(old, new) {
//         wbBufFlush(...)
//     }
//     ... actual memory write ...
//
// The arguments to wbBufFlush depend on whether the caller is doing
// its own cgo pointer checks. If it is, then this can be
// wbBufFlush(nil, 0). Otherwise, it must pass the slot address and
// new.
//
// The caller must ensure there are no preemption points during the
// above sequence. There must be no preemption points while buf is in
// use because it is a per-P resource. There must be no preemption
// points between the buffer put and the write to memory because this
// could allow a GC phase change, which could result in missed write
// barriers.
//
// putFast must be nowritebarrierrec to because write barriers here would
// corrupt the write barrier buffer. It (and everything it calls, if
// it called anything) has to be nosplit to avoid scheduling on to a
// different P and a different buffer.
//
//go:nowritebarrierrec
//go:nosplit
func (b *wbBuf) putFast(old, new uintptr) bool {
	p := (*[2]uintptr)(unsafe.Pointer(b.next))
	p[0] = old
	p[1] = new
	b.next += 2 * sys.PtrSize
	return b.next != b.end
}

// wbBufFlush flushes the current P's write barrier buffer to the GC
// workbufs. It is passed the slot and value of the write barrier that
// caused the flush so that it can implement cgocheck.
//
// This must not have write barriers because it is part of the write
// barrier implementation.
//
// This and everything it calls must be nosplit because 1) the stack
// contains untyped slots from gcWriteBarrier and 2) there must not be
// a GC safe point between the write barrier test in the caller and
// flushing the buffer.
//
// TODO: A "go:nosplitrec" annotation would be perfect for this.
//
//go:nowritebarrierrec
//go:nosplit
func wbBufFlush(dst *uintptr, src uintptr) {
	// Note: Every possible return from this function must reset
	// the buffer's next pointer to prevent buffer overflow.

	// This *must not* modify its arguments because this
	// function's argument slots do double duty in gcWriteBarrier
	// as register spill slots. Currently, not modifying the
	// arguments is sufficient to keep the spill slots unmodified
	// (which seems unlikely to change since it costs little and
	// helps with debugging).

	if getg().m.dying > 0 {
		// We're going down. Not much point in write barriers
		// and this way we can allow write barriers in the
		// panic path.
		getg().m.p.ptr().wbBuf.discard()
		return
	}

	if writeBarrier.cgo && dst != nil {
		// This must be called from the stack that did the
		// write. It's nosplit all the way down.
		cgoCheckWriteBarrier(dst, src)
		if !writeBarrier.needed {
			// We were only called for cgocheck.
			getg().m.p.ptr().wbBuf.discard()
			return
		}
	}

	// Switch to the system stack so we don't have to worry about
	// the untyped stack slots or safe points.
	systemstack(func() {
		if debugCachedWork {
			// For debugging, include the old value of the
			// slot and some other data in the traceback.
			wbBuf := &getg().m.p.ptr().wbBuf
			var old uintptr
			if dst != nil {
				// dst may be nil in direct calls to wbBufFlush.
				old = *dst
			}
			wbBufFlush1Debug(old, wbBuf.buf[0], wbBuf.buf[1], &wbBuf.buf[0], wbBuf.next)
		} else {
			wbBufFlush1(getg().m.p.ptr())
		}
	})
}

// wbBufFlush1Debug is a temporary function for debugging issue
// #27993. It exists solely to add some context to the traceback.
//
//go:nowritebarrierrec
//go:systemstack
//go:noinline
func wbBufFlush1Debug(old, buf1, buf2 uintptr, start *uintptr, next uintptr) {
	wbBufFlush1(getg().m.p.ptr())
}

// wbBufFlush1 flushes p's write barrier buffer to the GC work queue.
//
// This must not have write barriers because it is part of the write
// barrier implementation, so this may lead to infinite loops or
// buffer corruption.
//
// This must be non-preemptible because it uses the P's workbuf.
//
//go:nowritebarrierrec
//go:systemstack
func wbBufFlush1(_p_ *p) {
	// Get the buffered pointers.
	start := uintptr(unsafe.Pointer(&_p_.wbBuf.buf[0]))
	n := (_p_.wbBuf.next - start) / unsafe.Sizeof(_p_.wbBuf.buf[0])
	ptrs := _p_.wbBuf.buf[:n]

	// Poison the buffer to make extra sure nothing is enqueued
	// while we're processing the buffer.
	_p_.wbBuf.next = 0

	if useCheckmark {
		// Slow path for checkmark mode.
		for _, ptr := range ptrs {
			shade(ptr)
		}
		_p_.wbBuf.reset()
		return
	}

	// Mark all of the pointers in the buffer and record only the
	// pointers we greyed. We use the buffer itself to temporarily
	// record greyed pointers.
	//
	// TODO: Should scanobject/scanblock just stuff pointers into
	// the wbBuf? Then this would become the sole greying path.
	//
	// TODO: We could avoid shading any of the "new" pointers in
	// the buffer if the stack has been shaded, or even avoid
	// putting them in the buffer at all (which would double its
	// capacity). This is slightly complicated with the buffer; we
	// could track whether any un-shaded goroutine has used the
	// buffer, or just track globally whether there are any
	// un-shaded stacks and flush after each stack scan.
	gcw := &_p_.gcw
	pos := 0
	for _, ptr := range ptrs {
		if ptr < minLegalPointer {
			// nil pointers are very common, especially
			// for the "old" values. Filter out these and
			// other "obvious" non-heap pointers ASAP.
			//
			// TODO: Should we filter out nils in the fast
			// path to reduce the rate of flushes?
			continue
		}
		obj, span, objIndex := findObject(ptr, 0, 0, false)
		if obj == 0 {
			continue
		}
		// TODO: Consider making two passes where the first
		// just prefetches the mark bits.
		mbits := span.markBitsForIndex(objIndex)
		if mbits.isMarked() {
			continue
		}
		mbits.setMarked()
		if span.spanclass.noscan() {
			gcw.bytesMarked += uint64(span.elemsize)
			continue
		}
		ptrs[pos] = obj
		pos++
	}

	// Enqueue the greyed objects.
	gcw.putBatch(ptrs[:pos])

	_p_.wbBuf.reset()
}
<commit_msg>runtime: scan write barrier buffer conservatively<commit_after>// Copyright 2017 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.

// This implements the write barrier buffer. The write barrier itself
// is gcWriteBarrier and is implemented in assembly.
//
// See mbarrier.go for algorithmic details on the write barrier. This
// file deals only with the buffer.
//
// The write barrier has a fast path and a slow path. The fast path
// simply enqueues to a per-P write barrier buffer. It's written in
// assembly and doesn't clobber any general purpose registers, so it
// doesn't have the usual overheads of a Go call.
//
// When the buffer fills up, the write barrier invokes the slow path
// (wbBufFlush) to flush the buffer to the GC work queues. In this
// path, since the compiler didn't spill registers, we spill *all*
// registers and disallow any GC safe points that could observe the
// stack frame (since we don't know the types of the spilled
// registers).

package runtime

import (
	"runtime/internal/atomic"
	"runtime/internal/sys"
	"unsafe"
)

// testSmallBuf forces a small write barrier buffer to stress write
// barrier flushing.
const testSmallBuf = false

// wbBuf is a per-P buffer of pointers queued by the write barrier.
// This buffer is flushed to the GC workbufs when it fills up and on
// various GC transitions.
//
// This is closely related to a "sequential store buffer" (SSB),
// except that SSBs are usually used for maintaining remembered sets,
// while this is used for marking.
type wbBuf struct {
	// next points to the next slot in buf. It must not be a
	// pointer type because it can point past the end of buf and
	// must be updated without write barriers.
	//
	// This is a pointer rather than an index to optimize the
	// write barrier assembly.
	next uintptr

	// end points to just past the end of buf. It must not be a
	// pointer type because it points past the end of buf and must
	// be updated without write barriers.
	end uintptr

	// buf stores a series of pointers to execute write barriers
	// on. This must be a multiple of wbBufEntryPointers because
	// the write barrier only checks for overflow once per entry.
	buf [wbBufEntryPointers * wbBufEntries]uintptr

	// debugGen causes the write barrier buffer to flush after
	// every write barrier if equal to gcWorkPauseGen. This is for
	// debugging #27993. This is only set if debugCachedWork is
	// set.
	debugGen uint32
}

const (
	// wbBufEntries is the number of write barriers between
	// flushes of the write barrier buffer.
	//
	// This trades latency for throughput amortization. Higher
	// values amortize flushing overhead more, but increase the
	// latency of flushing. Higher values also increase the cache
	// footprint of the buffer.
	//
	// TODO: What is the latency cost of this? Tune this value.
	wbBufEntries = 256

	// wbBufEntryPointers is the number of pointers added to the
	// buffer by each write barrier.
	wbBufEntryPointers = 2
)

// reset empties b by resetting its next and end pointers.
func (b *wbBuf) reset() {
	start := uintptr(unsafe.Pointer(&b.buf[0]))
	b.next = start
	if writeBarrier.cgo || (debugCachedWork && (throwOnGCWork || b.debugGen == atomic.Load(&gcWorkPauseGen))) {
		// Effectively disable the buffer by forcing a flush
		// on every barrier.
		b.end = uintptr(unsafe.Pointer(&b.buf[wbBufEntryPointers]))
	} else if testSmallBuf {
		// For testing, allow two barriers in the buffer. If
		// we only did one, then barriers of non-heap pointers
		// would be no-ops. This lets us combine a buffered
		// barrier with a flush at a later time.
		b.end = uintptr(unsafe.Pointer(&b.buf[2*wbBufEntryPointers]))
	} else {
		b.end = start + uintptr(len(b.buf))*unsafe.Sizeof(b.buf[0])
	}

	if (b.end-b.next)%(wbBufEntryPointers*unsafe.Sizeof(b.buf[0])) != 0 {
		throw("bad write barrier buffer bounds")
	}
}

// discard resets b's next pointer, but not its end pointer.
//
// This must be nosplit because it's called by wbBufFlush.
//
//go:nosplit
func (b *wbBuf) discard() {
	b.next = uintptr(unsafe.Pointer(&b.buf[0]))
}

// empty reports whether b contains no pointers.
func (b *wbBuf) empty() bool {
	return b.next == uintptr(unsafe.Pointer(&b.buf[0]))
}

// putFast adds old and new to the write barrier buffer and returns
// false if a flush is necessary. Callers should use this as:
//
//     buf := &getg().m.p.ptr().wbBuf
//     if !buf.putFast(old, new) {
//         wbBufFlush(...)
//     }
//     ... actual memory write ...
//
// The arguments to wbBufFlush depend on whether the caller is doing
// its own cgo pointer checks. If it is, then this can be
// wbBufFlush(nil, 0). Otherwise, it must pass the slot address and
// new.
//
// The caller must ensure there are no preemption points during the
// above sequence. There must be no preemption points while buf is in
// use because it is a per-P resource. There must be no preemption
// points between the buffer put and the write to memory because this
// could allow a GC phase change, which could result in missed write
// barriers.
//
// putFast must be nowritebarrierrec to because write barriers here would
// corrupt the write barrier buffer. It (and everything it calls, if
// it called anything) has to be nosplit to avoid scheduling on to a
// different P and a different buffer.
//
//go:nowritebarrierrec
//go:nosplit
func (b *wbBuf) putFast(old, new uintptr) bool {
	p := (*[2]uintptr)(unsafe.Pointer(b.next))
	p[0] = old
	p[1] = new
	b.next += 2 * sys.PtrSize
	return b.next != b.end
}

// wbBufFlush flushes the current P's write barrier buffer to the GC
// workbufs. It is passed the slot and value of the write barrier that
// caused the flush so that it can implement cgocheck.
//
// This must not have write barriers because it is part of the write
// barrier implementation.
//
// This and everything it calls must be nosplit because 1) the stack
// contains untyped slots from gcWriteBarrier and 2) there must not be
// a GC safe point between the write barrier test in the caller and
// flushing the buffer.
//
// TODO: A "go:nosplitrec" annotation would be perfect for this.
//
//go:nowritebarrierrec
//go:nosplit
func wbBufFlush(dst *uintptr, src uintptr) {
	// Note: Every possible return from this function must reset
	// the buffer's next pointer to prevent buffer overflow.

	// This *must not* modify its arguments because this
	// function's argument slots do double duty in gcWriteBarrier
	// as register spill slots. Currently, not modifying the
	// arguments is sufficient to keep the spill slots unmodified
	// (which seems unlikely to change since it costs little and
	// helps with debugging).

	if getg().m.dying > 0 {
		// We're going down. Not much point in write barriers
		// and this way we can allow write barriers in the
		// panic path.
		getg().m.p.ptr().wbBuf.discard()
		return
	}

	if writeBarrier.cgo && dst != nil {
		// This must be called from the stack that did the
		// write. It's nosplit all the way down.
		cgoCheckWriteBarrier(dst, src)
		if !writeBarrier.needed {
			// We were only called for cgocheck.
			getg().m.p.ptr().wbBuf.discard()
			return
		}
	}

	// Switch to the system stack so we don't have to worry about
	// the untyped stack slots or safe points.
	systemstack(func() {
		if debugCachedWork {
			// For debugging, include the old value of the
			// slot and some other data in the traceback.
			wbBuf := &getg().m.p.ptr().wbBuf
			var old uintptr
			if dst != nil {
				// dst may be nil in direct calls to wbBufFlush.
				old = *dst
			}
			wbBufFlush1Debug(old, wbBuf.buf[0], wbBuf.buf[1], &wbBuf.buf[0], wbBuf.next)
		} else {
			wbBufFlush1(getg().m.p.ptr())
		}
	})
}

// wbBufFlush1Debug is a temporary function for debugging issue
// #27993. It exists solely to add some context to the traceback.
//
//go:nowritebarrierrec
//go:systemstack
//go:noinline
func wbBufFlush1Debug(old, buf1, buf2 uintptr, start *uintptr, next uintptr) {
	wbBufFlush1(getg().m.p.ptr())
}

// wbBufFlush1 flushes p's write barrier buffer to the GC work queue.
//
// This must not have write barriers because it is part of the write
// barrier implementation, so this may lead to infinite loops or
// buffer corruption.
//
// This must be non-preemptible because it uses the P's workbuf.
//
//go:nowritebarrierrec
//go:systemstack
func wbBufFlush1(_p_ *p) {
	// Get the buffered pointers.
	start := uintptr(unsafe.Pointer(&_p_.wbBuf.buf[0]))
	n := (_p_.wbBuf.next - start) / unsafe.Sizeof(_p_.wbBuf.buf[0])
	ptrs := _p_.wbBuf.buf[:n]

	// Poison the buffer to make extra sure nothing is enqueued
	// while we're processing the buffer.
	_p_.wbBuf.next = 0

	if useCheckmark {
		// Slow path for checkmark mode.
		for _, ptr := range ptrs {
			shade(ptr)
		}
		_p_.wbBuf.reset()
		return
	}

	// Mark all of the pointers in the buffer and record only the
	// pointers we greyed. We use the buffer itself to temporarily
	// record greyed pointers.
	//
	// TODO: Should scanobject/scanblock just stuff pointers into
	// the wbBuf? Then this would become the sole greying path.
	//
	// TODO: We could avoid shading any of the "new" pointers in
	// the buffer if the stack has been shaded, or even avoid
	// putting them in the buffer at all (which would double its
	// capacity). This is slightly complicated with the buffer; we
	// could track whether any un-shaded goroutine has used the
	// buffer, or just track globally whether there are any
	// un-shaded stacks and flush after each stack scan.
	gcw := &_p_.gcw
	pos := 0
	for _, ptr := range ptrs {
		if ptr < minLegalPointer {
			// nil pointers are very common, especially
			// for the "old" values. Filter out these and
			// other "obvious" non-heap pointers ASAP.
			//
			// TODO: Should we filter out nils in the fast
			// path to reduce the rate of flushes?
			continue
		}
		obj, span, objIndex := findObject(ptr, 0, 0, !usestackmaps)
		if obj == 0 {
			continue
		}
		if span.isFree(objIndex) {
			// For gccgo, it is possible that we have a write barrier
			// writing to unintialized stack memory. So we could see
			// a bad pointer in the write barrier buffer. Don't mark
			// it in this case.
			continue
		}
		// TODO: Consider making two passes where the first
		// just prefetches the mark bits.
		mbits := span.markBitsForIndex(objIndex)
		if mbits.isMarked() {
			continue
		}
		mbits.setMarked()
		if span.spanclass.noscan() {
			gcw.bytesMarked += uint64(span.elemsize)
			continue
		}
		ptrs[pos] = obj
		pos++
	}

	// Enqueue the greyed objects.
	gcw.putBatch(ptrs[:pos])

	_p_.wbBuf.reset()
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"net"
	"net/http"

	"github.com/juju/errors"
	"github.com/peer-calls/peer-calls/server/multierr"
)

type Params struct {
	TLSCertFile string
	TLSKeyFile  string
}

type Server struct {
	server *http.Server
	params Params
}

func New(params Params, handler http.Handler) *Server {
	server := &http.Server{
		Handler: handler,
	}
	return &Server{
		server: server,
		params: params,
	}
}

func (s Server) Start(ctx context.Context, l net.Listener) (err error) {
	startErrCh := make(chan error, 1)

	go func() {
		defer close(startErrCh)

		if s.params.TLSCertFile != "" {
			err = s.server.ServeTLS(l, s.params.TLSCertFile, s.params.TLSKeyFile)
			err = errors.Trace(err)
		} else {
			err = s.server.Serve(l)
			err = errors.Trace(err)
		}

		startErrCh <- errors.Annotate(err, "start server")
	}()

	select {
	case <-ctx.Done():
	case err := <-startErrCh:
		return errors.Trace(err)
	}

	err = errors.Trace(s.server.Close())

	if startErr := <-startErrCh; startErr != nil {
		err = errors.Trace(startErr)
	}

	if !multierr.Is(err, http.ErrServerClosed) {
		return errors.Trace(err)
	}

	return nil
}
<commit_msg>Fix race condition in server.Server.Start<commit_after>package server

import (
	"context"
	"net"
	"net/http"

	"github.com/juju/errors"
	"github.com/peer-calls/peer-calls/server/multierr"
)

type Params struct {
	TLSCertFile string
	TLSKeyFile  string
}

type Server struct {
	server *http.Server
	params Params
}

func New(params Params, handler http.Handler) *Server {
	server := &http.Server{
		Handler: handler,
	}
	return &Server{
		server: server,
		params: params,
	}
}

func (s Server) Start(ctx context.Context, l net.Listener) error {
	startErrCh := make(chan error, 1)

	go func() {
		defer close(startErrCh)

		var err error

		if s.params.TLSCertFile != "" {
			err = s.server.ServeTLS(l, s.params.TLSCertFile, s.params.TLSKeyFile)
			err = errors.Trace(err)
		} else {
			err = s.server.Serve(l)
			err = errors.Trace(err)
		}

		startErrCh <- errors.Annotate(err, "start server")
	}()

	select {
	case <-ctx.Done():
	case err := <-startErrCh:
		return errors.Trace(err)
	}

	err := errors.Trace(s.server.Close())

	if startErr := <-startErrCh; startErr != nil {
		err = errors.Trace(startErr)
	}

	if !multierr.Is(err, http.ErrServerClosed) {
		return errors.Trace(err)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/jmcvetta/neoism"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestCreate(t *testing.T) {
	assert := assert.New(t)
	person := person{UUID: "123", Name: "Test", Identifiers: []identifier{identifier{fsAuthority, "FACTSET_ID"}}}

	db, err := neoism.Connect("http://localhost:7474/db/data")
	assert.NoError(err, "Failed to connect to Neo4j")
	peopleDriver = NewPeopleCypherDriver(db)

	assert.NoError(peopleDriver.Write(person), "Failed to write person")

	storedPerson, found, err := peopleDriver.Read("123")

	assert.NoError(err, "Error finding person")
	assert.True(found, "Didn't find person")
	assert.Equal(person, storedPerson, "people should be the same")
}

func TestBatchByCount(t *testing.T) {
	assert := assert.New(t)
	mr := &mockRunner{}
	batchCypherRunner := NewBatchCypherRunner(mr, 3, time.Millisecond*20)

	errCh := make(chan error)

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "First"},
			&neoism.CypherQuery{Statement: "Second"},
		})
	}()

	go func() {
		time.Sleep(time.Millisecond * 10)
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "Third"},
		})
	}()

	for i := 0; i < 2; i++ {
		err := <-errCh
		assert.NoError(err, "Got an error for %d", i)
	}

	expected := []*neoism.CypherQuery{
		&neoism.CypherQuery{Statement: "First"},
		&neoism.CypherQuery{Statement: "Second"},
		&neoism.CypherQuery{Statement: "Third"},
	}

	assert.Equal(expected, mr.queriesRun, "queries didn't match")
}

func TestBatchByTimeout(t *testing.T) {
	assert := assert.New(t)
	mr := &mockRunner{}
	batchCypherRunner := NewBatchCypherRunner(mr, 3, time.Millisecond*20)

	errCh := make(chan error)

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "First"},
		})
	}()

	timer := time.NewTimer(time.Millisecond * 10)

	select {
	case <-timer.C:
		assert.NoError(<-errCh, "Got an error") //expect the timer to expire first, so check we didn't get an error
	case <-errCh:
		t.Fatal("Processed query ahead of timeout")
	}

	expected := []*neoism.CypherQuery{
		&neoism.CypherQuery{Statement: "First"},
	}

	assert.Equal(expected, mr.queriesRun, "queries didn't match")
}

func TestEveryoneGetsErrorOnFailure(t *testing.T) {
	assert := assert.New(t)
	mr := &failRunner{}
	batchCypherRunner := NewBatchCypherRunner(mr, 3, time.Millisecond*20)

	errCh := make(chan error)

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "First"},
			&neoism.CypherQuery{Statement: "Second"},
		})
	}()

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "Third"},
		})
	}()

	for i := 0; i < 2; i++ {
		err := <-errCh
		assert.Error(err, "Didn't get an error for %d", i)
	}

	assert.Equal(len(errCh), 0, "too many errors")
}

type mockRunner struct {
	queriesRun []*neoism.CypherQuery
}

func (mr *mockRunner) CypherBatch(queries []*neoism.CypherQuery) error {
	if mr.queriesRun != nil {
		return errors.New("Should not have any queries waiting")
	}
	mr.queriesRun = queries
	return nil
}

type failRunner struct {
}

func (mr *failRunner) CypherBatch(queries []*neoism.CypherQuery) error {
	return errors.New("Fail for every query")
}
<commit_msg>Comment out the test that expects a running neo4j on localhost:7474 until I can get tagging of tests working<commit_after>package main

import (
	"errors"
	"github.com/jmcvetta/neoism"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func _TestCreate(t *testing.T) {
	assert := assert.New(t)
	person := person{UUID: "123", Name: "Test", Identifiers: []identifier{identifier{fsAuthority, "FACTSET_ID"}}}

	db, err := neoism.Connect("http://localhost:7474/db/data")
	assert.NoError(err, "Failed to connect to Neo4j")
	peopleDriver = NewPeopleCypherDriver(db)

	assert.NoError(peopleDriver.Write(person), "Failed to write person")

	storedPerson, found, err := peopleDriver.Read("123")

	assert.NoError(err, "Error finding person")
	assert.True(found, "Didn't find person")
	assert.Equal(person, storedPerson, "people should be the same")
}

func TestBatchByCount(t *testing.T) {
	assert := assert.New(t)
	mr := &mockRunner{}
	batchCypherRunner := NewBatchCypherRunner(mr, 3, time.Millisecond*20)

	errCh := make(chan error)

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "First"},
			&neoism.CypherQuery{Statement: "Second"},
		})
	}()

	go func() {
		time.Sleep(time.Millisecond * 10)
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "Third"},
		})
	}()

	for i := 0; i < 2; i++ {
		err := <-errCh
		assert.NoError(err, "Got an error for %d", i)
	}

	expected := []*neoism.CypherQuery{
		&neoism.CypherQuery{Statement: "First"},
		&neoism.CypherQuery{Statement: "Second"},
		&neoism.CypherQuery{Statement: "Third"},
	}

	assert.Equal(expected, mr.queriesRun, "queries didn't match")
}

func TestBatchByTimeout(t *testing.T) {
	assert := assert.New(t)
	mr := &mockRunner{}
	batchCypherRunner := NewBatchCypherRunner(mr, 3, time.Millisecond*20)

	errCh := make(chan error)

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "First"},
		})
	}()

	timer := time.NewTimer(time.Millisecond * 10)

	select {
	case <-timer.C:
		assert.NoError(<-errCh, "Got an error") //expect the timer to expire first, so check we didn't get an error
	case <-errCh:
		t.Fatal("Processed query ahead of timeout")
	}

	expected := []*neoism.CypherQuery{
		&neoism.CypherQuery{Statement: "First"},
	}

	assert.Equal(expected, mr.queriesRun, "queries didn't match")
}

func TestEveryoneGetsErrorOnFailure(t *testing.T) {
	assert := assert.New(t)
	mr := &failRunner{}
	batchCypherRunner := NewBatchCypherRunner(mr, 3, time.Millisecond*20)

	errCh := make(chan error)

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "First"},
			&neoism.CypherQuery{Statement: "Second"},
		})
	}()

	go func() {
		errCh <- batchCypherRunner.CypherBatch([]*neoism.CypherQuery{
			&neoism.CypherQuery{Statement: "Third"},
		})
	}()

	for i := 0; i < 2; i++ {
		err := <-errCh
		assert.Error(err, "Didn't get an error for %d", i)
	}

	assert.Equal(len(errCh), 0, "too many errors")
}

type mockRunner struct {
	queriesRun []*neoism.CypherQuery
}

func (mr *mockRunner) CypherBatch(queries []*neoism.CypherQuery) error {
	if mr.queriesRun != nil {
		return errors.New("Should not have any queries waiting")
	}
	mr.queriesRun = queries
	return nil
}

type failRunner struct {
}

func (mr *failRunner) CypherBatch(queries []*neoism.CypherQuery) error {
	return errors.New("Fail for every query")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"./ascii"
	"unicode"
)

func main() {
	hello, _, _ := ascii.GreetingASCII()

	f := func(c rune) bool {
		return unicode.Is(unicode.ASCII_Hex_Digit, c)
	}

	if strings.IndexFunc(hello, f) != -1 {
		fmt.Println("Found non-ASCII character")
	} else {
		fmt.Println("All ASCII here")
	}
}
<commit_msg>Fungerende ASCII-tester<commit_after>package main

import (
	"fmt"
	"strings"
	"./ascii"
	"unicode"
)

func main() {
	_, hellohex, _ := ascii.GreetingASCII()

	f := func(c rune) bool {
		return unicode.Is(unicode.ASCII_Hex_Digit, c)
	}
	fmt.Println(hellohex)
	if strings.IndexFunc(hellohex, f) != -1 {
		fmt.Println("All ASCII here")
	} else {
		fmt.Println("Found non-ASCII character")
	}
}
<|endoftext|>


<commit_before>// +build tk

package main

import (
	"bytes"
	"encoding/base64"
	"flag"
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"log"
	"os"

	"github.com/nsf/gothic"
)

func main() {
	opt := flag.Bool("s", false, "Use true 16-color solarized palette")
	optVersion := flag.Bool("v", false, "print version number")
	optCenteredCamera := flag.Bool("c", false, "centered camera")
	optMinimalUI := flag.Bool("m", false, "80x24 minimal UI")
	optNoAnim := flag.Bool("n", false, "no animations")
	flag.Parse()
	if *opt {
		SolarizedPalette()
	}
	if *optVersion {
		fmt.Println(Version)
		os.Exit(0)
	}
	if *optCenteredCamera {
		CenteredCamera = true
	}
	if *optNoAnim {
		DisableAnimations = true
	}

	tui := &termui{}
	if *optMinimalUI {
		gameConfig.Small = true
		UIHeight = 24
		UIWidth = 80
	}
	err := tui.Init()
	if err != nil {
		fmt.Fprintf(os.Stderr, "boohu: %v\n", err)
		os.Exit(1)
	}
	defer tui.Close()

	ApplyDefaultKeyBindings()
	tui.PostInit()
	gameConfig.Tiles = true
	LinkColors()
	gameConfig.DarkLOS = true

	g := &game{}
	load, err := g.LoadConfig()
	if load && err != nil {
		g.Print("Error loading config file.")
	} else if load {
		CustomKeys = true
	}

	tui.DrawWelcome()
	load, err = g.Load()
	if !load {
		g.InitLevel()
	} else if err != nil {
		g.InitLevel()
		g.Print("Error loading saved game… starting new game.")
	}
	g.ui = tui
	g.EventLoop()
}

type termui struct {
	ir         *gothic.Interpreter
	cells      []UICell
	backBuffer []UICell
	cursor     position
	stty       string
	cache      map[UICell]string
	width      int
	height     int
	mousepos   position
	menuHover  menu
	itemHover  int
}

func (ui *termui) Init() error {
	ui.cells = make([]UICell, UIWidth*UIHeight)
	ui.ResetCells()
	ui.backBuffer = make([]UICell, UIWidth*UIHeight)
	ui.ir = gothic.NewInterpreter(`
set width [expr {16 * 100}]
set height [expr {24 * 26}]
set can [canvas .c -width $width -height $height -background black]
grid $can -row 0 -column 0
focus $can
image create photo gamescreen -width $width -height $height -palette 256/256/256
image create photo bufscreen -width $width -height $height -palette 256/256/256
$can create image 0 0 -anchor nw -image gamescreen
bind $can <Key> {
	GetKey %A %K
}
`)
	ui.ir.RegisterCommand("GetKey", func(c, keysym string) {
		var s string
		if c != "" {
			s = c
		} else {
			s = keysym
		}
		ch <- uiInput{key: s}
	})
	ui.menuHover = -1
	ui.ResetCells()
	ui.backBuffer = make([]UICell, UIWidth*UIHeight)
	ui.InitElements()
	return nil
}

func (ui *termui) InitElements() error {
	ui.width = 16
	ui.height = 24
	ui.cache = make(map[UICell]string)
	return nil
}

var ch chan uiInput
var interrupt chan bool

func init() {
	ch = make(chan uiInput, 100)
	interrupt = make(chan bool)
}

type uiInput struct {
	key       string
	mouse     bool
	mouseX    int
	mouseY    int
	button    int
	interrupt bool
}

func (ui *termui) Close() {
}

func (ui *termui) PostInit() {
	SolarizedPalette()
	ui.HideCursor()
	settingsActions = append(settingsActions, toggleTiles)
}

func (ui *termui) Flush() {
	for i := 0; i < len(ui.cells); i++ {
		if ui.cells[i] == ui.backBuffer[i] {
			continue
		}
		cell := ui.cells[i]
		x, y := ui.GetPos(i)
		ui.Draw(cell, x, y)
		ui.backBuffer[i] = cell
	}
	ui.ir.Eval("gamescreen copy bufscreen") // TODO: optimize this
}

func (ui *termui) ApplyToggleLayout() {
	gameConfig.Small = !gameConfig.Small
	if gameConfig.Small {
		ui.ResetCells()
		ui.Flush()
		UIHeight = 24
		UIWidth = 80
	} else {
		UIHeight = 26
		UIWidth = 100
	}
	ui.cells = make([]UICell, UIWidth*UIHeight)
	ui.ResetCells()
	ui.backBuffer = make([]UICell, UIWidth*UIHeight)
}

func getImage(cell UICell) string {
	var pngImg []byte
	if cell.inMap && gameConfig.Tiles {
		pngImg = TileImgs["map-notile"]
		if im, ok := TileImgs["map-"+string(cell.r)]; ok {
			pngImg = im
		} else if im, ok := TileImgs["map-"+MapNames[cell.r]]; ok {
			pngImg = im
		}
	} else {
		pngImg = TileImgs["map-notile"]
		if im, ok := TileImgs["letter-"+string(cell.r)]; ok {
			pngImg = im
		} else if im, ok := TileImgs["letter-"+LetterNames[cell.r]]; ok {
			pngImg = im
		}
	}
	buf := make([]byte, len(pngImg))
	base64.StdEncoding.Decode(buf, pngImg) // TODO: check error
	br := bytes.NewReader(buf)
	img, err := png.Decode(br)
	if err != nil {
		log.Printf("Could not decode png: %v", err)
		return ""
	}
	rect := img.Bounds()
	rgbaimg := image.NewRGBA(rect)
	draw.Draw(rgbaimg, rect, img, rect.Min, draw.Src)
	bgc := cell.bg.Color()
	fgc := cell.fg.Color()
	for y := 0; y < rect.Max.Y; y++ {
		for x := 0; x < rect.Max.X; x++ {
			c := rgbaimg.At(x, y)
			r, _, _, _ := c.RGBA()
			if r == 0 {
				rgbaimg.Set(x, y, bgc)
			} else {
				rgbaimg.Set(x, y, fgc)
			}
		}
	}
	pngbuf := &bytes.Buffer{}
	png.Encode(pngbuf, rgbaimg)
	return base64.StdEncoding.EncodeToString(pngbuf.Bytes())
}

func (ui *termui) Draw(cell UICell, x, y int) {
	var img string
	if im, ok := ui.cache[cell]; ok {
		img = im
	} else {
		img = getImage(cell)
		ui.cache[cell] = img
	}
	ui.ir.Eval("::bufscreen put %{%s} -format png -to %{%d} %{%d}", img, x*ui.width, ui.height*y)
}
<commit_msg>make mouse work in tk backend<commit_after>// +build tk

package main

import (
	"bytes"
	"encoding/base64"
	"flag"
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"log"
	"os"

	"github.com/nsf/gothic"
)

func main() {
	opt := flag.Bool("s", false, "Use true 16-color solarized palette")
	optVersion := flag.Bool("v", false, "print version number")
	optCenteredCamera := flag.Bool("c", false, "centered camera")
	optMinimalUI := flag.Bool("m", false, "80x24 minimal UI")
	optNoAnim := flag.Bool("n", false, "no animations")
	flag.Parse()
	if *opt {
		SolarizedPalette()
	}
	if *optVersion {
		fmt.Println(Version)
		os.Exit(0)
	}
	if *optCenteredCamera {
		CenteredCamera = true
	}
	if *optNoAnim {
		DisableAnimations = true
	}

	tui := &termui{}
	if *optMinimalUI {
		gameConfig.Small = true
		UIHeight = 24
		UIWidth = 80
	}
	err := tui.Init()
	if err != nil {
		fmt.Fprintf(os.Stderr, "boohu: %v\n", err)
		os.Exit(1)
	}
	defer tui.Close()

	ApplyDefaultKeyBindings()
	tui.PostInit()
	gameConfig.Tiles = true
	LinkColors()
	gameConfig.DarkLOS = true

	g := &game{}
	load, err := g.LoadConfig()
	if load && err != nil {
		g.Print("Error loading config file.")
	} else if load {
		CustomKeys = true
	}

	tui.DrawWelcome()
	load, err = g.Load()
	if !load {
		g.InitLevel()
	} else if err != nil {
		g.InitLevel()
		g.Print("Error loading saved game… starting new game.")
	}
	g.ui = tui
	g.EventLoop()
}

type termui struct {
	ir         *gothic.Interpreter
	cells      []UICell
	backBuffer []UICell
	cursor     position
	stty       string
	cache      map[UICell]string
	width      int
	height     int
	mousepos   position
	menuHover  menu
	itemHover  int
}

func (ui *termui) Init() error {
	ui.cells = make([]UICell, UIWidth*UIHeight)
	ui.ResetCells()
	ui.backBuffer = make([]UICell, UIWidth*UIHeight)
	ui.ir = gothic.NewInterpreter(`
set width [expr {16 * 100}]
set height [expr {24 * 26}]
set can [canvas .c -width $width -height $height -background black]
grid $can -row 0 -column 0
focus $can
image create photo gamescreen -width $width -height $height -palette 256/256/256
image create photo bufscreen -width $width -height $height -palette 256/256/256
$can create image 0 0 -anchor nw -image gamescreen
bind $can <Key> {
	GetKey %A %K
}
bind $can <Motion> {
	MouseMotion %x %y
}
bind $can <ButtonPress> {
	MouseDown %x %y %b
}
`)
	ui.ir.RegisterCommand("GetKey", func(c, keysym string) {
		var s string
		if c != "" {
			s = c
		} else {
			s = keysym
		}
		ch <- uiInput{key: s}
	})
	ui.ir.RegisterCommand("MouseDown", func(x, y, b int) {
		ch <- uiInput{mouse: true, mouseX: (x - 1) / ui.width, mouseY: (y - 1) / ui.height, button: b - 1}
	})
	ui.ir.RegisterCommand("MouseMotion", func(x, y int) {
		nx := (x - 1) / ui.width
		ny := (y - 1) / ui.height
		if nx != ui.mousepos.X || ny != ui.mousepos.Y {
			ui.mousepos.X = nx
			ui.mousepos.Y = ny
			ch <- uiInput{mouse: true, mouseX: nx, mouseY: ny, button: -1}
		}
	})
	ui.menuHover = -1
	ui.ResetCells()
	ui.backBuffer = make([]UICell, UIWidth*UIHeight)
	ui.InitElements()
	return nil
}

func (ui *termui) InitElements() error {
	ui.width = 16
	ui.height = 24
	ui.cache = make(map[UICell]string)
	return nil
}

var ch chan uiInput
var interrupt chan bool

func init() {
	ch = make(chan uiInput, 100)
	interrupt = make(chan bool)
}

type uiInput struct {
	key       string
	mouse     bool
	mouseX    int
	mouseY    int
	button    int
	interrupt bool
}

func (ui *termui) Close() {
}

func (ui *termui) PostInit() {
	SolarizedPalette()
	ui.HideCursor()
	settingsActions = append(settingsActions, toggleTiles)
}

func (ui *termui) Flush() {
	for i := 0; i < len(ui.cells); i++ {
		if ui.cells[i] == ui.backBuffer[i] {
			continue
		}
		cell := ui.cells[i]
		x, y := ui.GetPos(i)
		ui.Draw(cell, x, y)
		ui.backBuffer[i] = cell
	}
	ui.ir.Eval("gamescreen copy bufscreen") // TODO: optimize this
}

func (ui *termui) ApplyToggleLayout() {
	gameConfig.Small = !gameConfig.Small
	if gameConfig.Small {
		ui.ResetCells()
		ui.Flush()
		UIHeight = 24
		UIWidth = 80
	} else {
		UIHeight = 26
		UIWidth = 100
	}
	ui.cells = make([]UICell, UIWidth*UIHeight)
	ui.ResetCells()
	ui.backBuffer = make([]UICell, UIWidth*UIHeight)
}

func getImage(cell UICell) string {
	var pngImg []byte
	if cell.inMap && gameConfig.Tiles {
		pngImg = TileImgs["map-notile"]
		if im, ok := TileImgs["map-"+string(cell.r)]; ok {
			pngImg = im
		} else if im, ok := TileImgs["map-"+MapNames[cell.r]]; ok {
			pngImg = im
		}
	} else {
		pngImg = TileImgs["map-notile"]
		if im, ok := TileImgs["letter-"+string(cell.r)]; ok {
			pngImg = im
		} else if im, ok := TileImgs["letter-"+LetterNames[cell.r]]; ok {
			pngImg = im
		}
	}
	buf := make([]byte, len(pngImg))
	base64.StdEncoding.Decode(buf, pngImg) // TODO: check error
	br := bytes.NewReader(buf)
	img, err := png.Decode(br)
	if err != nil {
		log.Printf("Could not decode png: %v", err)
		return ""
	}
	rect := img.Bounds()
	rgbaimg := image.NewRGBA(rect)
	draw.Draw(rgbaimg, rect, img, rect.Min, draw.Src)
	bgc := cell.bg.Color()
	fgc := cell.fg.Color()
	for y := 0; y < rect.Max.Y; y++ {
		for x := 0; x < rect.Max.X; x++ {
			c := rgbaimg.At(x, y)
			r, _, _, _ := c.RGBA()
			if r == 0 {
				rgbaimg.Set(x, y, bgc)
			} else {
				rgbaimg.Set(x, y, fgc)
			}
		}
	}
	pngbuf := &bytes.Buffer{}
	png.Encode(pngbuf, rgbaimg)
	return base64.StdEncoding.EncodeToString(pngbuf.Bytes())
}

func (ui *termui) Draw(cell UICell, x, y int) {
	var img string
	if im, ok := ui.cache[cell]; ok {
		img = im
	} else {
		img = getImage(cell)
		ui.cache[cell] = img
	}
	ui.ir.Eval("::bufscreen put %{%s} -format png -to %{%d} %{%d}", img, x*ui.width, ui.height*y)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2019 the Octant contributors. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package action

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/vmware-tanzu/octant/pkg/log"
)

//go:generate mockgen -destination=./fake/mock_alert.go -package=fake github.com/vmware-tanzu/octant/pkg/action Alerter

const (
	// DefaultAlertExpiration is the default expiration for alerts.
	DefaultAlertExpiration = 10 * time.Second
)

// AlertType is the type of alert.
type AlertType string

const (
	// AlertTypeError is for error alerts.
	AlertTypeError AlertType = "ERROR"

	// AlertTypeWarning is for warning alerts.
	AlertTypeWarning AlertType = "WARNING"

	// AlertTypeInfo is for info alerts.
	AlertTypeInfo AlertType = "INFO"
)

// Alert is an alert message.
type Alert struct {
	// Type is the type of alert.
	Type AlertType `json:"type"`
	// Message is the message for the alert.
	Message string `json:"message"`
	// Expiration is the time the alert expires.
	Expiration *time.Time `json:"expiration,omitempty"`
}

// CreateAlert creates an alert with optional expiration. If the expireAt is < 1
// Expiration will be nil.
func CreateAlert(alertType AlertType, message string, expireAt time.Duration) Alert {
	alert := Alert{
		Type:    alertType,
		Message: message,
	}

	if expireAt > 0 {
		t := time.Now().Add(expireAt)
		alert.Expiration = &t
	}

	return alert
}

type Alerter interface {
	SendAlert(alert Alert)
}

// DispatcherFunc is a function that will be dispatched to handle a payload.
type DispatcherFunc func(ctx context.Context, alerter Alerter, payload Payload) error

// Dispatcher handles actions.
type Dispatcher interface {
	ActionName() string
	Handle(ctx context.Context, alerter Alerter, payload Payload) error
}

// Dispatchers is a slice of Dispatcher.
type Dispatchers []Dispatcher

// ToActionPaths converts Dispatchers to a map.
func (d Dispatchers) ToActionPaths() map[string]DispatcherFunc {
	m := make(map[string]DispatcherFunc)

	for i := range d {
		m[d[i].ActionName()] = d[i].Handle
	}

	return m
}

// Manager manages actions.
type Manager struct {
	logger     log.Logger

	// key: string, value: []DispatcherFunc
	dispatches sync.Map
}

// NewManager creates an instance of Manager.
func NewManager(logger log.Logger) *Manager {
	return &Manager{
		logger:     logger.With("component", "action-manager"),
		dispatches: sync.Map{},
	}
}

// Register registers a dispatcher function to an action path.
func (m *Manager) Register(actionPath string, actionFunc DispatcherFunc) error {
	var af []DispatcherFunc

	val, ok := m.dispatches.Load(actionPath)
	if !ok {
		af = make([]DispatcherFunc, 1)
		af[0] = actionFunc
	} else {
		af, ok = val.([]DispatcherFunc)
		if !ok {
			return fmt.Errorf("failed to convert value to []DispatcherFunc")
		}
		af = append(af, actionFunc)
	}

	m.logger.Infof("REGISTER: %+v\n%+v", actionPath, af)
	m.dispatches.Store(actionPath, af)

	return nil
}

// Dispatch dispatches a payload to a path.
func (m *Manager) Dispatch(ctx context.Context, alerter Alerter, actionPath string, payload Payload) error {
	val, ok := m.dispatches.Load(actionPath)
	if !ok {
		return &NotFoundError{Path: actionPath}

	}
	actionFuncs := val.([]DispatcherFunc)
	for _, f := range actionFuncs {
		if err := f(ctx, alerter, payload); err != nil {
			m.logger.Errorf("actionFunc returned err: %s", err)
		}
	}

	return nil
}
<commit_msg>remove verbose info logging<commit_after>/*
Copyright (c) 2019 the Octant contributors. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package action

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/vmware-tanzu/octant/pkg/log"
)

//go:generate mockgen -destination=./fake/mock_alert.go -package=fake github.com/vmware-tanzu/octant/pkg/action Alerter

const (
	// DefaultAlertExpiration is the default expiration for alerts.
	DefaultAlertExpiration = 10 * time.Second
)

// AlertType is the type of alert.
type AlertType string

const (
	// AlertTypeError is for error alerts.
	AlertTypeError AlertType = "ERROR"

	// AlertTypeWarning is for warning alerts.
	AlertTypeWarning AlertType = "WARNING"

	// AlertTypeInfo is for info alerts.
	AlertTypeInfo AlertType = "INFO"
)

// Alert is an alert message.
type Alert struct {
	// Type is the type of alert.
	Type AlertType `json:"type"`
	// Message is the message for the alert.
	Message string `json:"message"`
	// Expiration is the time the alert expires.
	Expiration *time.Time `json:"expiration,omitempty"`
}

// CreateAlert creates an alert with optional expiration. If the expireAt is < 1
// Expiration will be nil.
func CreateAlert(alertType AlertType, message string, expireAt time.Duration) Alert {
	alert := Alert{
		Type:    alertType,
		Message: message,
	}

	if expireAt > 0 {
		t := time.Now().Add(expireAt)
		alert.Expiration = &t
	}

	return alert
}

type Alerter interface {
	SendAlert(alert Alert)
}

// DispatcherFunc is a function that will be dispatched to handle a payload.
type DispatcherFunc func(ctx context.Context, alerter Alerter, payload Payload) error

// Dispatcher handles actions.
type Dispatcher interface {
	ActionName() string
	Handle(ctx context.Context, alerter Alerter, payload Payload) error
}

// Dispatchers is a slice of Dispatcher.
type Dispatchers []Dispatcher

// ToActionPaths converts Dispatchers to a map.
func (d Dispatchers) ToActionPaths() map[string]DispatcherFunc {
	m := make(map[string]DispatcherFunc)

	for i := range d {
		m[d[i].ActionName()] = d[i].Handle
	}

	return m
}

// Manager manages actions.
type Manager struct {
	logger     log.Logger

	// key: string, value: []DispatcherFunc
	dispatches sync.Map
}

// NewManager creates an instance of Manager.
func NewManager(logger log.Logger) *Manager {
	return &Manager{
		logger:     logger.With("component", "action-manager"),
		dispatches: sync.Map{},
	}
}

// Register registers a dispatcher function to an action path.
func (m *Manager) Register(actionPath string, actionFunc DispatcherFunc) error {
	var af []DispatcherFunc

	val, ok := m.dispatches.Load(actionPath)
	if !ok {
		af = make([]DispatcherFunc, 1)
		af[0] = actionFunc
	} else {
		af, ok = val.([]DispatcherFunc)
		if !ok {
			return fmt.Errorf("failed to convert value to []DispatcherFunc")
		}
		af = append(af, actionFunc)
	}

	m.dispatches.Store(actionPath, af)

	return nil
}

// Dispatch dispatches a payload to a path.
func (m *Manager) Dispatch(ctx context.Context, alerter Alerter, actionPath string, payload Payload) error {
	val, ok := m.dispatches.Load(actionPath)
	if !ok {
		return &NotFoundError{Path: actionPath}

	}

	actionFuncs := val.([]DispatcherFunc)
	for _, f := range actionFuncs {
		if err := f(ctx, alerter, payload); err != nil {
			m.logger.Errorf("actionFunc returned err: %s", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package userSystem

import (
	"database/sql"
	"errors"
	log "github.com/Sirupsen/logrus"
	"github.com/oxfeeefeee/appgo"
)

const (
	pushBatchSize = 3
)

func (u *UserSystem) PushTo(users []appgo.Id, content *appgo.PushData) {
	doPush := func(ids []appgo.Id) {
		if tokens, err := u.GetPushTokens(ids); err != nil {
			log.WithFields(log.Fields{
				"users": ids,
				"error": err,
			}).Errorln("failed to GetPushTokens")
		} else {
			for prov, data := range tokens {
				pusher := u.DefaultPusher
				if p, ok := u.Pushers[prov]; ok {
					pusher = p
				}
				for plat, tokens := range data {
					pusher.PushNotif(plat, tokens, content)
				}
			}
		}
	}
	for i := 0; i < len(users); i += pushBatchSize {
		end := i + pushBatchSize
		if end > len(users) {
			end = len(users)
		}
		doPush(users[i:end])
	}
}

func (u *UserSystem) SetPushToken(id appgo.Id, platform appgo.Platform,
	provider, token string) error {
	if provider == "" || token == "" {
		return errors.New("bad push provider or token")
	}
	user := &UserModel{Id: id}
	update := &UserModel{
		Platform:     platform,
		PushProvider: sql.NullString{provider, true},
		PushToken:    sql.NullString{token, true},
	}
	return u.db.Model(user).Updates(update).Error
}

func (u *UserSystem) GetPushTokens(ids []appgo.Id) (map[string]map[appgo.Platform][]string, error) {
	var users []*UserModel
	if err := u.db.Select("platform, push_provider, push_token").
		Where("id in (?)", ids).Find(&users).Error; err != nil {
		return nil, err
	}
	ret := make(map[string]map[appgo.Platform][]string)
	for _, user := range users {
		plat, prov, token := user.Platform, user.PushProvider.String, user.PushToken.String
		if plat != 0 && prov != "" && token != "" {
			if _, ok := ret[prov]; !ok {
				ret[prov] = make(map[appgo.Platform][]string)
			}
			if _, ok := ret[prov][plat]; !ok {
				ret[prov][plat] = make([]string, 0)
			}
			ret[prov][plat] = append(ret[prov][plat], token)
		}
	}
	return ret, nil
}
<commit_msg>change pushBatchSize<commit_after>package userSystem

import (
	"database/sql"
	"errors"
	log "github.com/Sirupsen/logrus"
	"github.com/oxfeeefeee/appgo"
)

const (
	pushBatchSize = 450
)

func (u *UserSystem) PushTo(users []appgo.Id, content *appgo.PushData) {
	doPush := func(ids []appgo.Id) {
		if tokens, err := u.GetPushTokens(ids); err != nil {
			log.WithFields(log.Fields{
				"users": ids,
				"error": err,
			}).Errorln("failed to GetPushTokens")
		} else {
			for prov, data := range tokens {
				pusher := u.DefaultPusher
				if p, ok := u.Pushers[prov]; ok {
					pusher = p
				}
				for plat, tokens := range data {
					pusher.PushNotif(plat, tokens, content)
				}
			}
		}
	}
	for i := 0; i < len(users); i += pushBatchSize {
		end := i + pushBatchSize
		if end > len(users) {
			end = len(users)
		}
		doPush(users[i:end])
	}
}

func (u *UserSystem) SetPushToken(id appgo.Id, platform appgo.Platform,
	provider, token string) error {
	if provider == "" || token == "" {
		return errors.New("bad push provider or token")
	}
	user := &UserModel{Id: id}
	update := &UserModel{
		Platform:     platform,
		PushProvider: sql.NullString{provider, true},
		PushToken:    sql.NullString{token, true},
	}
	return u.db.Model(user).Updates(update).Error
}

func (u *UserSystem) GetPushTokens(ids []appgo.Id) (map[string]map[appgo.Platform][]string, error) {
	var users []*UserModel
	if err := u.db.Select("platform, push_provider, push_token").
		Where("id in (?)", ids).Find(&users).Error; err != nil {
		return nil, err
	}
	ret := make(map[string]map[appgo.Platform][]string)
	for _, user := range users {
		plat, prov, token := user.Platform, user.PushProvider.String, user.PushToken.String
		if plat != 0 && prov != "" && token != "" {
			if _, ok := ret[prov]; !ok {
				ret[prov] = make(map[appgo.Platform][]string)
			}
			if _, ok := ret[prov][plat]; !ok {
				ret[prov][plat] = make([]string, 0)
			}
			ret[prov][plat] = append(ret[prov][plat], token)
		}
	}
	return ret, nil
}
<|endoftext|>


<commit_before>package server

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rsa"
	"errors"
	"fmt"

	// Rather than crypto/x509 as ct allows disabling critical extension checks.
	"github.com/google/certificate-transparency-go/x509"
	"github.com/google/go-tpm-tools/internal"
	pb "github.com/google/go-tpm-tools/proto/attest"
	tpmpb "github.com/google/go-tpm-tools/proto/tpm"
	"github.com/google/go-tpm/tpm2"
	"google.golang.org/protobuf/proto"
)

// The hash algorithms we support, in their preferred order of use.
var supportedHashAlgs = []tpm2.Algorithm{
	tpm2.AlgSHA512, tpm2.AlgSHA384, tpm2.AlgSHA256, tpm2.AlgSHA1,
}

// VerifyOpts allows for customizing the functionality of VerifyAttestation.
type VerifyOpts struct {
	// The nonce used when calling client.Attest
	Nonce []byte
	// Trusted public keys that can be used to directly verify the key used for
	// attestation. This option should be used if you already know the AK, as
	// it provides the highest level of assurance.
	TrustedAKs []crypto.PublicKey
	// Allow attestations to be verified using SHA-1. This defaults to false
	// because SHA-1 is a weak hash algorithm with known collision attacks.
	// However, setting this to true may be necessary if the client only
	// supports the legacy event log format. This is the case on older Linux
	// distributions (such as Debian 10).
	AllowSHA1 bool
	// A collection of trusted root CAs that are used to sign AK certificates.
	// The TrustedAKs are used first, followed by TrustRootCerts and
	// IntermediateCerts.
	// Adding a specific TPM manufacturer's root and intermediate CAs means all
	// TPMs signed by that CA will be trusted.
	TrustedRootCerts  *x509.CertPool
	IntermediateCerts *x509.CertPool
}

// VerifyAttestation performs the following checks on an Attestation:
//    - the AK used to generate the attestation is trusted (based on VerifyOpts)
//    - the provided signature is generated by the trusted AK public key
//    - the signature signs the provided quote data
//    - the quote data starts with TPM_GENERATED_VALUE
//    - the quote data is a valid TPMS_QUOTE_INFO
//    - the quote data was taken over the provided PCRs
//    - the provided PCR values match the quote data internal digest
//    - the provided opts.Nonce matches that in the quote data
//    - the provided eventlog matches the provided PCR values
//
// After this, the eventlog is parsed and the corresponding MachineState is
// returned. This design prevents unverified MachineStates from being used.
func VerifyAttestation(attestation *pb.Attestation, opts VerifyOpts) (*pb.MachineState, error) {
	// Verify the AK
	akPubArea, err := tpm2.DecodePublic(attestation.GetAkPub())
	if err != nil {
		return nil, fmt.Errorf("failed to decode AK public area: %w", err)
	}
	akPubKey, err := akPubArea.Key()
	if err != nil {
		return nil, fmt.Errorf("failed to get AK public key: %w", err)
	}
	if err := checkAKTrusted(akPubKey, attestation.GetAkCert(), opts); err != nil {
		return nil, fmt.Errorf("failed to validate AK: %w", err)
	}

	// Verify the signing hash algorithm
	signHashAlg, err := internal.GetSigningHashAlg(akPubArea)
	if err != nil {
		return nil, fmt.Errorf("bad AK public area: %w", err)
	}
	if err = checkHashAlgSupported(signHashAlg, opts); err != nil {
		return nil, fmt.Errorf("in AK public area: %w", err)
	}

	// Attempt to replay the log against our PCRs in order of hash preference
	var lastErr error
	for _, quote := range supportedQuotes(attestation.GetQuotes()) {
		// Verify the Quote
		if err = internal.VerifyQuote(quote, akPubKey, opts.Nonce); err != nil {
			lastErr = fmt.Errorf("failed to verify quote: %w", err)
			continue
		}

		// Parse event logs and replay the events against the provided PCRs
		pcrs := quote.GetPcrs()
		state, err := parsePCClientEventLog(attestation.GetEventLog(), pcrs)
		if err != nil {
			lastErr = fmt.Errorf("failed to validate the PCClient event log: %w", err)
			continue
		}

		celState, err := parseCanonicalEventLog(attestation.GetCanonicalEventLog(), pcrs)
		if err != nil {
			lastErr = fmt.Errorf("failed to validate the Canonical event log: %w", err)
			continue
		}

		proto.Merge(celState, state)

		// Verify the PCR hash algorithm. We have this check here (instead of at
		// the start of the loop) so that the user gets a "SHA-1 not supported"
		// error only if allowing SHA-1 support would actually allow the log
		// to be verified. This makes debugging failed verifications easier.
		pcrHashAlg := tpm2.Algorithm(pcrs.GetHash())
		if err = checkHashAlgSupported(pcrHashAlg, opts); err != nil {
			lastErr = fmt.Errorf("when verifying PCRs: %w", err)
			continue
		}

		return celState, nil
	}

	if lastErr != nil {
		return nil, lastErr
	}
	return nil, fmt.Errorf("attestation does not contain a supported quote")
}

func pubKeysEqual(k1 crypto.PublicKey, k2 crypto.PublicKey) bool {
	switch key := k1.(type) {
	case *rsa.PublicKey:
		return key.Equal(k2)
	case *ecdsa.PublicKey:
		return key.Equal(k2)
	default:
		return false
	}
}

// Checks if the provided AK public key can be trusted
func checkAKTrusted(ak crypto.PublicKey, akCertBytes []byte, opts VerifyOpts) error {
	checkPub := len(opts.TrustedAKs) > 0
	checkCert := opts.TrustedRootCerts != nil && len(opts.TrustedRootCerts.Subjects()) > 0
	if !checkPub && !checkCert {
		return fmt.Errorf("no trust mechanism provided, either use TrustedAKs or TrustedRootCerts")
	}
	if checkPub && checkCert {
		return fmt.Errorf("multiple trust mechanisms provided, only use one of TrustedAKs or TrustedRootCerts")
	}

	// Check against known AKs
	if checkPub {
		for _, trusted := range opts.TrustedAKs {
			if pubKeysEqual(ak, trusted) {
				return nil
			}
		}
		return fmt.Errorf("public key is not trusted")
	}

	// Check if the AK Cert chains to a trusted root
	if len(akCertBytes) == 0 {
		return errors.New("no certificate provided in attestation")
	}
	akCert, err := x509.ParseCertificate(akCertBytes)
	if err != nil {
		return fmt.Errorf("failed to parse certificate: %w", err)
	}

	x509Opts := x509.VerifyOptions{
		Roots:         opts.TrustedRootCerts,
		Intermediates: opts.IntermediateCerts,
		// x509 (both ct and crypto) marks the SAN extension unhandled if SAN
		// does not parse any of DNSNames, EmailAddresses, IPAddresses, or URIs.
		// https://cs.opensource.google/go/go/+/master:src/crypto/x509/parser.go;l=668-678
		DisableCriticalExtensionChecks: true,
		// The default key usage (ExtKeyUsageServerAuth) is not appropriate for
		// an Attestation Key: ExtKeyUsage of
		// - https://oidref.com/2.23.133.8.1
		// - https://oidref.com/2.23.133.8.3
		// https://pkg.go.dev/crypto/x509#VerifyOptions
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsage(x509.ExtKeyUsageAny)},
	}
	if _, err := akCert.Verify(x509Opts); err != nil {
		return fmt.Errorf("failed to verify certificate against trusted roots: %v", err)
	}
	return nil
}

func checkHashAlgSupported(hash tpm2.Algorithm, opts VerifyOpts) error {
	if hash == tpm2.AlgSHA1 && !opts.AllowSHA1 {
		return fmt.Errorf("SHA-1 is not allowed for verification (set VerifyOpts.AllowSHA1 to true to allow)")
	}
	for _, alg := range supportedHashAlgs {
		if hash == alg {
			return nil
		}
	}
	return fmt.Errorf("unsupported hash algorithm: %v", hash)
}

// Retrieve the supported quotes in order of hash preference
func supportedQuotes(quotes []*tpmpb.Quote) []*tpmpb.Quote {
	out := make([]*tpmpb.Quote, 0, len(quotes))
	for _, alg := range supportedHashAlgs {
		for _, quote := range quotes {
			if tpm2.Algorithm(quote.GetPcrs().GetHash()) == alg {
				out = append(out, quote)
				break
			}
		}
	}
	return out
}
<commit_msg>server: Fix AK Cert checking bug<commit_after>package server

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rsa"
	"errors"
	"fmt"

	// Rather than crypto/x509 as ct allows disabling critical extension checks.
	"github.com/google/certificate-transparency-go/x509"
	"github.com/google/go-tpm-tools/internal"
	pb "github.com/google/go-tpm-tools/proto/attest"
	tpmpb "github.com/google/go-tpm-tools/proto/tpm"
	"github.com/google/go-tpm/tpm2"
	"google.golang.org/protobuf/proto"
)

// The hash algorithms we support, in their preferred order of use.
var supportedHashAlgs = []tpm2.Algorithm{
	tpm2.AlgSHA512, tpm2.AlgSHA384, tpm2.AlgSHA256, tpm2.AlgSHA1,
}

// VerifyOpts allows for customizing the functionality of VerifyAttestation.
type VerifyOpts struct {
	// The nonce used when calling client.Attest
	Nonce []byte
	// Trusted public keys that can be used to directly verify the key used for
	// attestation. This option should be used if you already know the AK, as
	// it provides the highest level of assurance.
	TrustedAKs []crypto.PublicKey
	// Allow attestations to be verified using SHA-1. This defaults to false
	// because SHA-1 is a weak hash algorithm with known collision attacks.
	// However, setting this to true may be necessary if the client only
	// supports the legacy event log format. This is the case on older Linux
	// distributions (such as Debian 10).
	AllowSHA1 bool
	// A collection of trusted root CAs that are used to sign AK certificates.
	// The TrustedAKs are used first, followed by TrustRootCerts and
	// IntermediateCerts.
	// Adding a specific TPM manufacturer's root and intermediate CAs means all
	// TPMs signed by that CA will be trusted.
	TrustedRootCerts  *x509.CertPool
	IntermediateCerts *x509.CertPool
}

// VerifyAttestation performs the following checks on an Attestation:
//    - the AK used to generate the attestation is trusted (based on VerifyOpts)
//    - the provided signature is generated by the trusted AK public key
//    - the signature signs the provided quote data
//    - the quote data starts with TPM_GENERATED_VALUE
//    - the quote data is a valid TPMS_QUOTE_INFO
//    - the quote data was taken over the provided PCRs
//    - the provided PCR values match the quote data internal digest
//    - the provided opts.Nonce matches that in the quote data
//    - the provided eventlog matches the provided PCR values
//
// After this, the eventlog is parsed and the corresponding MachineState is
// returned. This design prevents unverified MachineStates from being used.
func VerifyAttestation(attestation *pb.Attestation, opts VerifyOpts) (*pb.MachineState, error) {
	// Verify the AK
	akPubArea, err := tpm2.DecodePublic(attestation.GetAkPub())
	if err != nil {
		return nil, fmt.Errorf("failed to decode AK public area: %w", err)
	}
	akPubKey, err := akPubArea.Key()
	if err != nil {
		return nil, fmt.Errorf("failed to get AK public key: %w", err)
	}
	if err := checkAKTrusted(akPubKey, attestation.GetAkCert(), opts); err != nil {
		return nil, fmt.Errorf("failed to validate AK: %w", err)
	}

	// Verify the signing hash algorithm
	signHashAlg, err := internal.GetSigningHashAlg(akPubArea)
	if err != nil {
		return nil, fmt.Errorf("bad AK public area: %w", err)
	}
	if err = checkHashAlgSupported(signHashAlg, opts); err != nil {
		return nil, fmt.Errorf("in AK public area: %w", err)
	}

	// Attempt to replay the log against our PCRs in order of hash preference
	var lastErr error
	for _, quote := range supportedQuotes(attestation.GetQuotes()) {
		// Verify the Quote
		if err = internal.VerifyQuote(quote, akPubKey, opts.Nonce); err != nil {
			lastErr = fmt.Errorf("failed to verify quote: %w", err)
			continue
		}

		// Parse event logs and replay the events against the provided PCRs
		pcrs := quote.GetPcrs()
		state, err := parsePCClientEventLog(attestation.GetEventLog(), pcrs)
		if err != nil {
			lastErr = fmt.Errorf("failed to validate the PCClient event log: %w", err)
			continue
		}

		celState, err := parseCanonicalEventLog(attestation.GetCanonicalEventLog(), pcrs)
		if err != nil {
			lastErr = fmt.Errorf("failed to validate the Canonical event log: %w", err)
			continue
		}

		proto.Merge(celState, state)

		// Verify the PCR hash algorithm. We have this check here (instead of at
		// the start of the loop) so that the user gets a "SHA-1 not supported"
		// error only if allowing SHA-1 support would actually allow the log
		// to be verified. This makes debugging failed verifications easier.
		pcrHashAlg := tpm2.Algorithm(pcrs.GetHash())
		if err = checkHashAlgSupported(pcrHashAlg, opts); err != nil {
			lastErr = fmt.Errorf("when verifying PCRs: %w", err)
			continue
		}

		return celState, nil
	}

	if lastErr != nil {
		return nil, lastErr
	}
	return nil, fmt.Errorf("attestation does not contain a supported quote")
}

func pubKeysEqual(k1 crypto.PublicKey, k2 crypto.PublicKey) bool {
	switch key := k1.(type) {
	case *rsa.PublicKey:
		return key.Equal(k2)
	case *ecdsa.PublicKey:
		return key.Equal(k2)
	default:
		return false
	}
}

// Checks if the provided AK public key can be trusted
func checkAKTrusted(ak crypto.PublicKey, akCertBytes []byte, opts VerifyOpts) error {
	checkPub := len(opts.TrustedAKs) > 0
	checkCert := opts.TrustedRootCerts != nil && len(opts.TrustedRootCerts.Subjects()) > 0
	if !checkPub && !checkCert {
		return fmt.Errorf("no trust mechanism provided, either use TrustedAKs or TrustedRootCerts")
	}
	if checkPub && checkCert {
		return fmt.Errorf("multiple trust mechanisms provided, only use one of TrustedAKs or TrustedRootCerts")
	}

	// Check against known AKs
	if checkPub {
		for _, trusted := range opts.TrustedAKs {
			if pubKeysEqual(ak, trusted) {
				return nil
			}
		}
		return fmt.Errorf("public key is not trusted")
	}

	// Check if the AK Cert chains to a trusted root
	if len(akCertBytes) == 0 {
		return errors.New("no certificate provided in attestation")
	}
	akCert, err := x509.ParseCertificate(akCertBytes)
	if err != nil {
		return fmt.Errorf("failed to parse certificate: %w", err)
	}
	if !pubKeysEqual(ak, akCert.PublicKey) {
		return fmt.Errorf("mismatch between public key and certificate")
	}

	x509Opts := x509.VerifyOptions{
		Roots:         opts.TrustedRootCerts,
		Intermediates: opts.IntermediateCerts,
		// x509 (both ct and crypto) marks the SAN extension unhandled if SAN
		// does not parse any of DNSNames, EmailAddresses, IPAddresses, or URIs.
		// https://cs.opensource.google/go/go/+/master:src/crypto/x509/parser.go;l=668-678
		DisableCriticalExtensionChecks: true,
		// The default key usage (ExtKeyUsageServerAuth) is not appropriate for
		// an Attestation Key: ExtKeyUsage of
		// - https://oidref.com/2.23.133.8.1
		// - https://oidref.com/2.23.133.8.3
		// https://pkg.go.dev/crypto/x509#VerifyOptions
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsage(x509.ExtKeyUsageAny)},
	}
	if _, err := akCert.Verify(x509Opts); err != nil {
		return fmt.Errorf("failed to verify certificate against trusted roots: %v", err)
	}
	return nil
}

func checkHashAlgSupported(hash tpm2.Algorithm, opts VerifyOpts) error {
	if hash == tpm2.AlgSHA1 && !opts.AllowSHA1 {
		return fmt.Errorf("SHA-1 is not allowed for verification (set VerifyOpts.AllowSHA1 to true to allow)")
	}
	for _, alg := range supportedHashAlgs {
		if hash == alg {
			return nil
		}
	}
	return fmt.Errorf("unsupported hash algorithm: %v", hash)
}

// Retrieve the supported quotes in order of hash preference
func supportedQuotes(quotes []*tpmpb.Quote) []*tpmpb.Quote {
	out := make([]*tpmpb.Quote, 0, len(quotes))
	for _, alg := range supportedHashAlgs {
		for _, quote := range quotes {
			if tpm2.Algorithm(quote.GetPcrs().GetHash()) == alg {
				out = append(out, quote)
				break
			}
		}
	}
	return out
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package core

import (
	"bytes"
	"debug/elf"
	"encoding/binary"
	"fmt"
	"io"
	"os"

	"mynewt.apache.org/newt/util"
)

type CoreConvert struct {
	Source    *os.File
	Target    *os.File
	ImageHash []byte
	elfHdr    *elf.Header32
	phdrs     []*elf.Prog32
	data      [][]byte
}

const (
	COREDUMP_TLV_IMAGE = 1
	COREDUMP_TLV_MEM   = 2
	COREDUMP_TLV_REGS  = 3
)

const (
	COREDUMP_MAGIC = 0x690c47c3
)

type coreDumpHdr struct {
	Magic uint32
	Size  uint32
}

type coreDumpTlv struct {
	Type uint8
	pad  uint8
	Len  uint16
	Off  uint32
}

func NewCoreConvert() *CoreConvert {
	return &CoreConvert{}
}

func (cc *CoreConvert) readHdr() error {
	var hdr coreDumpHdr

	hdr_buf := make([]byte, binary.Size(hdr))
	if hdr_buf == nil {
		return util.NewNewtError("Out of memory")
	}

	cnt, err := cc.Source.Read(hdr_buf)
	if err != nil {
		return util.NewNewtError(fmt.Sprintf("Error reading: %s", err.Error()))
	}
	if cnt != binary.Size(hdr) {
		return util.NewNewtError("Short read")
	}

	hdr.Magic = binary.LittleEndian.Uint32(hdr_buf[0:4])
	hdr.Size = binary.LittleEndian.Uint32(hdr_buf[4:8])

	if hdr.Magic != COREDUMP_MAGIC {
		return util.NewNewtError("Source file is not corefile")
	}
	return nil
}

func (cc *CoreConvert) readTlv() (*coreDumpTlv, error) {
	var tlv coreDumpTlv

	tlv_buf := make([]byte, binary.Size(tlv))
	if tlv_buf == nil {
		return nil, util.NewNewtError("Out of memory")
	}

	cnt, err := cc.Source.Read(tlv_buf)
	if err == io.EOF {
		return nil, nil
	}
	if err != nil {
		return nil, util.NewNewtError(fmt.Sprintf("Error reading: %s",
			err.Error()))
	}
	if cnt == 0 {
		return nil, nil
	}
	if cnt != binary.Size(tlv) {
		return nil, util.NewNewtError("Short read")
	}

	tlv.Type = uint8(tlv_buf[0])
	tlv.pad = uint8(tlv_buf[1])
	tlv.Len = binary.LittleEndian.Uint16(tlv_buf[2:4])
	tlv.Off = binary.LittleEndian.Uint32(tlv_buf[4:8])

	return &tlv, nil
}

func (cc *CoreConvert) makeElfHdr() {
	var hdr elf.Header32
	var phdr elf.Prog32
	var shdr elf.Section32

	copy(hdr.Ident[:], elf.ELFMAG)
	hdr.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS32)
	hdr.Ident[elf.EI_DATA] = byte(elf.ELFDATA2LSB)
	hdr.Ident[elf.EI_VERSION] = byte(elf.EV_CURRENT)
	hdr.Ident[elf.EI_OSABI] = byte(elf.ELFOSABI_NONE)
	hdr.Ident[elf.EI_ABIVERSION] = 0
	hdr.Ident[elf.EI_PAD] = 0
	hdr.Type = uint16(elf.ET_CORE)
	hdr.Machine = uint16(elf.EM_ARM)
	hdr.Version = uint32(elf.EV_CURRENT)
	hdr.Entry = 0
	hdr.Phoff = uint32(binary.Size(hdr))
	hdr.Shoff = 0
	hdr.Flags = 0
	hdr.Ehsize = uint16(binary.Size(hdr))
	hdr.Phentsize = uint16(binary.Size(phdr))
	hdr.Phnum = uint16(len(cc.phdrs))
	hdr.Shentsize = uint16(binary.Size(shdr))
	hdr.Shnum = 0
	hdr.Shstrndx = uint16(elf.SHN_UNDEF)

	cc.elfHdr = &hdr
}

func (cc *CoreConvert) makeProgHdr(off uint32, mem []byte) {
	var phdr elf.Prog32

	memSz := uint32(len(mem))

	phdr.Type = uint32(elf.PT_LOAD)
	phdr.Off = 0 /* offset of data in file */
	phdr.Vaddr = off
	phdr.Paddr = 0
	phdr.Filesz = memSz
	phdr.Memsz = memSz
	phdr.Flags = uint32(elf.PF_R)
	phdr.Align = 4

	cc.phdrs = append(cc.phdrs, &phdr)
	if memSz%4 != 0 {
		pad := make([]byte, 4-memSz%4)
		mem = append(mem, pad...)
	}
	cc.data = append(cc.data, mem)
}

func (cc *CoreConvert) makeRegData(regs []byte) []byte {
	type Elf32_Note struct {
		Namesz uint32
		Descsz uint32
		Ntype  uint32
	}

	type Elf32_Prstatus struct {
		Dummy  [18]uint32
		Regs   [18]uint32
		Dummy2 uint32
	}

	var note Elf32_Note
	var sts Elf32_Prstatus

	idx := 0
	for off := 0; off < len(regs); off += 4 {
		reg := binary.LittleEndian.Uint32(regs[off : off+4])
		sts.Regs[idx] = reg
		idx++
		if idx >= 18 {
			break
		}
	}

	noteName := ".reg"
	noteLen := len(noteName) + 1
	if noteLen%4 != 0 {
		noteLen = noteLen + 4 - (noteLen % 4)
	}
	noteBytes := make([]byte, noteLen)
	copy(noteBytes[:], noteName)

	note.Namesz = uint32(len(noteName) + 1) /* include terminating '\0' */
	note.Descsz = uint32(binary.Size(sts))
	note.Ntype = uint32(elf.NT_PRSTATUS)

	buffer := new(bytes.Buffer)
	binary.Write(buffer, binary.LittleEndian, note)
	buffer.Write(noteBytes)
	binary.Write(buffer, binary.LittleEndian, sts)
	return buffer.Bytes()
}

func (cc *CoreConvert) makeRegInfo(regs []byte) {
	var phdr elf.Prog32

	phdr.Type = uint32(elf.PT_NOTE)
	phdr.Off = 0
	phdr.Vaddr = 0
	phdr.Paddr = 0
	phdr.Filesz = 0
	phdr.Memsz = 0
	phdr.Flags = 0
	phdr.Align = 4

	data := cc.makeRegData(regs)
	phdr.Filesz = uint32(len(data))

	cc.phdrs = append(cc.phdrs, &phdr)
	cc.data = append(cc.data, data)
}

func (cc *CoreConvert) setProgHdrOff() {
	off := binary.Size(cc.elfHdr)
	off += len(cc.phdrs) * binary.Size(cc.phdrs[0])

	for idx, phdr := range cc.phdrs {
		phdr.Off = uint32(off)
		off += len(cc.data[idx])
	}
}

func (cc *CoreConvert) Convert() error {
	if cc.Source == nil || cc.Target == nil {
		return util.NewNewtError("Missing file parameters")
	}

	err := cc.readHdr()
	if err != nil {
		return err
	}

	for {
		tlv, err := cc.readTlv()
		if err != nil {
			return err
		}
		if tlv == nil {
			break
		}
		data_buf := make([]byte, tlv.Len)
		cnt, err := cc.Source.Read(data_buf)
		if err != nil {
			return util.NewNewtError(fmt.Sprintf("Error reading: %s",
				err.Error()))
		}
		if cnt != int(tlv.Len) {
			return util.NewNewtError("Short file")
		}
		switch tlv.Type {
		case COREDUMP_TLV_MEM:
			cc.makeProgHdr(tlv.Off, data_buf)
		case COREDUMP_TLV_IMAGE:
			cc.ImageHash = data_buf
		case COREDUMP_TLV_REGS:
			if tlv.Len%4 != 0 {
				return util.NewNewtError("Invalid register area size")
			}
			cc.makeRegInfo(data_buf)
		default:
			return util.NewNewtError("Unknown TLV type")
		}
	}
	cc.makeElfHdr()
	if err != nil {
		return err
	}
	cc.setProgHdrOff()

	binary.Write(cc.Target, binary.LittleEndian, cc.elfHdr)
	for _, phdr := range cc.phdrs {
		binary.Write(cc.Target, binary.LittleEndian, phdr)
	}
	for _, data := range cc.data {
		cc.Target.Write(data)
	}
	return nil
}

func ConvertFilenames(srcFilename string,
	dstFilename string) (*CoreConvert, error) {

	coreConvert := NewCoreConvert()

	var err error

	coreConvert.Source, err = os.OpenFile(srcFilename, os.O_RDONLY, 0)
	if err != nil {
		return coreConvert, util.FmtNewtError("Cannot open file %s - %s",
			srcFilename, err.Error())
	}
	defer coreConvert.Source.Close()

	coreConvert.Target, err = os.OpenFile(dstFilename,
		os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
	if err != nil {
		return coreConvert, util.FmtNewtError("Cannot open file %s - %s",
			dstFilename, err.Error())
	}
	defer coreConvert.Target.Close()

	if err := coreConvert.Convert(); err != nil {
		return coreConvert, err
	}

	return coreConvert, nil
}
<commit_msg>newtmgr; expose CoreDumpHdr and CoreDumpTlv types.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package core

import (
	"bytes"
	"debug/elf"
	"encoding/binary"
	"fmt"
	"io"
	"os"

	"mynewt.apache.org/newt/util"
)

type CoreConvert struct {
	Source    *os.File
	Target    *os.File
	ImageHash []byte
	elfHdr    *elf.Header32
	phdrs     []*elf.Prog32
	data      [][]byte
}

const (
	COREDUMP_TLV_IMAGE = 1
	COREDUMP_TLV_MEM   = 2
	COREDUMP_TLV_REGS  = 3
)

const (
	COREDUMP_MAGIC = 0x690c47c3
)

type CoreDumpHdr struct {
	Magic uint32
	Size  uint32
}

type CoreDumpTlv struct {
	Type uint8
	pad  uint8
	Len  uint16
	Off  uint32
}

func NewCoreConvert() *CoreConvert {
	return &CoreConvert{}
}

func (cc *CoreConvert) readHdr() error {
	var hdr coreDumpHdr

	hdr_buf := make([]byte, binary.Size(hdr))
	if hdr_buf == nil {
		return util.NewNewtError("Out of memory")
	}

	cnt, err := cc.Source.Read(hdr_buf)
	if err != nil {
		return util.NewNewtError(fmt.Sprintf("Error reading: %s", err.Error()))
	}
	if cnt != binary.Size(hdr) {
		return util.NewNewtError("Short read")
	}

	hdr.Magic = binary.LittleEndian.Uint32(hdr_buf[0:4])
	hdr.Size = binary.LittleEndian.Uint32(hdr_buf[4:8])

	if hdr.Magic != COREDUMP_MAGIC {
		return util.NewNewtError("Source file is not corefile")
	}
	return nil
}

func (cc *CoreConvert) readTlv() (*coreDumpTlv, error) {
	var tlv coreDumpTlv

	tlv_buf := make([]byte, binary.Size(tlv))
	if tlv_buf == nil {
		return nil, util.NewNewtError("Out of memory")
	}

	cnt, err := cc.Source.Read(tlv_buf)
	if err == io.EOF {
		return nil, nil
	}
	if err != nil {
		return nil, util.NewNewtError(fmt.Sprintf("Error reading: %s",
			err.Error()))
	}
	if cnt == 0 {
		return nil, nil
	}
	if cnt != binary.Size(tlv) {
		return nil, util.NewNewtError("Short read")
	}

	tlv.Type = uint8(tlv_buf[0])
	tlv.pad = uint8(tlv_buf[1])
	tlv.Len = binary.LittleEndian.Uint16(tlv_buf[2:4])
	tlv.Off = binary.LittleEndian.Uint32(tlv_buf[4:8])

	return &tlv, nil
}

func (cc *CoreConvert) makeElfHdr() {
	var hdr elf.Header32
	var phdr elf.Prog32
	var shdr elf.Section32

	copy(hdr.Ident[:], elf.ELFMAG)
	hdr.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS32)
	hdr.Ident[elf.EI_DATA] = byte(elf.ELFDATA2LSB)
	hdr.Ident[elf.EI_VERSION] = byte(elf.EV_CURRENT)
	hdr.Ident[elf.EI_OSABI] = byte(elf.ELFOSABI_NONE)
	hdr.Ident[elf.EI_ABIVERSION] = 0
	hdr.Ident[elf.EI_PAD] = 0
	hdr.Type = uint16(elf.ET_CORE)
	hdr.Machine = uint16(elf.EM_ARM)
	hdr.Version = uint32(elf.EV_CURRENT)
	hdr.Entry = 0
	hdr.Phoff = uint32(binary.Size(hdr))
	hdr.Shoff = 0
	hdr.Flags = 0
	hdr.Ehsize = uint16(binary.Size(hdr))
	hdr.Phentsize = uint16(binary.Size(phdr))
	hdr.Phnum = uint16(len(cc.phdrs))
	hdr.Shentsize = uint16(binary.Size(shdr))
	hdr.Shnum = 0
	hdr.Shstrndx = uint16(elf.SHN_UNDEF)

	cc.elfHdr = &hdr
}

func (cc *CoreConvert) makeProgHdr(off uint32, mem []byte) {
	var phdr elf.Prog32

	memSz := uint32(len(mem))

	phdr.Type = uint32(elf.PT_LOAD)
	phdr.Off = 0 /* offset of data in file */
	phdr.Vaddr = off
	phdr.Paddr = 0
	phdr.Filesz = memSz
	phdr.Memsz = memSz
	phdr.Flags = uint32(elf.PF_R)
	phdr.Align = 4

	cc.phdrs = append(cc.phdrs, &phdr)
	if memSz%4 != 0 {
		pad := make([]byte, 4-memSz%4)
		mem = append(mem, pad...)
	}
	cc.data = append(cc.data, mem)
}

func (cc *CoreConvert) makeRegData(regs []byte) []byte {
	type Elf32_Note struct {
		Namesz uint32
		Descsz uint32
		Ntype  uint32
	}

	type Elf32_Prstatus struct {
		Dummy  [18]uint32
		Regs   [18]uint32
		Dummy2 uint32
	}

	var note Elf32_Note
	var sts Elf32_Prstatus

	idx := 0
	for off := 0; off < len(regs); off += 4 {
		reg := binary.LittleEndian.Uint32(regs[off : off+4])
		sts.Regs[idx] = reg
		idx++
		if idx >= 18 {
			break
		}
	}

	noteName := ".reg"
	noteLen := len(noteName) + 1
	if noteLen%4 != 0 {
		noteLen = noteLen + 4 - (noteLen % 4)
	}
	noteBytes := make([]byte, noteLen)
	copy(noteBytes[:], noteName)

	note.Namesz = uint32(len(noteName) + 1) /* include terminating '\0' */
	note.Descsz = uint32(binary.Size(sts))
	note.Ntype = uint32(elf.NT_PRSTATUS)

	buffer := new(bytes.Buffer)
	binary.Write(buffer, binary.LittleEndian, note)
	buffer.Write(noteBytes)
	binary.Write(buffer, binary.LittleEndian, sts)
	return buffer.Bytes()
}

func (cc *CoreConvert) makeRegInfo(regs []byte) {
	var phdr elf.Prog32

	phdr.Type = uint32(elf.PT_NOTE)
	phdr.Off = 0
	phdr.Vaddr = 0
	phdr.Paddr = 0
	phdr.Filesz = 0
	phdr.Memsz = 0
	phdr.Flags = 0
	phdr.Align = 4

	data := cc.makeRegData(regs)
	phdr.Filesz = uint32(len(data))

	cc.phdrs = append(cc.phdrs, &phdr)
	cc.data = append(cc.data, data)
}

func (cc *CoreConvert) setProgHdrOff() {
	off := binary.Size(cc.elfHdr)
	off += len(cc.phdrs) * binary.Size(cc.phdrs[0])

	for idx, phdr := range cc.phdrs {
		phdr.Off = uint32(off)
		off += len(cc.data[idx])
	}
}

func (cc *CoreConvert) Convert() error {
	if cc.Source == nil || cc.Target == nil {
		return util.NewNewtError("Missing file parameters")
	}

	err := cc.readHdr()
	if err != nil {
		return err
	}

	for {
		tlv, err := cc.readTlv()
		if err != nil {
			return err
		}
		if tlv == nil {
			break
		}
		data_buf := make([]byte, tlv.Len)
		cnt, err := cc.Source.Read(data_buf)
		if err != nil {
			return util.NewNewtError(fmt.Sprintf("Error reading: %s",
				err.Error()))
		}
		if cnt != int(tlv.Len) {
			return util.NewNewtError("Short file")
		}
		switch tlv.Type {
		case COREDUMP_TLV_MEM:
			cc.makeProgHdr(tlv.Off, data_buf)
		case COREDUMP_TLV_IMAGE:
			cc.ImageHash = data_buf
		case COREDUMP_TLV_REGS:
			if tlv.Len%4 != 0 {
				return util.NewNewtError("Invalid register area size")
			}
			cc.makeRegInfo(data_buf)
		default:
			return util.NewNewtError("Unknown TLV type")
		}
	}
	cc.makeElfHdr()
	if err != nil {
		return err
	}
	cc.setProgHdrOff()

	binary.Write(cc.Target, binary.LittleEndian, cc.elfHdr)
	for _, phdr := range cc.phdrs {
		binary.Write(cc.Target, binary.LittleEndian, phdr)
	}
	for _, data := range cc.data {
		cc.Target.Write(data)
	}
	return nil
}

func ConvertFilenames(srcFilename string,
	dstFilename string) (*CoreConvert, error) {

	coreConvert := NewCoreConvert()

	var err error

	coreConvert.Source, err = os.OpenFile(srcFilename, os.O_RDONLY, 0)
	if err != nil {
		return coreConvert, util.FmtNewtError("Cannot open file %s - %s",
			srcFilename, err.Error())
	}
	defer coreConvert.Source.Close()

	coreConvert.Target, err = os.OpenFile(dstFilename,
		os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
	if err != nil {
		return coreConvert, util.FmtNewtError("Cannot open file %s - %s",
			dstFilename, err.Error())
	}
	defer coreConvert.Target.Close()

	if err := coreConvert.Convert(); err != nil {
		return coreConvert, err
	}

	return coreConvert, nil
}
<|endoftext|>


<commit_before>package database

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

	"github.com/lib/pq"

	"github.com/seadsystem/Backend/DB/landingzone/constants"
	"github.com/seadsystem/Backend/DB/landingzone/decoders"
)

type DB struct {
	conn *sql.DB
}

func New() (DB, error) {
	conn, err := sql.Open("postgres", fmt.Sprintf("host=%s user=%s dbname=%s password=%s port=%d sslmode=disable", constants.DB_SOCKET, constants.DB_USER, constants.DB_NAME, constants.DB_PASSWORD, constants.DB_PORT))
	return DB{conn}, err
}

func (db DB) InsertRaw(database_channel <-chan decoders.SeadPacket) {
	// Infinite loop with no breaks.
	for {
		log.Println("Waiting for data...")
		data := <-database_channel // Wait for first piece of data before starting transaction
		log.Println("Got data.")

		// Begin transaction
		txn, err := db.conn.Begin()
		if err != nil {
			log.Fatal(err)
		}

		// Prepare statement
		stmt, err := txn.Prepare(pq.CopyIn("data_raw", "serial", "type", "data", "time"))
		if err != nil {
			log.Fatal(err)
		}

	Data_processing:
		for {
			// Process data
			scale := constants.Scale[data.Type]
			data_type := string(data.Type)
			interp_time := data.Timestamp
			peroid := Duration(data.Peroid * float64(time.Second))
			for _, element := range data.Data {
				_, err = stmt.Exec(data.Serial, data_type, float32(element)*scale, interp_time.Format(time.RFC3339))
				interp_time.Add(peroid)
				if err != nil {
					log.Println(err)
					break
				}
			}

			log.Println("Waiting for more data...")

			// Receive result of read
			select {
			case data = <-database_channel:
				log.Println("Got data.")
			case <-time.After(time.Second * constants.DB_TIME_LIMIT):
				log.Println("Transaction timed out.")
				break Data_processing
			}
		}

		log.Println("Closing off transaction...")

		// Flush buffer
		_, err = stmt.Exec()
		if err != nil {
			log.Fatal(err)
		}

		// Close prepared statement
		err = stmt.Close()
		if err != nil {
			log.Fatal(err)
		}

		// Commit transaction
		err = txn.Commit()
		if err != nil {
			log.Fatal(err)
		}

		log.Println("Transaction closed")
	}
}
<commit_msg>Fixed missspelling of Period<commit_after>package database

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

	"github.com/lib/pq"

	"github.com/seadsystem/Backend/DB/landingzone/constants"
	"github.com/seadsystem/Backend/DB/landingzone/decoders"
)

type DB struct {
	conn *sql.DB
}

func New() (DB, error) {
	conn, err := sql.Open("postgres", fmt.Sprintf("host=%s user=%s dbname=%s password=%s port=%d sslmode=disable", constants.DB_SOCKET, constants.DB_USER, constants.DB_NAME, constants.DB_PASSWORD, constants.DB_PORT))
	return DB{conn}, err
}

func (db DB) InsertRaw(database_channel <-chan decoders.SeadPacket) {
	// Infinite loop with no breaks.
	for {
		log.Println("Waiting for data...")
		data := <-database_channel // Wait for first piece of data before starting transaction
		log.Println("Got data.")

		// Begin transaction
		txn, err := db.conn.Begin()
		if err != nil {
			log.Fatal(err)
		}

		// Prepare statement
		stmt, err := txn.Prepare(pq.CopyIn("data_raw", "serial", "type", "data", "time"))
		if err != nil {
			log.Fatal(err)
		}

	Data_processing:
		for {
			// Process data
			scale := constants.Scale[data.Type]
			data_type := string(data.Type)
			interp_time := data.Timestamp
			period := Duration(data.Period * float64(time.Second))
			for _, element := range data.Data {
				_, err = stmt.Exec(data.Serial, data_type, float32(element)*scale, interp_time.Format(time.RFC3339))
				interp_time.Add(period)
				if err != nil {
					log.Println(err)
					break
				}
			}

			log.Println("Waiting for more data...")

			// Receive result of read
			select {
			case data = <-database_channel:
				log.Println("Got data.")
			case <-time.After(time.Second * constants.DB_TIME_LIMIT):
				log.Println("Transaction timed out.")
				break Data_processing
			}
		}

		log.Println("Closing off transaction...")

		// Flush buffer
		_, err = stmt.Exec()
		if err != nil {
			log.Fatal(err)
		}

		// Close prepared statement
		err = stmt.Close()
		if err != nil {
			log.Fatal(err)
		}

		// Commit transaction
		err = txn.Commit()
		if err != nil {
			log.Fatal(err)
		}

		log.Println("Transaction closed")
	}
}
<|endoftext|>