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

// +build darwin freebsd linux netbsd openbsd windows

package os

import (
	"runtime"
	"syscall"
)

type UnixSignal int32

func (sig UnixSignal) String() string {
	s := runtime.Signame(int32(sig))
	if len(s) > 0 {
		return s
	}
	return "UnixSignal"
}

// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
// StartProcess is a low-level interface. The exec package provides
// higher-level interfaces.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
	sysattr := &syscall.ProcAttr{
		Dir: attr.Dir,
		Env: attr.Env,
		Sys: attr.Sys,
	}
	if sysattr.Env == nil {
		sysattr.Env = Environ()
	}
	for _, f := range attr.Files {
		sysattr.Files = append(sysattr.Files, f.Fd())
	}

	pid, h, e := syscall.StartProcess(name, argv, sysattr)
	if e != nil {
		return nil, &PathError{"fork/exec", name, e}
	}
	return newProcess(pid, h), nil
}

// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
	return p.Signal(SIGKILL)
}

// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns.  If it fails, it returns an error.
//
// To run a child process, see StartProcess (for a low-level interface)
// or the exec package (for higher-level interfaces).
func Exec(name string, argv []string, envv []string) error {
	if envv == nil {
		envv = Environ()
	}
	e := syscall.Exec(name, argv, envv)
	if e != nil {
		return &PathError{"exec", name, e}
	}
	return nil
}

// TODO(rsc): Should os implement its own syscall.WaitStatus
// wrapper with the methods, or is exposing the underlying one enough?
//
// TODO(rsc): Certainly need to have Rusage struct,
// since syscall one might have different field types across
// different OS.

// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg struct {
	Pid                int             // The process's id.
	syscall.WaitStatus                 // System-dependent status info.
	Rusage             *syscall.Rusage // System-dependent resource usage info.
}

// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err error) {
	p, e := FindProcess(pid)
	if e != nil {
		return nil, e
	}
	defer p.Release()
	return p.Wait(options)
}

// Convert i to decimal string.
func itod(i int) string {
	if i == 0 {
		return "0"
	}

	u := uint64(i)
	if i < 0 {
		u = -u
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; u > 0; u /= 10 {
		bp--
		b[bp] = byte(u%10) + '0'
	}

	if i < 0 {
		bp--
		b[bp] = '-'
	}

	return string(b[bp:])
}

func (w *Waitmsg) String() string {
	if w == nil {
		return "<nil>"
	}
	// TODO(austin) Use signal names when possible?
	res := ""
	switch {
	case w.Exited():
		res = "exit status " + itod(w.ExitStatus())
	case w.Signaled():
		res = "signal " + itod(w.Signal())
	case w.Stopped():
		res = "stop signal " + itod(w.StopSignal())
		if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
			res += " (trap " + itod(w.TrapCause()) + ")"
		}
	case w.Continued():
		res = "continued"
	}
	if w.CoreDump() {
		res += " (core dumped)"
	}
	return res
}
<commit_msg>os: update package location of exec to os/exec in comments<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd linux netbsd openbsd windows

package os

import (
	"runtime"
	"syscall"
)

type UnixSignal int32

func (sig UnixSignal) String() string {
	s := runtime.Signame(int32(sig))
	if len(s) > 0 {
		return s
	}
	return "UnixSignal"
}

// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
	sysattr := &syscall.ProcAttr{
		Dir: attr.Dir,
		Env: attr.Env,
		Sys: attr.Sys,
	}
	if sysattr.Env == nil {
		sysattr.Env = Environ()
	}
	for _, f := range attr.Files {
		sysattr.Files = append(sysattr.Files, f.Fd())
	}

	pid, h, e := syscall.StartProcess(name, argv, sysattr)
	if e != nil {
		return nil, &PathError{"fork/exec", name, e}
	}
	return newProcess(pid, h), nil
}

// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
	return p.Signal(SIGKILL)
}

// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns.  If it fails, it returns an error.
//
// To run a child process, see StartProcess (for a low-level interface)
// or the os/exec package (for higher-level interfaces).
func Exec(name string, argv []string, envv []string) error {
	if envv == nil {
		envv = Environ()
	}
	e := syscall.Exec(name, argv, envv)
	if e != nil {
		return &PathError{"exec", name, e}
	}
	return nil
}

// TODO(rsc): Should os implement its own syscall.WaitStatus
// wrapper with the methods, or is exposing the underlying one enough?
//
// TODO(rsc): Certainly need to have Rusage struct,
// since syscall one might have different field types across
// different OS.

// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg struct {
	Pid                int             // The process's id.
	syscall.WaitStatus                 // System-dependent status info.
	Rusage             *syscall.Rusage // System-dependent resource usage info.
}

// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err error) {
	p, e := FindProcess(pid)
	if e != nil {
		return nil, e
	}
	defer p.Release()
	return p.Wait(options)
}

// Convert i to decimal string.
func itod(i int) string {
	if i == 0 {
		return "0"
	}

	u := uint64(i)
	if i < 0 {
		u = -u
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; u > 0; u /= 10 {
		bp--
		b[bp] = byte(u%10) + '0'
	}

	if i < 0 {
		bp--
		b[bp] = '-'
	}

	return string(b[bp:])
}

func (w *Waitmsg) String() string {
	if w == nil {
		return "<nil>"
	}
	// TODO(austin) Use signal names when possible?
	res := ""
	switch {
	case w.Exited():
		res = "exit status " + itod(w.ExitStatus())
	case w.Signaled():
		res = "signal " + itod(w.Signal())
	case w.Stopped():
		res = "stop signal " + itod(w.StopSignal())
		if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
			res += " (trap " + itod(w.TrapCause()) + ")"
		}
	case w.Continued():
		res = "continued"
	}
	if w.CoreDump() {
		res += " (core dumped)"
	}
	return res
}
<|endoftext|>


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

/*
	Package unsafe contains operations that step around the type safety of Go programs.
*/
package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package.  It represents the type of an arbitrary Go expression.
type ArbitraryType int

// Pointer represents a pointer to an arbitrary type.  There are three special operations
// available for type Pointer that are not available for other types.
//	1) A pointer value of any type can be converted to a Pointer.
//	2) A Pointer can be converted to a pointer value of any type.
//	3) A uintptr can be converted to a Pointer.
//	4) A Pointer can be converted to a uintptr.
// Pointer therefore allows a program to defeat the type system and read and write
// arbitrary memory. It should be used with extreme care.
type Pointer *ArbitraryType

// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
// "top level" of the value only.  For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
func Sizeof(v ArbitraryType) uintptr

// Offsetof returns the offset within the struct of the field represented by v,
// which must be of the form structValue.field.  In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
func Offsetof(v ArbitraryType) uintptr

// Alignof returns the alignment of the value v.  It is the maximum value m such
// that the address of a variable with the type of v will always be zero mod m.
// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) uintptr
<commit_msg>unsafe: fix a typo<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package unsafe contains operations that step around the type safety of Go programs.
*/
package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package.  It represents the type of an arbitrary Go expression.
type ArbitraryType int

// Pointer represents a pointer to an arbitrary type.  There are four special operations
// available for type Pointer that are not available for other types.
//	1) A pointer value of any type can be converted to a Pointer.
//	2) A Pointer can be converted to a pointer value of any type.
//	3) A uintptr can be converted to a Pointer.
//	4) A Pointer can be converted to a uintptr.
// Pointer therefore allows a program to defeat the type system and read and write
// arbitrary memory. It should be used with extreme care.
type Pointer *ArbitraryType

// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
// "top level" of the value only.  For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
func Sizeof(v ArbitraryType) uintptr

// Offsetof returns the offset within the struct of the field represented by v,
// which must be of the form structValue.field.  In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
func Offsetof(v ArbitraryType) uintptr

// Alignof returns the alignment of the value v.  It is the maximum value m such
// that the address of a variable with the type of v will always be zero mod m.
// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) uintptr
<|endoftext|>


<commit_before>// Copyright (c) 2012-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package statsd

import (
	"fmt"
	"regexp"
)

type ValidatorFunc func(string) error

var safeName = regexp.MustCompile(`^[a-zA-Z0-9\-_.]+$`)

// A stat name validator function. This function may be used to validate
// whether a stat name contains invalid characters. If invalid
// characters are found, the function will return an error.
func SafeNameValidator(stat string) error {
	if !safeName.MatchString(stat) {
		return fmt.Errorf("invalid stat name: %s", stat)
	}
	return nil
}
<commit_msg>fix comment and rename validator<commit_after>// Copyright (c) 2012-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package statsd

import (
	"fmt"
	"regexp"
)

type ValidatorFunc func(string) error

var safeName = regexp.MustCompile(`^[a-zA-Z0-9\-_.]+$`)

// CheckName may be used to validate whether a stat name contains invalid
// characters. If invalid characters are found, the function will return an
// error.
func CheckName(stat string) error {
	if !safeName.MatchString(stat) {
		return fmt.Errorf("invalid stat name: %s", stat)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net"
	"sync"
	"time"

	"encoding/json"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	pconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/coreos/go-etcd/etcd"
	"github.com/skynetservices/skydns/msg"
)

// The periodic interval for checking the state of things.
const syncInterval = 5 * time.Second

type KubernetesSync struct {
	mu         sync.Mutex // protects serviceMap
	serviceMap map[string]*serviceInfo
	eclient    *etcd.Client
}

func NewKubernetesSync(client *etcd.Client) *KubernetesSync {
	ks := &KubernetesSync{
		serviceMap: make(map[string]*serviceInfo),
		eclient:    client,
	}
	return ks
}

// This is a belt-and-suspenders loop that periodically
// addes the records in the local cache of Kubernetes
// services to the skydns repository to prevent them
// from expiring.
func (ksync *KubernetesSync) SyncLoop() {
	for {
		select {
		case <-time.After(syncInterval):
			log.Println("periodic sync")
			ksync.ensureDNS()
		}
	}
}

// Ensure that dns records exist for all services.
// This seems a bit redundant. TBD - remove?
func (ksync *KubernetesSync) ensureDNS() {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	for name, info := range ksync.serviceMap {
		err := ksync.addDNS(name, info)
		if err != nil {
			log.Println("failed to ensure dns for %q: %s", name, err)
		}
	}
}

// OnUpdate manages the active set of service records.
// Active service records get ttl bumps if found in the update set or
// removed if missing from the update set.
func (ksync *KubernetesSync) OnUpdate(services []api.Service) {
	activeServices := util.StringSet{}
	for _, service := range services {
		activeServices.Insert(service.Name)
		info, exists := ksync.getServiceInfo(service.Name)
		serviceIP := net.ParseIP(service.PortalIP)
		if exists && (info.portalPort != service.Port || !info.portalIP.Equal(serviceIP)) {
			err := ksync.removeDNS(service.Name, info)
			if err != nil {
				log.Printf("failed to remove dns for %q: %s\n", service.Name, err)
			}
		}
		log.Printf("adding new service %q at %s:%d/%s (local :%d)\n", service.Name, serviceIP, service.Port, service.Protocol, service.ProxyPort)
		si := &serviceInfo{
			proxyPort: service.ProxyPort,
			protocol:  service.Protocol,
			active:    true,
		}
		ksync.setServiceInfo(service.Name, si)
		si.portalIP = serviceIP
		si.portalPort = service.Port
		err := ksync.addDNS(service.Name, si)
		if err != nil {
			log.Println("failed to add dns %q: %s", service.Name, err)
		}
	}
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	for name, info := range ksync.serviceMap {
		if !activeServices.Has(name) {
			err := ksync.removeDNS(name, info)
			if err != nil {
				log.Println("failed to remove dns for %q: %s", name, err)
			}
			delete(ksync.serviceMap, name)
		}
	}
}

func (ksync *KubernetesSync) getServiceInfo(service string) (*serviceInfo, bool) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	info, ok := ksync.serviceMap[service]
	return info, ok
}

func (ksync *KubernetesSync) setServiceInfo(service string, info *serviceInfo) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	ksync.serviceMap[service] = info
}

func (ksync *KubernetesSync) removeDNS(service string, info *serviceInfo) error {
	record := service + "." + config.Domain
	// Remove from SkyDNS registration
	log.Printf("removing %s from DNS", record)
	_, err := ksync.eclient.Delete(msg.Path(record), true)
	return err
}

func (ksync *KubernetesSync) addDNS(service string, info *serviceInfo) error {
	// ADD to SkyDNS registry
	svc := msg.Service{
		Host:     info.portalIP.String(),
		Port:     info.portalPort,
		Priority: 10,
		Weight:   10,
		Ttl:      30,
	}
	b, err := json.Marshal(svc)
	record := service + "." + config.Domain
	//Set with no TTL, and hope that kubernetes events are accurate.
	//TODO(BJK) Think this through a little more

	log.Printf("setting dns record: %v\n", record)
	_, err = ksync.eclient.Set(msg.Path(record), string(b), uint64(0))
	return err
}

type serviceInfo struct {
	portalIP   net.IP
	portalPort int
	protocol   api.Protocol
	proxyPort  int
	mu         sync.Mutex // protects active
	active     bool
}

func init() {
	client.BindClientConfigFlags(flag.CommandLine, clientConfig)
}

func WatchKubernetes(eclient *etcd.Client) {
	serviceConfig := pconfig.NewServiceConfig()
	endpointsConfig := pconfig.NewEndpointsConfig()
	/*
		// disable API requests for now due to namespace bug in k8s
		// api.  Re-enable when bug is fixed, api is best long term
		// communnication channel
		// define api config source
		if clientConfig.Host != "" {
			log.Println("using api calls to get Kubernetes config %v", clientConfig.Host)
			client, err := client.New(clientConfig)
			if err != nil {
				log.Fatalf("Kubernetes requested, but received invalid API configuration: %v", err)
			}
			pconfig.NewSourceAPI(
				client,
				30*time.Second,
				serviceConfig.Channel("api"),
				endpointsConfig.Channel("api"),
			)
		}
	*/

	pconfig.NewConfigSourceEtcd(eclient,
		serviceConfig.Channel("etcd"),
		endpointsConfig.Channel("etcd"))

	ks := NewKubernetesSync(eclient)
	// Wire skydns to handle changes to services
	serviceConfig.RegisterHandler(ks)
	ks.SyncLoop()
}
<commit_msg>change kubernetes client to use k8s api at master after breaking kubernetes API change<commit_after>package main

import (
	"flag"
	"log"
	"net"
	"sync"
	"time"

	"encoding/json"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	pconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/coreos/go-etcd/etcd"
	"github.com/skynetservices/skydns/msg"
)

// The periodic interval for checking the state of things.
const syncInterval = 5 * time.Second

type KubernetesSync struct {
	mu         sync.Mutex // protects serviceMap
	serviceMap map[string]*serviceInfo
	eclient    *etcd.Client
}

func NewKubernetesSync(client *etcd.Client) *KubernetesSync {
	ks := &KubernetesSync{
		serviceMap: make(map[string]*serviceInfo),
		eclient:    client,
	}
	return ks
}

// OnUpdate manages the active set of service records.
// Active service records get ttl bumps if found in the update set or
// removed if missing from the update set.
func (ksync *KubernetesSync) OnUpdate(services []api.Service) {
	activeServices := util.StringSet{}
	for _, service := range services {
		activeServices.Insert(service.Name)
		info, exists := ksync.getServiceInfo(service.Name)
		serviceIP := net.ParseIP(service.PortalIP)
		if exists && (info.portalPort != service.Port || !info.portalIP.Equal(serviceIP)) {
			err := ksync.removeDNS(service.Name, info)
			if err != nil {
				log.Printf("failed to remove dns for %q: %s\n", service.Name, err)
			}
		}
		log.Printf("adding new service %q at %s:%d/%s (local :%d)\n", service.Name, serviceIP, service.Port, service.Protocol, service.ProxyPort)
		si := &serviceInfo{
			proxyPort: service.ProxyPort,
			protocol:  service.Protocol,
			active:    true,
		}
		ksync.setServiceInfo(service.Name, si)
		si.portalIP = serviceIP
		si.portalPort = service.Port
		err := ksync.addDNS(service.Name, si)
		if err != nil {
			log.Println("failed to add dns %q: %s", service.Name, err)
		}
	}
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	for name, info := range ksync.serviceMap {
		if !activeServices.Has(name) {
			err := ksync.removeDNS(name, info)
			if err != nil {
				log.Println("failed to remove dns for %q: %s", name, err)
			}
			delete(ksync.serviceMap, name)
		}
	}
}

func (ksync *KubernetesSync) getServiceInfo(service string) (*serviceInfo, bool) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	info, ok := ksync.serviceMap[service]
	return info, ok
}

func (ksync *KubernetesSync) setServiceInfo(service string, info *serviceInfo) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	ksync.serviceMap[service] = info
}

func (ksync *KubernetesSync) removeDNS(service string, info *serviceInfo) error {
	record := service + "." + config.Domain
	// Remove from SkyDNS registration
	log.Printf("removing %s from DNS", record)
	_, err := ksync.eclient.Delete(msg.Path(record), true)
	return err
}

func (ksync *KubernetesSync) addDNS(service string, info *serviceInfo) error {
	// ADD to SkyDNS registry
	svc := msg.Service{
		Host:     info.portalIP.String(),
		Port:     info.portalPort,
		Priority: 10,
		Weight:   10,
		Ttl:      30,
	}
	b, err := json.Marshal(svc)
	record := service + "." + config.Domain
	//Set with no TTL, and hope that kubernetes events are accurate.

	log.Printf("setting dns record: %v\n", record)
	_, err = ksync.eclient.Set(msg.Path(record), string(b), uint64(0))
	return err
}

type serviceInfo struct {
	portalIP   net.IP
	portalPort int
	protocol   api.Protocol
	proxyPort  int
	mu         sync.Mutex // protects active
	active     bool
}

func init() {
	client.BindClientConfigFlags(flag.CommandLine, clientConfig)
}

func WatchKubernetes(eclient *etcd.Client) {
	serviceConfig := pconfig.NewServiceConfig()
	endpointsConfig := pconfig.NewEndpointsConfig()

	if clientConfig.Host != "" {
		log.Printf("using api calls to get Kubernetes config %v\n", clientConfig.Host)
		client, err := client.New(clientConfig)
		if err != nil {
			log.Fatalf("Kubernetes requested, but received invalid API configuration: %v", err)
		}
		pconfig.NewSourceAPI(
			client.Services(api.NamespaceAll),
			client.Endpoints(api.NamespaceAll),
			syncInterval,
			serviceConfig.Channel("api"),
			endpointsConfig.Channel("api"),
		)
	}

	ks := NewKubernetesSync(eclient)
	// Wire skydns to handle changes to services
	serviceConfig.RegisterHandler(ks)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net"
	"sync"
	"time"

	"encoding/json"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	pconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/coreos/go-etcd/etcd"
	"github.com/skynetservices/skydns/msg"
)

// The periodic interval for checking the state of things.
const syncInterval = 5 * time.Second

type KubernetesSync struct {
	mu         sync.Mutex // protects serviceMap
	serviceMap map[string]*serviceInfo
	eclient    *etcd.Client
}

func NewKubernetesSync(client *etcd.Client) *KubernetesSync {
	ks := &KubernetesSync{
		serviceMap: make(map[string]*serviceInfo),
		eclient:    client,
	}
	return ks
}

// OnUpdate manages the active set of service records.
// Active service records get ttl bumps if found in the update set or
// removed if missing from the update set.
func (ksync *KubernetesSync) OnUpdate(services []api.Service) {
	activeServices := util.StringSet{}
	for _, service := range services {
		activeServices.Insert(service.Name)
		info, exists := ksync.getServiceInfo(service.Name)
		serviceIP := net.ParseIP(service.PortalIP)
		if exists && (info.portalPort != service.Port || !info.portalIP.Equal(serviceIP)) {
			err := ksync.removeDNS(service.Name, info)
			if err != nil {
				log.Printf("failed to remove dns for %q: %s\n", service.Name, err)
			}
		}
		log.Printf("adding new service %q at %s:%d/%s (local :%d)\n", service.Name, serviceIP, service.Port, service.Protocol, service.ProxyPort)
		si := &serviceInfo{
			proxyPort: service.ProxyPort,
			protocol:  service.Protocol,
			active:    true,
		}
		ksync.setServiceInfo(service.Name, si)
		si.portalIP = serviceIP
		si.portalPort = service.Port
		err := ksync.addDNS(service.Name, si)
		if err != nil {
			log.Println("failed to add dns %q: %s", service.Name, err)
		}
	}
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	for name, info := range ksync.serviceMap {
		if !activeServices.Has(name) {
			err := ksync.removeDNS(name, info)
			if err != nil {
				log.Println("failed to remove dns for %q: %s", name, err)
			}
			delete(ksync.serviceMap, name)
		}
	}
}

func (ksync *KubernetesSync) getServiceInfo(service string) (*serviceInfo, bool) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	info, ok := ksync.serviceMap[service]
	return info, ok
}

func (ksync *KubernetesSync) setServiceInfo(service string, info *serviceInfo) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	ksync.serviceMap[service] = info
}

func (ksync *KubernetesSync) removeDNS(service string, info *serviceInfo) error {
	record := service + "." + config.Domain
	// Remove from SkyDNS registration
	log.Printf("removing %s from DNS", record)
	_, err := ksync.eclient.Delete(msg.Path(record), true)
	return err
}

func (ksync *KubernetesSync) addDNS(service string, info *serviceInfo) error {
	// ADD to SkyDNS registry
	svc := msg.Service{
		Host:     info.portalIP.String(),
		Port:     info.portalPort,
		Priority: 10,
		Weight:   10,
		Ttl:      30,
	}
	b, err := json.Marshal(svc)
	record := service + "." + config.Domain
	//Set with no TTL, and hope that kubernetes events are accurate.

	log.Printf("setting dns record: %v\n", record)
	_, err = ksync.eclient.Set(msg.Path(record), string(b), uint64(0))
	return err
}

type serviceInfo struct {
	portalIP   net.IP
	portalPort int
	protocol   api.Protocol
	proxyPort  int
	mu         sync.Mutex // protects active
	active     bool
}

func init() {
	client.BindClientConfigFlags(flag.CommandLine, clientConfig)
}

func WatchKubernetes(eclient *etcd.Client) {
	serviceConfig := pconfig.NewServiceConfig()
	endpointsConfig := pconfig.NewEndpointsConfig()

	if clientConfig.Host != "" {
		log.Printf("using api calls to get Kubernetes config %v\n", clientConfig.Host)
		client, err := client.New(clientConfig)
		if err != nil {
			log.Fatalf("Kubernetes requested, but received invalid API configuration: %v", err)
		}
		pconfig.NewSourceAPI(
			client.Services(api.NamespaceAll),
			client.Endpoints(api.NamespaceAll),
			syncInterval,
			serviceConfig.Channel("api"),
			endpointsConfig.Channel("api"),
		)
	}

	ks := NewKubernetesSync(eclient)
	// Wire skydns to handle changes to services
	serviceConfig.RegisterHandler(ks)
}
<commit_msg>fix kubernetes build at master - service now has ObjectMeta and ServiceSpec embedded types<commit_after>package main

import (
	"flag"
	"log"
	"net"
	"sync"
	"time"

	"encoding/json"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	pconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/coreos/go-etcd/etcd"
	"github.com/skynetservices/skydns/msg"
)

// The periodic interval for checking the state of things.
const syncInterval = 5 * time.Second

type KubernetesSync struct {
	mu         sync.Mutex // protects serviceMap
	serviceMap map[string]*serviceInfo
	eclient    *etcd.Client
}

func NewKubernetesSync(client *etcd.Client) *KubernetesSync {
	ks := &KubernetesSync{
		serviceMap: make(map[string]*serviceInfo),
		eclient:    client,
	}
	return ks
}

// OnUpdate manages the active set of service records.
// Active service records get ttl bumps if found in the update set or
// removed if missing from the update set.
func (ksync *KubernetesSync) OnUpdate(services []api.Service) {
	activeServices := util.StringSet{}
	for _, service := range services {
		activeServices.Insert(service.Name)
		info, exists := ksync.getServiceInfo(service.ObjectMeta.Name)
		serviceIP := net.ParseIP(service.Spec.PortalIP)
		if exists && (info.portalPort != service.Spec.Port || !info.portalIP.Equal(serviceIP)) {
			err := ksync.removeDNS(service.ObjectMeta.Name, info)
			if err != nil {
				log.Printf("failed to remove dns for %q: %s\n", service.ObjectMeta.Name, err)
			}
		}
		log.Printf("adding new service %q at %s:%d/%s (local :%d)\n", service.ObjectMeta.Name, serviceIP, service.Spec.Port, service.Spec.Protocol, service.Spec.ProxyPort)
		si := &serviceInfo{
			proxyPort: service.Spec.ProxyPort,
			protocol:  service.Spec.Protocol,
			active:    true,
		}
		ksync.setServiceInfo(service.ObjectMeta.Name, si)
		si.portalIP = serviceIP
		si.portalPort = service.Spec.Port
		err := ksync.addDNS(service.ObjectMeta.Name, si)
		if err != nil {
			log.Println("failed to add dns %q: %s", service.ObjectMeta.Name, err)
		}
	}
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	for name, info := range ksync.serviceMap {
		if !activeServices.Has(name) {
			err := ksync.removeDNS(name, info)
			if err != nil {
				log.Println("failed to remove dns for %q: %s", name, err)
			}
			delete(ksync.serviceMap, name)
		}
	}
}

func (ksync *KubernetesSync) getServiceInfo(service string) (*serviceInfo, bool) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	info, ok := ksync.serviceMap[service]
	return info, ok
}

func (ksync *KubernetesSync) setServiceInfo(service string, info *serviceInfo) {
	ksync.mu.Lock()
	defer ksync.mu.Unlock()
	ksync.serviceMap[service] = info
}

func (ksync *KubernetesSync) removeDNS(service string, info *serviceInfo) error {
	record := service + "." + config.Domain
	// Remove from SkyDNS registration
	log.Printf("removing %s from DNS", record)
	_, err := ksync.eclient.Delete(msg.Path(record), true)
	return err
}

func (ksync *KubernetesSync) addDNS(service string, info *serviceInfo) error {
	// ADD to SkyDNS registry
	svc := msg.Service{
		Host:     info.portalIP.String(),
		Port:     info.portalPort,
		Priority: 10,
		Weight:   10,
		Ttl:      30,
	}
	b, err := json.Marshal(svc)
	record := service + "." + config.Domain
	//Set with no TTL, and hope that kubernetes events are accurate.

	log.Printf("setting dns record: %v\n", record)
	_, err = ksync.eclient.Set(msg.Path(record), string(b), uint64(0))
	return err
}

type serviceInfo struct {
	portalIP   net.IP
	portalPort int
	protocol   api.Protocol
	proxyPort  int
	mu         sync.Mutex // protects active
	active     bool
}

func init() {
	client.BindClientConfigFlags(flag.CommandLine, clientConfig)
}

func WatchKubernetes(eclient *etcd.Client) {
	serviceConfig := pconfig.NewServiceConfig()
	endpointsConfig := pconfig.NewEndpointsConfig()

	if clientConfig.Host != "" {
		log.Printf("using api calls to get Kubernetes config %v\n", clientConfig.Host)
		client, err := client.New(clientConfig)
		if err != nil {
			log.Fatalf("Kubernetes requested, but received invalid API configuration: %v", err)
		}
		pconfig.NewSourceAPI(
			client.Services(api.NamespaceAll),
			client.Endpoints(api.NamespaceAll),
			syncInterval,
			serviceConfig.Channel("api"),
			endpointsConfig.Channel("api"),
		)
	}

	ks := NewKubernetesSync(eclient)
	// Wire skydns to handle changes to services
	serviceConfig.RegisterHandler(ks)
}
<|endoftext|>


<commit_before>package server_details

import (
	"fmt"
	"net"
	"strconv"

	"github.com/hashicorp/serf/serf"
)

// Key is used in maps and for equality tests.  A key is based on endpoints.
type Key struct {
	Datacenter string
	Port       int
	AddrString string
}

// Equal compares two Key objects
func (k *Key) Equal(x *Key) bool {
	return k.Datacenter == x.Datacenter &&
		k.Port == x.Port &&
		k.AddrString == x.AddrString
}

// ServerDetails is used to return details of a consul server
type ServerDetails struct {
	Name       string
	Datacenter string
	Port       int
	Bootstrap  bool
	Expect     int
	Version    int
	Addr       net.Addr
}

// Key returns the corresponding Key
func (s *ServerDetails) Key() *Key {
	var serverAddr string
	if s.Addr != nil {
		serverAddr = s.Addr.String() + s.Addr.Network()
	}
	return &Key{
		Datacenter: s.Datacenter,
		Port:       s.Port,
		AddrString: serverAddr,
	}
}

// String returns a string representation of ServerDetails
func (s *ServerDetails) String() string {
	var addrStr, networkStr string
	if s.Addr != nil {
		addrStr = s.Addr.String()
		networkStr = s.Addr.Network()
	}

	return fmt.Sprintf("%s (Addr: %s/%s) (DC: %s)", s.Name, addrStr, networkStr, s.Datacenter)
}

// IsConsulServer returns true if a serf member is a consul server. Returns a
// bool and a pointer to the ServerDetails.
func IsConsulServer(m serf.Member) (bool, *ServerDetails) {
	if m.Tags["role"] != "consul" {
		return false, nil
	}

	datacenter := m.Tags["dc"]
	_, bootstrap := m.Tags["bootstrap"]

	expect := 0
	expect_str, ok := m.Tags["expect"]
	var err error
	if ok {
		expect, err = strconv.Atoi(expect_str)
		if err != nil {
			return false, nil
		}
	}

	port_str := m.Tags["port"]
	port, err := strconv.Atoi(port_str)
	if err != nil {
		return false, nil
	}

	vsn_str := m.Tags["vsn"]
	vsn, err := strconv.Atoi(vsn_str)
	if err != nil {
		return false, nil
	}

	addr := &net.TCPAddr{IP: m.Addr, Port: port}

	parts := &ServerDetails{
		Name:       m.Name,
		Datacenter: datacenter,
		Port:       port,
		Bootstrap:  bootstrap,
		Expect:     expect,
		Addr:       addr,
		Version:    vsn,
	}
	return true, parts
}
<commit_msg>Switch the order of ServerDetails.String()<commit_after>package server_details

import (
	"fmt"
	"net"
	"strconv"

	"github.com/hashicorp/serf/serf"
)

// Key is used in maps and for equality tests.  A key is based on endpoints.
type Key struct {
	Datacenter string
	Port       int
	AddrString string
}

// Equal compares two Key objects
func (k *Key) Equal(x *Key) bool {
	return k.Datacenter == x.Datacenter &&
		k.Port == x.Port &&
		k.AddrString == x.AddrString
}

// ServerDetails is used to return details of a consul server
type ServerDetails struct {
	Name       string
	Datacenter string
	Port       int
	Bootstrap  bool
	Expect     int
	Version    int
	Addr       net.Addr
}

// Key returns the corresponding Key
func (s *ServerDetails) Key() *Key {
	var serverAddr string
	if s.Addr != nil {
		serverAddr = s.Addr.String() + s.Addr.Network()
	}
	return &Key{
		Datacenter: s.Datacenter,
		Port:       s.Port,
		AddrString: serverAddr,
	}
}

// String returns a string representation of ServerDetails
func (s *ServerDetails) String() string {
	var addrStr, networkStr string
	if s.Addr != nil {
		addrStr = s.Addr.String()
		networkStr = s.Addr.Network()
	}

	return fmt.Sprintf("%s (Addr: %s/%s) (DC: %s)", s.Name, networkStr, addrStr, s.Datacenter)
}

// IsConsulServer returns true if a serf member is a consul server. Returns a
// bool and a pointer to the ServerDetails.
func IsConsulServer(m serf.Member) (bool, *ServerDetails) {
	if m.Tags["role"] != "consul" {
		return false, nil
	}

	datacenter := m.Tags["dc"]
	_, bootstrap := m.Tags["bootstrap"]

	expect := 0
	expect_str, ok := m.Tags["expect"]
	var err error
	if ok {
		expect, err = strconv.Atoi(expect_str)
		if err != nil {
			return false, nil
		}
	}

	port_str := m.Tags["port"]
	port, err := strconv.Atoi(port_str)
	if err != nil {
		return false, nil
	}

	vsn_str := m.Tags["vsn"]
	vsn, err := strconv.Atoi(vsn_str)
	if err != nil {
		return false, nil
	}

	addr := &net.TCPAddr{IP: m.Addr, Port: port}

	parts := &ServerDetails{
		Name:       m.Name,
		Datacenter: datacenter,
		Port:       port,
		Bootstrap:  bootstrap,
		Expect:     expect,
		Addr:       addr,
		Version:    vsn,
	}
	return true, parts
}
<|endoftext|>


<commit_before>package maintenance

import (
	"os"
	"strconv"

	"github.com/HouzuoGuo/laitos/misc"
	"github.com/HouzuoGuo/laitos/platform/procexp"
	"github.com/prometheus/client_golang/prometheus"
)

const (
	// PrometheusProcessIDLabel is the name of data label given to process explorer metrics registered with prometheus.
	// The label data shall be the PID of this program.
	PrometheusProcessIDLabel = "pid"
)

// ProcessExplorerMetrics are the collection of program performance metrics registered with prometheus
// The measurements are taken from process status and statistics exposed by procfs (a Linux OS feature).
type ProcessExplorerMetrics struct {
	numUserModeSecInclChildren   *prometheus.GaugeVec
	numKernelModeSecInclChildren *prometheus.GaugeVec
	numRunSec                    *prometheus.GaugeVec
	numWaitSec                   *prometheus.GaugeVec
	numVoluntarySwitches         *prometheus.GaugeVec
	numInvoluntarySwitches       *prometheus.GaugeVec
}

// NewProcessExplorerMetrics creates a new ProcessExplorerMetrics with all of its metrics collectors initialised.
func NewProcessExplorerMetrics() *ProcessExplorerMetrics {
	if !misc.EnablePrometheusIntegration {
		return &ProcessExplorerMetrics{}
	}
	metricsLabelNames := []string{PrometheusProcessIDLabel}
	return &ProcessExplorerMetrics{
		numUserModeSecInclChildren:   prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_user_mode_sec_incl_children"}, metricsLabelNames),
		numKernelModeSecInclChildren: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_kernal_mode_sec_incl_children"}, metricsLabelNames),
		numRunSec:                    prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_run_sec"}, metricsLabelNames),
		numWaitSec:                   prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_wait_sec"}, metricsLabelNames),
		numVoluntarySwitches:         prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_voluntary_switches"}, metricsLabelNames),
		numInvoluntarySwitches:       prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_involuntary_switches"}, metricsLabelNames),
	}
}

// RegisterGlobally registers all program performance metrics with the global & default prometheus instance.
func (metrics *ProcessExplorerMetrics) RegisterGlobally() error {
	if !misc.EnablePrometheusIntegration {
		return nil
	}
	for _, metric := range []prometheus.Collector{
		metrics.numKernelModeSecInclChildren,
		metrics.numUserModeSecInclChildren,
		metrics.numRunSec,
		metrics.numWaitSec,
		metrics.numInvoluntarySwitches,
		metrics.numVoluntarySwitches,
	} {
		if err := prometheus.Register(metric); err != nil {
			return err
		}
	}
	return nil
}

// Refresh reads the latest program performance measurements and gives them to prometheus metrics.
func (metrics *ProcessExplorerMetrics) Refresh() error {
	if !misc.EnablePrometheusIntegration {
		return nil
	}
	proc, err := procexp.GetProcAndTaskStatus(0)
	if err != nil {
		return err
	}
	labels := prometheus.Labels{PrometheusProcessIDLabel: strconv.Itoa(os.Getpid())}
	metrics.numUserModeSecInclChildren.With(labels).Set(proc.Stats.NumUserModeSecInclChildren)
	metrics.numKernelModeSecInclChildren.With(labels).Set(proc.Stats.NumKernelModeSecInclChildren)
	metrics.numRunSec.With(labels).Set(proc.SchedulerStatsSum.NumRunSec)
	metrics.numWaitSec.With(labels).Set(proc.SchedulerStatsSum.NumWaitSec)
	metrics.numVoluntarySwitches.With(labels).Set(float64(proc.SchedulerStatsSum.NumVoluntarySwitches))
	metrics.numInvoluntarySwitches.With(labels).Set(float64(proc.SchedulerStatsSum.NumInvoluntarySwitches))
	return nil
}
<commit_msg>correct a typo in metrics name laitos_proc_num_kernel_mode_sec_incl_children<commit_after>package maintenance

import (
	"os"
	"strconv"

	"github.com/HouzuoGuo/laitos/misc"
	"github.com/HouzuoGuo/laitos/platform/procexp"
	"github.com/prometheus/client_golang/prometheus"
)

const (
	// PrometheusProcessIDLabel is the name of data label given to process explorer metrics registered with prometheus.
	// The label data shall be the PID of this program.
	PrometheusProcessIDLabel = "pid"
)

// ProcessExplorerMetrics are the collection of program performance metrics registered with prometheus
// The measurements are taken from process status and statistics exposed by procfs (a Linux OS feature).
type ProcessExplorerMetrics struct {
	numUserModeSecInclChildren   *prometheus.GaugeVec
	numKernelModeSecInclChildren *prometheus.GaugeVec
	numRunSec                    *prometheus.GaugeVec
	numWaitSec                   *prometheus.GaugeVec
	numVoluntarySwitches         *prometheus.GaugeVec
	numInvoluntarySwitches       *prometheus.GaugeVec
}

// NewProcessExplorerMetrics creates a new ProcessExplorerMetrics with all of its metrics collectors initialised.
func NewProcessExplorerMetrics() *ProcessExplorerMetrics {
	if !misc.EnablePrometheusIntegration {
		return &ProcessExplorerMetrics{}
	}
	metricsLabelNames := []string{PrometheusProcessIDLabel}
	return &ProcessExplorerMetrics{
		numUserModeSecInclChildren:   prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_user_mode_sec_incl_children"}, metricsLabelNames),
		numKernelModeSecInclChildren: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_kernel_mode_sec_incl_children"}, metricsLabelNames),
		numRunSec:                    prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_run_sec"}, metricsLabelNames),
		numWaitSec:                   prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_wait_sec"}, metricsLabelNames),
		numVoluntarySwitches:         prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_voluntary_switches"}, metricsLabelNames),
		numInvoluntarySwitches:       prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: "laitos_proc_num_involuntary_switches"}, metricsLabelNames),
	}
}

// RegisterGlobally registers all program performance metrics with the global & default prometheus instance.
func (metrics *ProcessExplorerMetrics) RegisterGlobally() error {
	if !misc.EnablePrometheusIntegration {
		return nil
	}
	for _, metric := range []prometheus.Collector{
		metrics.numKernelModeSecInclChildren,
		metrics.numUserModeSecInclChildren,
		metrics.numRunSec,
		metrics.numWaitSec,
		metrics.numInvoluntarySwitches,
		metrics.numVoluntarySwitches,
	} {
		if err := prometheus.Register(metric); err != nil {
			return err
		}
	}
	return nil
}

// Refresh reads the latest program performance measurements and gives them to prometheus metrics.
func (metrics *ProcessExplorerMetrics) Refresh() error {
	if !misc.EnablePrometheusIntegration {
		return nil
	}
	proc, err := procexp.GetProcAndTaskStatus(0)
	if err != nil {
		return err
	}
	labels := prometheus.Labels{PrometheusProcessIDLabel: strconv.Itoa(os.Getpid())}
	metrics.numUserModeSecInclChildren.With(labels).Set(proc.Stats.NumUserModeSecInclChildren)
	metrics.numKernelModeSecInclChildren.With(labels).Set(proc.Stats.NumKernelModeSecInclChildren)
	metrics.numRunSec.With(labels).Set(proc.SchedulerStatsSum.NumRunSec)
	metrics.numWaitSec.With(labels).Set(proc.SchedulerStatsSum.NumWaitSec)
	metrics.numVoluntarySwitches.With(labels).Set(float64(proc.SchedulerStatsSum.NumVoluntarySwitches))
	metrics.numInvoluntarySwitches.With(labels).Set(float64(proc.SchedulerStatsSum.NumInvoluntarySwitches))
	return nil
}
<|endoftext|>


<commit_before>package x86

import (
	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
	"math/rand"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
	"github.com/lunixbochs/usercorn/go/native"
)

var cgcSysNum = map[int]string{
	1: "_terminate",
	2: "transmit",
	3: "receive",
	4: "fdwait",
	5: "allocate",
	6: "deallocate",
	7: "random",
}

type CgcKernel struct {
	*co.KernelBase
}

func (k *CgcKernel) Literal_terminate(code int) {
	k.U.Exit(models.ExitStatus(code))
}

func (k *CgcKernel) Transmit(fd co.Fd, buf co.Buf, size co.Len, ret co.Obuf) int {
	if fd == 0 {
		fd = 1
	}
	mem, err := k.U.MemRead(buf.Addr, uint64(size))
	if err != nil {
		return -1 // FIXME
	}
	n, err := syscall.Write(int(fd), mem)
	if err != nil {
		return -1 // FIXME
	}
	if err := ret.Pack(int32(n)); err != nil {
		return -1 // FIXME
	}
	return 0
}

func (k *CgcKernel) Receive(fd co.Fd, buf co.Obuf, size co.Len, ret co.Obuf) int {
	tmp := make([]byte, size)
	n, err := syscall.Read(int(fd), tmp)
	if err != nil {
		return -1 // FIXME
	}
	if err := buf.Pack(tmp[:n]); err != nil {
		return -1 // FIXME
	}
	if err := ret.Pack(int32(n)); err != nil {
		return -1 // FIXME
	}
	return 0
}

func (k *CgcKernel) Fdwait(nfds int, reads, writes, timeoutBuf co.Buf, readyFds co.Obuf) int {
	var readSet, writeSet *native.Fdset32
	var timeout native.Timespec
	reads.Unpack(&readSet)
	writes.Unpack(&writeSet)
	timeoutBuf.Unpack(&timeout)

	readNative := readSet.Native()
	writeNative := writeSet.Native()

	n, err := native.Select(nfds, readNative, writeNative, &timeout)
	if err != nil {
		return -1 // FIXME?
	} else {
		readyFds.Pack(int32(n))
	}
	return 0
}

func (k *CgcKernel) Allocate(size uint32, executable int32, ret co.Obuf) int {
	// round up to nearest page
	size = (size + 0x1000) & ^uint32(0x1000-1)
	mmap, _ := k.U.Mmap(0, uint64(size))
	mmap.Desc = "heap"
	if executable != 0 {
		k.U.MemProtect(mmap.Addr, mmap.Size, uc.PROT_ALL)
	}
	ret.Pack(uint32(mmap.Addr))
	return 0
}

func (k *CgcKernel) Deallocate(addr, size uint32) int {
	// addr must be multiple of page size
	if addr&(0x1000-1) > 0 {
		return -1 // FIXME
	}
	// all pages containing a part of the range are unmapped
	var pages []*models.Mmap
	for _, mmap := range k.U.Mappings() {
		// does addr overlap mapping?
		if (uint64(addr) >= mmap.Addr && uint64(addr) < mmap.Addr+mmap.Size) ||
			(uint64(addr) < mmap.Addr && uint64(addr+size) > mmap.Addr) {
			pages = append(pages, mmap)
		}
	}
	for _, page := range pages {
		k.U.MemUnmap(page.Addr, page.Size)
	}
	return 0
}

func (k *CgcKernel) Random(buf co.Obuf, size uint32, ret co.Obuf) {
	tmp := make([]byte, size)
	n, _ := rand.Read(tmp)
	tmp = tmp[:n]
	buf.Pack(tmp)
	ret.Pack(uint32(n))
}

func CgcInit(u models.Usercorn, args, env []string) error {
	// TODO: does CGC even specify argv?
	// TODO: also, I seem to remember something about mapping in 16kb of random data
	secretPage := uint64(0x4347c000)
	if err := u.MemMap(secretPage, 0x1000); err != nil {
		return err
	}
	tmp := make([]byte, 0x1000)
	if _, err := rand.Read(tmp); err != nil {
		return err
	}
	if err := u.MemWrite(secretPage, tmp); err != nil {
		return err
	}
	u.MemWrite(secretPage, []byte("FLAG"))
	u.RegWrite(uc.X86_REG_ECX, secretPage)

	for _, m := range u.Mappings() {
		if m.Desc == "stack" {
			u.MemUnmap(m.Addr, m.Size)
			break
		}
	}
	base := uint64(0xbaaab000 - 0x800000)
	if err := u.MemMapProt(base, 0x800000, uc.PROT_ALL); err != nil {
		return err
	}
	for _, m := range u.Mappings() {
		if m.Addr == base {
			m.Desc = "stack"
			break
		}
	}
	u.RegWrite(u.Arch().SP, 0xbaaaaffc)
	u.SetStackBase(base)
	return nil
}

func CgcSyscall(u models.Usercorn) {
	eax, _ := u.RegRead(uc.X86_REG_EAX)
	name, _ := cgcSysNum[int(eax)]
	ret, _ := u.Syscall(int(eax), name, co.RegArgs(u, LinuxRegs))
	u.RegWrite(uc.X86_REG_EAX, ret)
}

func CgcInterrupt(u models.Usercorn, intno uint32) {
	if intno == 0x80 {
		CgcSyscall(u)
	}
}

func CgcKernels(u models.Usercorn) []interface{} {
	kernel := &CgcKernel{&co.KernelBase{}}
	return []interface{}{kernel}
}

func init() {
	Arch.RegisterOS(&models.OS{
		Name:      "cgc",
		Init:      CgcInit,
		Interrupt: CgcInterrupt,
		Kernels:   CgcKernels,
	})
}
<commit_msg>remove deterministic secret page<commit_after>package x86

import (
	"crypto/rand"
	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
	"github.com/lunixbochs/usercorn/go/native"
)

var cgcSysNum = map[int]string{
	1: "_terminate",
	2: "transmit",
	3: "receive",
	4: "fdwait",
	5: "allocate",
	6: "deallocate",
	7: "random",
}

type CgcKernel struct {
	*co.KernelBase
}

func (k *CgcKernel) Literal_terminate(code int) {
	k.U.Exit(models.ExitStatus(code))
}

func (k *CgcKernel) Transmit(fd co.Fd, buf co.Buf, size co.Len, ret co.Obuf) int {
	if fd == 0 {
		fd = 1
	}
	mem, err := k.U.MemRead(buf.Addr, uint64(size))
	if err != nil {
		return -1 // FIXME
	}
	n, err := syscall.Write(int(fd), mem)
	if err != nil {
		return -1 // FIXME
	}
	if err := ret.Pack(int32(n)); err != nil {
		return -1 // FIXME
	}
	return 0
}

func (k *CgcKernel) Receive(fd co.Fd, buf co.Obuf, size co.Len, ret co.Obuf) int {
	tmp := make([]byte, size)
	n, err := syscall.Read(int(fd), tmp)
	if err != nil {
		return -1 // FIXME
	}
	if err := buf.Pack(tmp[:n]); err != nil {
		return -1 // FIXME
	}
	if err := ret.Pack(int32(n)); err != nil {
		return -1 // FIXME
	}
	return 0
}

func (k *CgcKernel) Fdwait(nfds int, reads, writes, timeoutBuf co.Buf, readyFds co.Obuf) int {
	var readSet, writeSet *native.Fdset32
	var timeout native.Timespec
	reads.Unpack(&readSet)
	writes.Unpack(&writeSet)
	timeoutBuf.Unpack(&timeout)

	readNative := readSet.Native()
	writeNative := writeSet.Native()

	n, err := native.Select(nfds, readNative, writeNative, &timeout)
	if err != nil {
		return -1 // FIXME?
	} else {
		readyFds.Pack(int32(n))
	}
	return 0
}

func (k *CgcKernel) Allocate(size uint32, executable int32, ret co.Obuf) int {
	// round up to nearest page
	size = (size + 0x1000) & ^uint32(0x1000-1)
	mmap, _ := k.U.Mmap(0, uint64(size))
	mmap.Desc = "heap"
	if executable != 0 {
		k.U.MemProtect(mmap.Addr, mmap.Size, uc.PROT_ALL)
	}
	ret.Pack(uint32(mmap.Addr))
	return 0
}

func (k *CgcKernel) Deallocate(addr, size uint32) int {
	// addr must be multiple of page size
	if addr&(0x1000-1) > 0 {
		return -1 // FIXME
	}
	// all pages containing a part of the range are unmapped
	var pages []*models.Mmap
	for _, mmap := range k.U.Mappings() {
		// does addr overlap mapping?
		if (uint64(addr) >= mmap.Addr && uint64(addr) < mmap.Addr+mmap.Size) ||
			(uint64(addr) < mmap.Addr && uint64(addr+size) > mmap.Addr) {
			pages = append(pages, mmap)
		}
	}
	for _, page := range pages {
		k.U.MemUnmap(page.Addr, page.Size)
	}
	return 0
}

func (k *CgcKernel) Random(buf co.Obuf, size uint32, ret co.Obuf) {
	tmp := make([]byte, size)
	n, _ := rand.Read(tmp)
	tmp = tmp[:n]
	buf.Pack(tmp)
	ret.Pack(uint32(n))
}

func CgcInit(u models.Usercorn, args, env []string) error {
	// TODO: does CGC even specify argv?
	// TODO: also, I seem to remember something about mapping in 16kb of random data
	secretPage := uint64(0x4347c000)
	if err := u.MemMap(secretPage, 0x1000); err != nil {
		return err
	}
	tmp := make([]byte, 0x1000)
	if _, err := rand.Read(tmp); err != nil {
		return err
	}
	if err := u.MemWrite(secretPage, tmp); err != nil {
		return err
	}
	u.RegWrite(uc.X86_REG_ECX, secretPage)

	for _, m := range u.Mappings() {
		if m.Desc == "stack" {
			u.MemUnmap(m.Addr, m.Size)
			break
		}
	}
	base := uint64(0xbaaab000 - 0x800000)
	if err := u.MemMapProt(base, 0x800000, uc.PROT_ALL); err != nil {
		return err
	}
	for _, m := range u.Mappings() {
		if m.Addr == base {
			m.Desc = "stack"
			break
		}
	}
	u.RegWrite(u.Arch().SP, 0xbaaaaffc)
	u.SetStackBase(base)
	return nil
}

func CgcSyscall(u models.Usercorn) {
	eax, _ := u.RegRead(uc.X86_REG_EAX)
	name, _ := cgcSysNum[int(eax)]
	ret, _ := u.Syscall(int(eax), name, co.RegArgs(u, LinuxRegs))
	u.RegWrite(uc.X86_REG_EAX, ret)
}

func CgcInterrupt(u models.Usercorn, intno uint32) {
	if intno == 0x80 {
		CgcSyscall(u)
	}
}

func CgcKernels(u models.Usercorn) []interface{} {
	kernel := &CgcKernel{&co.KernelBase{}}
	return []interface{}{kernel}
}

func init() {
	Arch.RegisterOS(&models.OS{
		Name:      "cgc",
		Init:      CgcInit,
		Interrupt: CgcInterrupt,
		Kernels:   CgcKernels,
	})
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"

	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/client"
)

// NewExecWatchCommand returns the CLI command for "exec-watch".
func NewExecWatchCommand() cli.Command {
	return cli.Command{
		Name:  "exec-watch",
		Usage: "watch a key for changes and exec an executable",
		Flags: []cli.Flag{
			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
			cli.BoolFlag{Name: "recursive", Usage: "watch all values for key and child keys"},
		},
		Action: func(c *cli.Context) {
			execWatchCommandFunc(c, mustNewKeyAPI(c))
		},
	}
}

// execWatchCommandFunc executes the "exec-watch" command.
func execWatchCommandFunc(c *cli.Context, ki client.KeysAPI) {
	args := c.Args()
	argslen := len(args)

	if argslen < 2 {
		handleError(ExitBadArgs, errors.New("key and command to exec required"))
	}

	key := args[argslen-1]
	cmdArgs := args[:argslen-1]

	index := 0
	if c.Int("after-index") != 0 {
		index = c.Int("after-index") + 1
		key = args[0]
		cmdArgs = args[2:]
	}

	recursive := c.Bool("recursive")
	if recursive != false {
		key = args[0]
		cmdArgs = args[2:]
	}

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, os.Interrupt)

	go func() {
		<-sigch
		os.Exit(0)
	}()

	w := ki.Watcher(key, &client.WatcherOptions{AfterIndex: uint64(index), Recursive: recursive})

	for {
		resp, err := w.Next(context.TODO())
		if err != nil {
			handleError(ExitServerError, err)
		}
		if resp.Node.Dir {
			fmt.Fprintf(os.Stderr, "Ignored dir %s change", resp.Node.Key)
			continue
		}

		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
		cmd.Env = environResponse(resp, os.Environ())

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			os.Exit(1)
		}
		stderr, err := cmd.StderrPipe()
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			os.Exit(1)
		}

		go func() {
			err := cmd.Start()
			if err != nil {
				fmt.Fprintf(os.Stderr, err.Error())
				os.Exit(1)
			}
			go io.Copy(os.Stdout, stdout)
			go io.Copy(os.Stderr, stderr)
			cmd.Wait()
		}()
	}
}

func environResponse(resp *client.Response, env []string) []string {
	env = append(env, "ETCD_WATCH_ACTION="+resp.Action)
	env = append(env, "ETCD_WATCH_MODIFIED_INDEX="+fmt.Sprintf("%d", resp.Node.ModifiedIndex))
	env = append(env, "ETCD_WATCH_KEY="+resp.Node.Key)
	env = append(env, "ETCD_WATCH_VALUE="+resp.Node.Value)
	return env
}
<commit_msg>etcdctl: fix exec watch command<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"

	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/client"
)

// NewExecWatchCommand returns the CLI command for "exec-watch".
func NewExecWatchCommand() cli.Command {
	return cli.Command{
		Name:  "exec-watch",
		Usage: "watch a key for changes and exec an executable",
		Flags: []cli.Flag{
			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
			cli.BoolFlag{Name: "recursive", Usage: "watch all values for key and child keys"},
		},
		Action: func(c *cli.Context) {
			execWatchCommandFunc(c, mustNewKeyAPI(c))
		},
	}
}

// execWatchCommandFunc executes the "exec-watch" command.
func execWatchCommandFunc(c *cli.Context, ki client.KeysAPI) {
	args := c.Args()
	argslen := len(args)

	if argslen < 2 {
		handleError(ExitBadArgs, errors.New("key and command to exec required"))
	}

	var (
		key     string
		cmdArgs []string
	)

	foundSep := false
	for i := range args {
		if args[i] == "--" && i != 0 {
			foundSep = true
			break
		}
	}

	if foundSep {
		key = args[0]
		cmdArgs = args[2:]
	} else {
		// If no flag is parsed, the order of key and cmdArgs will be switched and
		// args will not contain `--`.
		key = args[argslen-1]
		cmdArgs = args[:argslen-1]
	}

	index := 0
	if c.Int("after-index") != 0 {
		index = c.Int("after-index") + 1
	}

	recursive := c.Bool("recursive")

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, os.Interrupt)

	go func() {
		<-sigch
		os.Exit(0)
	}()

	w := ki.Watcher(key, &client.WatcherOptions{AfterIndex: uint64(index), Recursive: recursive})

	for {
		resp, err := w.Next(context.TODO())
		if err != nil {
			handleError(ExitServerError, err)
		}
		if resp.Node.Dir {
			fmt.Fprintf(os.Stderr, "Ignored dir %s change", resp.Node.Key)
			continue
		}

		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
		cmd.Env = environResponse(resp, os.Environ())

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			os.Exit(1)
		}
		stderr, err := cmd.StderrPipe()
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			os.Exit(1)
		}

		go func() {
			err := cmd.Start()
			if err != nil {
				fmt.Fprintf(os.Stderr, err.Error())
				os.Exit(1)
			}
			go io.Copy(os.Stdout, stdout)
			go io.Copy(os.Stderr, stderr)
			cmd.Wait()
		}()
	}
}

func environResponse(resp *client.Response, env []string) []string {
	env = append(env, "ETCD_WATCH_ACTION="+resp.Action)
	env = append(env, "ETCD_WATCH_MODIFIED_INDEX="+fmt.Sprintf("%d", resp.Node.ModifiedIndex))
	env = append(env, "ETCD_WATCH_KEY="+resp.Node.Key)
	env = append(env, "ETCD_WATCH_VALUE="+resp.Node.Value)
	return env
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase

import (
	"encoding/base64"
	"errors"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"sync"

	"github.com/keybase/client/go/externals"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/service"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"github.com/keybase/kbfs/fsrpc"
	"github.com/keybase/kbfs/libkbfs"
)

var kbCtx *libkb.GlobalContext
var conn net.Conn
var startOnce sync.Once
var logSendContext libkb.LogSendContext
var kbfsConfig libkbfs.Config

// InitOnce runs the Keybase services (only runs one time)
func InitOnce(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) {
	startOnce.Do(func() {
		if err := Init(homeDir, logFile, runModeStr, accessGroupOverride); err != nil {
			kbCtx.Log.Errorf("Init error: %s", err)
		}
	})
}

// Init runs the Keybase services
func Init(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) error {
	fmt.Println("Go: Initializing")
	fmt.Printf("Go: Using log: %s\n", logFile)

	go func() {
		fmt.Println(http.ListenAndServe(":6060", nil))
	}()

	kbCtx = libkb.G
	kbCtx.Init()
	kbCtx.SetServices(externals.GetServices())
	usage := libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
	runMode, err := libkb.StringToRunMode(runModeStr)
	if err != nil {
		return err
	}
	config := libkb.AppConfig{
		HomeDir:                     homeDir,
		LogFile:                     logFile,
		RunMode:                     runMode,
		Debug:                       true,
		LocalRPCDebug:               "",
		SecurityAccessGroupOverride: accessGroupOverride,
	}
	err = kbCtx.Configure(config, usage)
	if err != nil {
		return err
	}

	svc := service.NewService(kbCtx, false)
	svc.StartLoopbackServer()
	kbCtx.SetService()
	uir := service.NewUIRouter(kbCtx)
	kbCtx.SetUIRouter(uir)
	svc.RunBackgroundOperations(uir)

	serviceLog := config.GetLogFile()
	logs := libkb.Logs{
		Service: serviceLog,
	}

	logSendContext = libkb.LogSendContext{
		Contextified: libkb.NewContextified(kbCtx),
		Logs:         logs,
	}

	// FIXME (MBG): This is causing RPC responses to sometimes not be recieved
	// on iOS. Repro by hooking up getExtendedStatus to a button in the iOS
	// client and watching JS logs. Disabling until we have a root cause / fix.
	kbfsParams := libkbfs.DefaultInitParams(kbCtx)
	kbfsConfig, err = libkbfs.Init(kbCtx, kbfsParams, serviceCn{}, func() {}, kbCtx.Log)
	if err != nil {
		return err
	}

	return Reset()
}

type serviceCn struct {
	ctx *libkb.GlobalContext
}

func (s serviceCn) NewKeybaseService(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.KeybaseService, error) {
	keybaseService := libkbfs.NewKeybaseDaemonRPC(config, ctx, log, true)
	keybaseService.AddProtocols([]rpc.Protocol{
		keybase1.FsProtocol(fsrpc.NewFS(config, log)),
	})
	return keybaseService, nil
}

func (s serviceCn) NewCrypto(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.Crypto, error) {
	return libkbfs.NewCryptoClientRPC(config, ctx), nil
}

// LogSend sends a log to Keybase
func LogSend(uiLogPath string) (string, error) {
	logSendContext.Logs.Desktop = uiLogPath
	return logSendContext.LogSend("", 10000)
}

// WriteB64 sends a base64 encoded msgpack rpc payload
func WriteB64(str string) error {
	data, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return fmt.Errorf("Base64 decode error: %s; %s", err, str)
	}
	n, err := conn.Write(data)
	if err != nil {
		return fmt.Errorf("Write error: %s", err)
	}
	if n != len(data) {
		return errors.New("Did not write all the data")
	}
	return nil
}

const targetBufferSize = 50 * 1024

// bufferSize must be divisible by 3 to ensure that we don't split
// our b64 encode across a payload boundary if we go over our buffer
// size.
const bufferSize = targetBufferSize - (targetBufferSize % 3)

// buffer for the conn.Read
var buffer = make([]byte, bufferSize)

// ReadB64 is a blocking read for base64 encoded msgpack rpc data.
// It is called serially by the mobile run loops.
func ReadB64() (string, error) {
	n, err := conn.Read(buffer)
	if n > 0 && err == nil {
		str := base64.StdEncoding.EncodeToString(buffer[0:n])
		return str, nil
	}

	if err != nil {
		// Attempt to fix the connection
		Reset()
		return "", fmt.Errorf("Read error: %s", err)
	}

	return "", nil
}

// Reset resets the socket connection
func Reset() error {
	if conn != nil {
		conn.Close()
	}

	var err error
	conn, err = kbCtx.LoopbackListener.Dial()
	if err != nil {
		return fmt.Errorf("Socket error: %s", err)
	}
	return nil
}

// Version returns semantic version string
func Version() string {
	return libkb.VersionString()
}
<commit_msg>Remove pprof<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase

import (
	"encoding/base64"
	"errors"
	"fmt"
	"net"
	"sync"

	"github.com/keybase/client/go/externals"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/service"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"github.com/keybase/kbfs/fsrpc"
	"github.com/keybase/kbfs/libkbfs"
)

var kbCtx *libkb.GlobalContext
var conn net.Conn
var startOnce sync.Once
var logSendContext libkb.LogSendContext
var kbfsConfig libkbfs.Config

// InitOnce runs the Keybase services (only runs one time)
func InitOnce(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) {
	startOnce.Do(func() {
		if err := Init(homeDir, logFile, runModeStr, accessGroupOverride); err != nil {
			kbCtx.Log.Errorf("Init error: %s", err)
		}
	})
}

// Init runs the Keybase services
func Init(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) error {
	fmt.Println("Go: Initializing")
	fmt.Printf("Go: Using log: %s\n", logFile)

	kbCtx = libkb.G
	kbCtx.Init()
	kbCtx.SetServices(externals.GetServices())
	usage := libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
	runMode, err := libkb.StringToRunMode(runModeStr)
	if err != nil {
		return err
	}
	config := libkb.AppConfig{
		HomeDir:                     homeDir,
		LogFile:                     logFile,
		RunMode:                     runMode,
		Debug:                       true,
		LocalRPCDebug:               "",
		SecurityAccessGroupOverride: accessGroupOverride,
	}
	err = kbCtx.Configure(config, usage)
	if err != nil {
		return err
	}

	svc := service.NewService(kbCtx, false)
	svc.StartLoopbackServer()
	kbCtx.SetService()
	uir := service.NewUIRouter(kbCtx)
	kbCtx.SetUIRouter(uir)
	svc.RunBackgroundOperations(uir)

	serviceLog := config.GetLogFile()
	logs := libkb.Logs{
		Service: serviceLog,
	}

	logSendContext = libkb.LogSendContext{
		Contextified: libkb.NewContextified(kbCtx),
		Logs:         logs,
	}

	// FIXME (MBG): This is causing RPC responses to sometimes not be recieved
	// on iOS. Repro by hooking up getExtendedStatus to a button in the iOS
	// client and watching JS logs. Disabling until we have a root cause / fix.
	kbfsParams := libkbfs.DefaultInitParams(kbCtx)
	kbfsConfig, err = libkbfs.Init(kbCtx, kbfsParams, serviceCn{}, func() {}, kbCtx.Log)
	if err != nil {
		return err
	}

	return Reset()
}

type serviceCn struct {
	ctx *libkb.GlobalContext
}

func (s serviceCn) NewKeybaseService(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.KeybaseService, error) {
	keybaseService := libkbfs.NewKeybaseDaemonRPC(config, ctx, log, true)
	keybaseService.AddProtocols([]rpc.Protocol{
		keybase1.FsProtocol(fsrpc.NewFS(config, log)),
	})
	return keybaseService, nil
}

func (s serviceCn) NewCrypto(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.Crypto, error) {
	return libkbfs.NewCryptoClientRPC(config, ctx), nil
}

// LogSend sends a log to Keybase
func LogSend(uiLogPath string) (string, error) {
	logSendContext.Logs.Desktop = uiLogPath
	return logSendContext.LogSend("", 10000)
}

// WriteB64 sends a base64 encoded msgpack rpc payload
func WriteB64(str string) error {
	data, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return fmt.Errorf("Base64 decode error: %s; %s", err, str)
	}
	n, err := conn.Write(data)
	if err != nil {
		return fmt.Errorf("Write error: %s", err)
	}
	if n != len(data) {
		return errors.New("Did not write all the data")
	}
	return nil
}

const targetBufferSize = 50 * 1024

// bufferSize must be divisible by 3 to ensure that we don't split
// our b64 encode across a payload boundary if we go over our buffer
// size.
const bufferSize = targetBufferSize - (targetBufferSize % 3)

// buffer for the conn.Read
var buffer = make([]byte, bufferSize)

// ReadB64 is a blocking read for base64 encoded msgpack rpc data.
// It is called serially by the mobile run loops.
func ReadB64() (string, error) {
	n, err := conn.Read(buffer)
	if n > 0 && err == nil {
		str := base64.StdEncoding.EncodeToString(buffer[0:n])
		return str, nil
	}

	if err != nil {
		// Attempt to fix the connection
		Reset()
		return "", fmt.Errorf("Read error: %s", err)
	}

	return "", nil
}

// Reset resets the socket connection
func Reset() error {
	if conn != nil {
		conn.Close()
	}

	var err error
	conn, err = kbCtx.LoopbackListener.Dial()
	if err != nil {
		return fmt.Errorf("Socket error: %s", err)
	}
	return nil
}

// Version returns semantic version string
func Version() string {
	return libkb.VersionString()
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package main

import (
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/client"
	"github.com/keybase/client/go/externals"
	"github.com/keybase/client/go/install"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/service"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

// Keep this around to simplify things
var G = libkb.G

var cmd libcmdline.Command

type Canceler interface {
	Cancel() error
}

type Stopper interface {
	Stop(exitcode keybase1.ExitCode)
}

func main() {
	err := libkb.SaferDLLLoading()

	g := G
	g.Init()

	// Set our panel of external services.
	g.SetServices(externals.GetServices())

	// Don't abort here. This should not happen on any known version of Windows, but
	// new MS platforms may create regressions.
	if err != nil {
		g.Log.Errorf("SaferDLLLoading error: %v", err.Error())
	}

	go HandleSignals()
	err = mainInner(g)

	if g.Env.GetDebug() {
		// hack to wait a little bit to receive all the log messages from the
		// service before shutting down in debug mode.
		time.Sleep(100 * time.Millisecond)
	}

	e2 := g.Shutdown()
	if err == nil {
		err = e2
	}
	if err != nil {
		// Note that logger.Error and logger.Errorf are the same, which causes problems
		// trying to print percent signs, which are used in environment variables
		// in Windows.
		// Had to change from Error to Errorf because of go vet because of:
		// https://github.com/golang/go/issues/6407
		g.Log.Errorf("%s", err.Error())
		if g.ExitCode == keybase1.ExitCode_OK {
			g.ExitCode = keybase1.ExitCode_NOTOK
		}
	}
	if g.ExitCode != keybase1.ExitCode_OK {
		os.Exit(int(g.ExitCode))
	}
}

func warnNonProd(log logger.Logger, e *libkb.Env) {
	mode := e.GetRunMode()
	if mode != libkb.ProductionRunMode {
		log.Warning("Running in %s mode", mode)
	}
}

func checkSystemUser(log logger.Logger) {
	if isAdminUser, match, _ := libkb.IsSystemAdminUser(); isAdminUser {
		log.Errorf("Oops, you are trying to run as an admin user (%s). This isn't supported.", match)
		os.Exit(int(keybase1.ExitCode_NOTOK))
	}
}

func mainInner(g *libkb.GlobalContext) error {
	cl := libcmdline.NewCommandLine(true, client.GetExtraFlags())
	cl.AddCommands(client.GetCommands(cl, g))
	cl.AddCommands(service.GetCommands(cl, g))
	cl.AddHelpTopics(client.GetHelpTopics())

	var err error
	cmd, err = cl.Parse(os.Args)
	if err != nil {
		err = fmt.Errorf("Error parsing command line arguments: %s\n", err)
		return err
	}

	if cmd == nil {
		return nil
	}

	checkSystemUser(g.Log)

	if !cl.IsService() {
		if logger.SaveConsoleMode() == nil {
			defer logger.RestoreConsoleMode()
		}
		client.InitUI()
	}

	if err = g.ConfigureCommand(cl, cmd); err != nil {
		return err
	}
	g.StartupMessage()

	warnNonProd(g.Log, g.Env)

	if err = configureProcesses(g, cl, &cmd); err != nil {
		return err
	}

	err = cmd.Run()
	if !cl.IsService() && !cl.SkipOutOfDateCheck() {
		// Errors that come up in printing this warning are logged but ignored.
		client.PrintOutOfDateWarnings(g)
	}
	return err
}

// AutoFork? Standalone? ClientServer? Brew service?  This function deals with the
// various run configurations that we can run in.
func configureProcesses(g *libkb.GlobalContext, cl *libcmdline.CommandLine, cmd *libcmdline.Command) (err error) {

	g.Log.Debug("+ configureProcesses")
	defer func() {
		g.Log.Debug("- configureProcesses -> %v", err)
	}()

	// On Linux, the service configures its own autostart file. Otherwise, no
	// need to configure if we're a service.
	if cl.IsService() {
		g.Log.Debug("| in configureProcesses, is service")
		if runtime.GOOS == "linux" {
			g.Log.Debug("| calling AutoInstall")
			_, err := install.AutoInstall(g, "", false, 10*time.Second, g.Log)
			if err != nil {
				return err
			}
		}
		return nil
	}

	// Start the server on the other end, possibly.
	// There are two cases in which we do this: (1) we want
	// a local loopback server in standalone mode; (2) we
	// need to "autofork" it. Do at most one of these
	// operations.
	if g.Env.GetStandalone() {
		if cl.IsNoStandalone() {
			err = fmt.Errorf("Can't run command in standalone mode")
			return err
		}
		err := service.NewService(g, false /* isDaemon */).StartLoopbackServer()
		if err != nil {
			if pflerr, ok := err.(libkb.PIDFileLockError); ok {
				err = fmt.Errorf("Can't run in standalone mode with a service running (see %q)",
					pflerr.Filename)
				return err
			}
		}
		return err
	}

	// After this point, we need to provide a remote logging story if necessary

	// If this command specifically asks not to be forked, then we are done in this
	// function. This sort of thing is true for the `ctl` commands and also the `version`
	// command.
	fc := cl.GetForkCmd()
	if fc == libcmdline.NoFork {
		return configureLogging(g, cl)
	}

	var newProc bool
	if libkb.IsBrewBuild {
		// If we're running in Brew mode, we might need to install ourselves as a persistent
		// service for future invocations of the command.
		newProc, err = install.AutoInstall(g, "", false, 10*time.Second, g.Log)
		if err != nil {
			return err
		}
	} else {
		// If this command warrants an autofork, do it now.
		if fc == libcmdline.ForceFork || g.Env.GetAutoFork() {
			newProc, err = client.AutoForkServer(g, cl)
			if err != nil {
				return err
			}
		}
	}

	// Restart the service if we see that it's out of date. It's important to do this
	// before we make any RPCs to the service --- for instance, before the logging
	// calls below. See the v1.0.8 update fiasco for more details. Also, only need
	// to do this if we didn't just start a new process.
	if !newProc {
		if err = client.FixVersionClash(g, cl); err != nil {
			return err
		}
	}

	g.Log.Debug("| After forks; newProc=%v", newProc)
	if err = configureLogging(g, cl); err != nil {
		return err
	}

	// This sends the client's PATH to the service so the service can update
	// its PATH if necessary. This is called after FixVersionClash(), which
	// happens above in configureProcesses().
	if err = configurePath(g, cl); err != nil {
		// Further note -- don't die here.  It could be we're calling this method
		// against an earlier version of the service that doesn't support it.
		// It's not critical that it succeed, so continue on.
		g.Log.Debug("Configure path failed: %v", err)
	}

	return nil
}

func configureLogging(g *libkb.GlobalContext, cl *libcmdline.CommandLine) error {

	g.Log.Debug("+ configureLogging")
	defer func() {
		g.Log.Debug("- configureLogging")
	}()
	// Whether or not we autoforked, we're now running in client-server
	// mode (as opposed to standalone). Register a global LogUI so that
	// calls to G.Log() in the daemon can be copied to us. This is
	// something of a hack on the daemon side.
	if !g.Env.GetDoLogForward() || cl.GetLogForward() == libcmdline.LogForwardNone {
		g.Log.Debug("Disabling log forwarding")
		return nil
	}

	protocols := []rpc.Protocol{client.NewLogUIProtocol()}
	if err := client.RegisterProtocolsWithContext(protocols, g); err != nil {
		return err
	}

	logLevel := keybase1.LogLevel_INFO
	if g.Env.GetDebug() {
		logLevel = keybase1.LogLevel_DEBUG
	}
	logClient, err := client.GetLogClient(g)
	if err != nil {
		return err
	}
	arg := keybase1.RegisterLoggerArg{
		Name:  "CLI client",
		Level: logLevel,
	}
	if err := logClient.RegisterLogger(context.TODO(), arg); err != nil {
		g.Log.Warning("Failed to register as a logger: %s", err)
	}

	return nil
}

// configurePath sends the client's PATH to the service.
func configurePath(g *libkb.GlobalContext, cl *libcmdline.CommandLine) error {
	if cl.IsService() {
		// this only runs on the client
		return nil
	}

	return client.SendPath(g)
}

func HandleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, os.Kill)
	for {
		s := <-c
		if s != nil {
			G.Log.Debug("trapped signal %v", s)

			// if the current command has a Stop function, then call it.
			// It will do its own stopping of the process and calling
			// shutdown
			if stop, ok := cmd.(Stopper); ok {
				G.Log.Debug("Stopping command cleanly via stopper")
				stop.Stop(keybase1.ExitCode_OK)
				return
			}

			// if the current command has a Cancel function, then call it:
			if canc, ok := cmd.(Canceler); ok {
				G.Log.Debug("canceling running command")
				if err := canc.Cancel(); err != nil {
					G.Log.Warning("error canceling command: %s", err)
				}
			}

			G.Log.Debug("calling shutdown")
			G.Shutdown()
			G.Log.Error("interrupted")
			os.Exit(3)
		}
	}
}
<commit_msg>quick short-circuit code for version -S (#6163)<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package main

import (
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/client"
	"github.com/keybase/client/go/externals"
	"github.com/keybase/client/go/install"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/service"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

// Keep this around to simplify things
var G = libkb.G

var cmd libcmdline.Command

type Canceler interface {
	Cancel() error
}

type Stopper interface {
	Stop(exitcode keybase1.ExitCode)
}

func handleQuickVersion() bool {
	if len(os.Args) == 3 && os.Args[1] == "version" && os.Args[2] == "-S" {
		fmt.Printf("%s\n", libkb.VersionString())
		return true
	}
	return false
}

func main() {
	err := libkb.SaferDLLLoading()

	// handle a Quick version query
	if handleQuickVersion() {
		return
	}

	g := G
	g.Init()

	// Set our panel of external services.
	g.SetServices(externals.GetServices())

	// Don't abort here. This should not happen on any known version of Windows, but
	// new MS platforms may create regressions.
	if err != nil {
		g.Log.Errorf("SaferDLLLoading error: %v", err.Error())
	}

	go HandleSignals()
	err = mainInner(g)

	if g.Env.GetDebug() {
		// hack to wait a little bit to receive all the log messages from the
		// service before shutting down in debug mode.
		time.Sleep(100 * time.Millisecond)
	}

	e2 := g.Shutdown()
	if err == nil {
		err = e2
	}
	if err != nil {
		// Note that logger.Error and logger.Errorf are the same, which causes problems
		// trying to print percent signs, which are used in environment variables
		// in Windows.
		// Had to change from Error to Errorf because of go vet because of:
		// https://github.com/golang/go/issues/6407
		g.Log.Errorf("%s", err.Error())
		if g.ExitCode == keybase1.ExitCode_OK {
			g.ExitCode = keybase1.ExitCode_NOTOK
		}
	}
	if g.ExitCode != keybase1.ExitCode_OK {
		os.Exit(int(g.ExitCode))
	}
}

func warnNonProd(log logger.Logger, e *libkb.Env) {
	mode := e.GetRunMode()
	if mode != libkb.ProductionRunMode {
		log.Warning("Running in %s mode", mode)
	}
}

func checkSystemUser(log logger.Logger) {
	if isAdminUser, match, _ := libkb.IsSystemAdminUser(); isAdminUser {
		log.Errorf("Oops, you are trying to run as an admin user (%s). This isn't supported.", match)
		os.Exit(int(keybase1.ExitCode_NOTOK))
	}
}

func mainInner(g *libkb.GlobalContext) error {
	cl := libcmdline.NewCommandLine(true, client.GetExtraFlags())
	cl.AddCommands(client.GetCommands(cl, g))
	cl.AddCommands(service.GetCommands(cl, g))
	cl.AddHelpTopics(client.GetHelpTopics())

	var err error
	cmd, err = cl.Parse(os.Args)
	if err != nil {
		err = fmt.Errorf("Error parsing command line arguments: %s\n", err)
		return err
	}

	if cmd == nil {
		return nil
	}

	checkSystemUser(g.Log)

	if !cl.IsService() {
		if logger.SaveConsoleMode() == nil {
			defer logger.RestoreConsoleMode()
		}
		client.InitUI()
	}

	if err = g.ConfigureCommand(cl, cmd); err != nil {
		return err
	}
	g.StartupMessage()

	warnNonProd(g.Log, g.Env)

	if err = configureProcesses(g, cl, &cmd); err != nil {
		return err
	}

	err = cmd.Run()
	if !cl.IsService() && !cl.SkipOutOfDateCheck() {
		// Errors that come up in printing this warning are logged but ignored.
		client.PrintOutOfDateWarnings(g)
	}
	return err
}

// AutoFork? Standalone? ClientServer? Brew service?  This function deals with the
// various run configurations that we can run in.
func configureProcesses(g *libkb.GlobalContext, cl *libcmdline.CommandLine, cmd *libcmdline.Command) (err error) {

	g.Log.Debug("+ configureProcesses")
	defer func() {
		g.Log.Debug("- configureProcesses -> %v", err)
	}()

	// On Linux, the service configures its own autostart file. Otherwise, no
	// need to configure if we're a service.
	if cl.IsService() {
		g.Log.Debug("| in configureProcesses, is service")
		if runtime.GOOS == "linux" {
			g.Log.Debug("| calling AutoInstall")
			_, err := install.AutoInstall(g, "", false, 10*time.Second, g.Log)
			if err != nil {
				return err
			}
		}
		return nil
	}

	// Start the server on the other end, possibly.
	// There are two cases in which we do this: (1) we want
	// a local loopback server in standalone mode; (2) we
	// need to "autofork" it. Do at most one of these
	// operations.
	if g.Env.GetStandalone() {
		if cl.IsNoStandalone() {
			err = fmt.Errorf("Can't run command in standalone mode")
			return err
		}
		err := service.NewService(g, false /* isDaemon */).StartLoopbackServer()
		if err != nil {
			if pflerr, ok := err.(libkb.PIDFileLockError); ok {
				err = fmt.Errorf("Can't run in standalone mode with a service running (see %q)",
					pflerr.Filename)
				return err
			}
		}
		return err
	}

	// After this point, we need to provide a remote logging story if necessary

	// If this command specifically asks not to be forked, then we are done in this
	// function. This sort of thing is true for the `ctl` commands and also the `version`
	// command.
	fc := cl.GetForkCmd()
	if fc == libcmdline.NoFork {
		return configureLogging(g, cl)
	}

	var newProc bool
	if libkb.IsBrewBuild {
		// If we're running in Brew mode, we might need to install ourselves as a persistent
		// service for future invocations of the command.
		newProc, err = install.AutoInstall(g, "", false, 10*time.Second, g.Log)
		if err != nil {
			return err
		}
	} else {
		// If this command warrants an autofork, do it now.
		if fc == libcmdline.ForceFork || g.Env.GetAutoFork() {
			newProc, err = client.AutoForkServer(g, cl)
			if err != nil {
				return err
			}
		}
	}

	// Restart the service if we see that it's out of date. It's important to do this
	// before we make any RPCs to the service --- for instance, before the logging
	// calls below. See the v1.0.8 update fiasco for more details. Also, only need
	// to do this if we didn't just start a new process.
	if !newProc {
		if err = client.FixVersionClash(g, cl); err != nil {
			return err
		}
	}

	g.Log.Debug("| After forks; newProc=%v", newProc)
	if err = configureLogging(g, cl); err != nil {
		return err
	}

	// This sends the client's PATH to the service so the service can update
	// its PATH if necessary. This is called after FixVersionClash(), which
	// happens above in configureProcesses().
	if err = configurePath(g, cl); err != nil {
		// Further note -- don't die here.  It could be we're calling this method
		// against an earlier version of the service that doesn't support it.
		// It's not critical that it succeed, so continue on.
		g.Log.Debug("Configure path failed: %v", err)
	}

	return nil
}

func configureLogging(g *libkb.GlobalContext, cl *libcmdline.CommandLine) error {

	g.Log.Debug("+ configureLogging")
	defer func() {
		g.Log.Debug("- configureLogging")
	}()
	// Whether or not we autoforked, we're now running in client-server
	// mode (as opposed to standalone). Register a global LogUI so that
	// calls to G.Log() in the daemon can be copied to us. This is
	// something of a hack on the daemon side.
	if !g.Env.GetDoLogForward() || cl.GetLogForward() == libcmdline.LogForwardNone {
		g.Log.Debug("Disabling log forwarding")
		return nil
	}

	protocols := []rpc.Protocol{client.NewLogUIProtocol()}
	if err := client.RegisterProtocolsWithContext(protocols, g); err != nil {
		return err
	}

	logLevel := keybase1.LogLevel_INFO
	if g.Env.GetDebug() {
		logLevel = keybase1.LogLevel_DEBUG
	}
	logClient, err := client.GetLogClient(g)
	if err != nil {
		return err
	}
	arg := keybase1.RegisterLoggerArg{
		Name:  "CLI client",
		Level: logLevel,
	}
	if err := logClient.RegisterLogger(context.TODO(), arg); err != nil {
		g.Log.Warning("Failed to register as a logger: %s", err)
	}

	return nil
}

// configurePath sends the client's PATH to the service.
func configurePath(g *libkb.GlobalContext, cl *libcmdline.CommandLine) error {
	if cl.IsService() {
		// this only runs on the client
		return nil
	}

	return client.SendPath(g)
}

func HandleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, os.Kill)
	for {
		s := <-c
		if s != nil {
			G.Log.Debug("trapped signal %v", s)

			// if the current command has a Stop function, then call it.
			// It will do its own stopping of the process and calling
			// shutdown
			if stop, ok := cmd.(Stopper); ok {
				G.Log.Debug("Stopping command cleanly via stopper")
				stop.Stop(keybase1.ExitCode_OK)
				return
			}

			// if the current command has a Cancel function, then call it:
			if canc, ok := cmd.(Canceler); ok {
				G.Log.Debug("canceling running command")
				if err := canc.Cancel(); err != nil {
					G.Log.Warning("error canceling command: %s", err)
				}
			}

			G.Log.Debug("calling shutdown")
			G.Shutdown()
			G.Log.Error("interrupted")
			os.Exit(3)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"path"

	keybase1 "github.com/keybase/client/go/protocol"
)

// InviteArg contains optional invitation arguments.
type InviteArg struct {
	Message    string
	NoteToSelf string
}

type Invitation struct {
	ID        string
	ShortCode string
	Throttled bool
}

func (i Invitation) Link() string {
	if i.Throttled {
		return ""
	}
	return path.Join(CanonicalHost, "inv", i.ShortCode[0:10])
}

func (i InviteArg) ToHTTPArgs() HTTPArgs {
	return HTTPArgs{
		"invitation_message": S{Val: i.Message},
		"note_to_self":       S{Val: i.NoteToSelf},
	}
}

func SendInvitation(g *GlobalContext, email string, arg InviteArg) (*Invitation, error) {
	hargs := arg.ToHTTPArgs()
	hargs["email"] = S{Val: email}
	return callSendInvitation(g, hargs)
}

func GenerateInvitationCode(g *GlobalContext, arg InviteArg) (*Invitation, error) {
	return callSendInvitation(g, arg.ToHTTPArgs())
}

func GenerateInvitationCodeForAssertion(g *GlobalContext, assertion keybase1.SocialAssertion, arg InviteArg) (*Invitation, error) {
	hargs := arg.ToHTTPArgs()
	hargs["assertion"] = S{Val: assertion.String()}
	return callSendInvitation(g, hargs)
}

func callSendInvitation(g *GlobalContext, params HTTPArgs) (*Invitation, error) {
	arg := APIArg{
		Endpoint:       "send_invitation",
		NeedSession:    true,
		Contextified:   NewContextified(g),
		Args:           params,
		AppStatusCodes: []int{SCOk, SCThrottleControl},
	}
	res, err := g.API.Post(arg)
	if err != nil {
		return nil, err
	}

	var inv Invitation

	if res.AppStatus.Code == SCThrottleControl {
		g.Log.Debug("send_invitation returned SCThrottleControl: user is out of invites")
		inv.Throttled = true
		return &inv, nil
	}

	inv.ID, err = res.Body.AtKey("invitation_id").GetString()
	if err != nil {
		return nil, err
	}
	inv.ShortCode, err = res.Body.AtKey("short_code").GetString()
	if err != nil {
		return nil, err
	}
	return &inv, nil
}
<commit_msg>Fix invite link<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"path"

	keybase1 "github.com/keybase/client/go/protocol"
)

// InviteArg contains optional invitation arguments.
type InviteArg struct {
	Message    string
	NoteToSelf string
}

type Invitation struct {
	ID        string
	ShortCode string
	Throttled bool
}

func (i Invitation) Link() string {
	if i.Throttled {
		return ""
	}
	return path.Join(CanonicalHost, "inv", i.ID[0:10])
}

func (i InviteArg) ToHTTPArgs() HTTPArgs {
	return HTTPArgs{
		"invitation_message": S{Val: i.Message},
		"note_to_self":       S{Val: i.NoteToSelf},
	}
}

func SendInvitation(g *GlobalContext, email string, arg InviteArg) (*Invitation, error) {
	hargs := arg.ToHTTPArgs()
	hargs["email"] = S{Val: email}
	return callSendInvitation(g, hargs)
}

func GenerateInvitationCode(g *GlobalContext, arg InviteArg) (*Invitation, error) {
	return callSendInvitation(g, arg.ToHTTPArgs())
}

func GenerateInvitationCodeForAssertion(g *GlobalContext, assertion keybase1.SocialAssertion, arg InviteArg) (*Invitation, error) {
	hargs := arg.ToHTTPArgs()
	hargs["assertion"] = S{Val: assertion.String()}
	return callSendInvitation(g, hargs)
}

func callSendInvitation(g *GlobalContext, params HTTPArgs) (*Invitation, error) {
	arg := APIArg{
		Endpoint:       "send_invitation",
		NeedSession:    true,
		Contextified:   NewContextified(g),
		Args:           params,
		AppStatusCodes: []int{SCOk, SCThrottleControl},
	}
	res, err := g.API.Post(arg)
	if err != nil {
		return nil, err
	}

	var inv Invitation

	if res.AppStatus.Code == SCThrottleControl {
		g.Log.Debug("send_invitation returned SCThrottleControl: user is out of invites")
		inv.Throttled = true
		return &inv, nil
	}

	inv.ID, err = res.Body.AtKey("invitation_id").GetString()
	if err != nil {
		return nil, err
	}
	inv.ShortCode, err = res.Body.AtKey("short_code").GetString()
	if err != nil {
		return nil, err
	}
	return &inv, nil
}
<|endoftext|>