<commit_before>// Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 logger

import (
	"os"
	"strings"
	"sync"

	log15 "gopkg.in/inconshreveable/log15.v2"
)

const (
	LOGLEVEL_ENV_VAR = "ECS_LOGLEVEL"
	LOGFILE_ENV_VAR  = "ECS_LOGFILE"

	DEFAULT_LOGLEVEL = log15.LvlWarn
)

// This logger is the base that all other loggers should inherit from
var logger log15.Logger
var logfile string
var level log15.Lvl

// Initialize this logger once
var once sync.Once

func initLogger() {
	logger = log15.New()

	envLevel := os.Getenv(LOGLEVEL_ENV_VAR)
	SetLevel(envLevel)

	logfile = os.Getenv(LOGFILE_ENV_VAR)

	SetHandlerChain()
}

func init() {
	once.Do(initLogger)
}

// This package relies on the log15 backend. It is simply a place to centralize
// instantiations of loggers so they all have the same basic config
func SetLevel(logLevel string) {
	parsedLevel, err := log15.LvlFromString(strings.ToLower(logLevel))
	if err == nil {
		level = parsedLevel
	}

	SetHandlerChain()
}

func SetHandlerChain() {
	// Filehandler is an optional handler that always logs at debug level when
	// set, but only runs if the LOGFILE_ENV_VAR (ECS_LOGFILE) is set.
	var fileHandler log15.Handler
	if logfile == "" {
		fileHandler = log15.DiscardHandler()
	} else {
		fileHandler = log15.CallerStackHandler("%+v", log15.Must.FileHandler(logfile, log15.LogfmtFormat()))
	}

	logger.SetHandler(
		log15.LazyHandler(
			log15.MultiHandler(
				log15.LvlFilterHandler(level,
					log15.StdoutHandler,
				),
				fileHandler,
			),
		),
	)
}

func ForModule(module string) log15.Logger {
	once.Do(initLogger)

	SetHandlerChain()

	return logger.New("module", module)
}
<commit_msg>Use log level set by ECS_LOGLEVEL env for file handler.<commit_after>// Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 logger

import (
	"os"
	"strings"
	"sync"

	log15 "gopkg.in/inconshreveable/log15.v2"
)

const (
	LOGLEVEL_ENV_VAR = "ECS_LOGLEVEL"
	LOGFILE_ENV_VAR  = "ECS_LOGFILE"

	DEFAULT_LOGLEVEL = log15.LvlWarn
)

// This logger is the base that all other loggers should inherit from
var logger log15.Logger
var logfile string
var level log15.Lvl

// Initialize this logger once
var once sync.Once

func initLogger() {
	logger = log15.New()

	envLevel := os.Getenv(LOGLEVEL_ENV_VAR)
	SetLevel(envLevel)

	logfile = os.Getenv(LOGFILE_ENV_VAR)

	SetHandlerChain()
}

func init() {
	once.Do(initLogger)
}

// This package relies on the log15 backend. It is simply a place to centralize
// instantiations of loggers so they all have the same basic config
func SetLevel(logLevel string) {
	parsedLevel, err := log15.LvlFromString(strings.ToLower(logLevel))
	if err == nil {
		level = parsedLevel
	}

	SetHandlerChain()
}

func SetHandlerChain() {
	// Filehandler is an optional handler that only runs if the
	// LOGFILE_ENV_VAR (ECS_LOGFILE) is set.
	var fileHandler log15.Handler
	if logfile == "" {
		fileHandler = log15.DiscardHandler()
	} else {
		fileHandler = log15.CallerStackHandler("%+v", log15.Must.FileHandler(logfile, log15.LogfmtFormat()))
	}

	logger.SetHandler(
		log15.LazyHandler(
			log15.MultiHandler(
				log15.LvlFilterHandler(level,
					log15.StdoutHandler,
				),
				log15.LvlFilterHandler(level,
					fileHandler,
				),
			),
		),
	)
}

func ForModule(module string) log15.Logger {
	once.Do(initLogger)

	SetHandlerChain()

	return logger.New("module", module)
}
<|endoftext|>


<commit_before>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package amqp

import (
	"os"
	"testing"
	"time"

	"github.com/TheThingsNetwork/ttn/core/types"
	. "github.com/smartystreets/assertions"
	AMQP "github.com/streadway/amqp"
)

var host string

func init() {
	host = os.Getenv("AMQP_ADDRESS")
	if host == "" {
		host = "localhost:5672"
	}
}

func TestNewClient(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestNewClient"), "guest", "guest", host)
	a.So(c, ShouldNotBeNil)
}

func TestConnect(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestConnect"), "guest", "guest", host)
	err := c.Connect()
	defer c.Disconnect()
	a.So(err, ShouldBeNil)

	// Connecting while already connected should not change anything
	err = c.Connect()
	defer c.Disconnect()
	a.So(err, ShouldBeNil)
}

func TestConnectInvalidAddress(t *testing.T) {
	a := New(t)
	ConnectRetries = 2
	ConnectRetryDelay = 50 * time.Millisecond
	c := NewClient(getLogger(t, "TestConnectInvalidAddress"), "guest", "guest", "localhost:56720")
	err := c.Connect()
	defer c.Disconnect()
	a.So(err, ShouldNotBeNil)
}

func TestIsConnected(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestIsConnected"), "guest", "guest", host)

	a.So(c.IsConnected(), ShouldBeFalse)

	c.Connect()
	defer c.Disconnect()

	a.So(c.IsConnected(), ShouldBeTrue)
}

func TestDisconnect(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestDisconnect"), "guest", "guest", host)

	// Disconnecting when not connected should not change anything
	c.Disconnect()
	a.So(c.IsConnected(), ShouldBeFalse)

	c.Connect()
	defer c.Disconnect()
	c.Disconnect()

	a.So(c.IsConnected(), ShouldBeFalse)
}

func TestReopenChannelClient(t *testing.T) {
	a := New(t)
	ctx := getLogger(t, "TestReopenChannelClient")
	c := NewClient(ctx, "guest", "guest", host).(*DefaultClient)
	closed, err := c.connect(false)
	a.So(err, ShouldBeNil)
	defer c.Disconnect()

	publisher := c.NewPublisher("amq.topic")
	err = publisher.Open()
	a.So(err, ShouldBeNil)
	defer publisher.Close()

	subscriber := c.NewSubscriber("amq.topic", "", false, true)
	err = subscriber.Open()
	a.So(err, ShouldBeNil)
	defer subscriber.Close()

	downs := make(chan types.DownlinkMessage, 1)
	err = subscriber.SubscribeDownlink(func(_ Subscriber, appID string, _ string, msg types.DownlinkMessage) {
		a.So(appID, ShouldEqual, "app")
		ctx.Debugf("Got downlink message")
		downs <- msg
	})
	a.So(err, ShouldBeNil)

	test := func() {
		ctx.Debug("Testing publish")
		err := publisher.PublishDownlink(types.DownlinkMessage{
			AppID: "app",
		})
		a.So(err, ShouldBeNil)
		select {
		case <-downs:
		case <-time.After(100 * time.Millisecond):
			panic("Published message didn't come in in time")
		}
		return
	}

	// First attempt should be OK
	test()

	// Make sure that the old channel is closed
	publisher.(*DefaultPublisher).channel.Close()
	subscriber.(*DefaultSubscriber).channel.Close()

	// Simulate a connection close so a new channel should be opened
	closed <- AMQP.ErrClosed

	// Give the reconnect some time
	time.Sleep(100 * time.Millisecond)

	// Second attempt should be OK as well and will only work on a new channel
	test()
	a.So(err, ShouldBeNil)
}
<commit_msg>Don't delete the test channel, we need it for reuse<commit_after>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package amqp

import (
	"os"
	"testing"
	"time"

	"github.com/TheThingsNetwork/ttn/core/types"
	. "github.com/smartystreets/assertions"
	AMQP "github.com/streadway/amqp"
)

var host string

func init() {
	host = os.Getenv("AMQP_ADDRESS")
	if host == "" {
		host = "localhost:5672"
	}
}

func TestNewClient(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestNewClient"), "guest", "guest", host)
	a.So(c, ShouldNotBeNil)
}

func TestConnect(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestConnect"), "guest", "guest", host)
	err := c.Connect()
	defer c.Disconnect()
	a.So(err, ShouldBeNil)

	// Connecting while already connected should not change anything
	err = c.Connect()
	defer c.Disconnect()
	a.So(err, ShouldBeNil)
}

func TestConnectInvalidAddress(t *testing.T) {
	a := New(t)
	ConnectRetries = 2
	ConnectRetryDelay = 50 * time.Millisecond
	c := NewClient(getLogger(t, "TestConnectInvalidAddress"), "guest", "guest", "localhost:56720")
	err := c.Connect()
	defer c.Disconnect()
	a.So(err, ShouldNotBeNil)
}

func TestIsConnected(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestIsConnected"), "guest", "guest", host)

	a.So(c.IsConnected(), ShouldBeFalse)

	c.Connect()
	defer c.Disconnect()

	a.So(c.IsConnected(), ShouldBeTrue)
}

func TestDisconnect(t *testing.T) {
	a := New(t)
	c := NewClient(getLogger(t, "TestDisconnect"), "guest", "guest", host)

	// Disconnecting when not connected should not change anything
	c.Disconnect()
	a.So(c.IsConnected(), ShouldBeFalse)

	c.Connect()
	defer c.Disconnect()
	c.Disconnect()

	a.So(c.IsConnected(), ShouldBeFalse)
}

func TestReopenChannelClient(t *testing.T) {
	a := New(t)
	ctx := getLogger(t, "TestReopenChannelClient")
	c := NewClient(ctx, "guest", "guest", host).(*DefaultClient)
	closed, err := c.connect(false)
	a.So(err, ShouldBeNil)
	defer c.Disconnect()

	publisher := c.NewPublisher("amq.topic")
	err = publisher.Open()
	a.So(err, ShouldBeNil)
	defer publisher.Close()

	subscriber := c.NewSubscriber("amq.topic", "", false, false)
	err = subscriber.Open()
	a.So(err, ShouldBeNil)
	defer subscriber.Close()

	downs := make(chan types.DownlinkMessage, 1)
	err = subscriber.SubscribeDownlink(func(_ Subscriber, appID string, _ string, msg types.DownlinkMessage) {
		a.So(appID, ShouldEqual, "app")
		ctx.Debugf("Got downlink message")
		downs <- msg
	})
	a.So(err, ShouldBeNil)

	test := func() {
		ctx.Debug("Testing publish")
		err := publisher.PublishDownlink(types.DownlinkMessage{
			AppID: "app",
		})
		a.So(err, ShouldBeNil)
		select {
		case <-downs:
		case <-time.After(100 * time.Millisecond):
			panic("Published message didn't come in in time")
		}
		return
	}

	// First attempt should be OK
	test()

	// Make sure that the old channel is closed
	publisher.(*DefaultPublisher).channel.Close()
	subscriber.(*DefaultSubscriber).channel.Close()

	// Simulate a connection close so a new channel should be opened
	closed <- AMQP.ErrClosed

	// Give the reconnect some time
	time.Sleep(100 * time.Millisecond)

	// Second attempt should be OK as well and will only work on a new channel
	test()
	a.So(err, ShouldBeNil)
}
<|endoftext|>


<commit_before>// Copyright 2016 CNI authors
//
// 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.

// This is a "meta-plugin". It reads in its own netconf, it does not create
// any network interface but just changes the network sysctl.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strings"

	"github.com/vishvananda/netlink"

	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/containernetworking/cni/pkg/version"

	"github.com/containernetworking/plugins/pkg/ns"
	bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
)

// TuningConf represents the network tuning configuration.
type TuningConf struct {
	types.NetConf
	SysCtl  map[string]string `json:"sysctl"`
	Mac     string            `json:"mac,omitempty"`
	Promisc bool              `json:"promisc,omitempty"`
	Mtu     int               `json:"mtu,omitempty"`

	RuntimeConfig struct {
		Mac string `json:"mac,omitempty"`
	} `json:"runtimeConfig,omitempty"`
	Args *struct {
		A *IPAMArgs `json:"cni"`
	} `json:"args"`
}

type IPAMArgs struct {
	SysCtl  *map[string]string `json:"sysctl"`
	Mac     *string            `json:"mac,omitempty"`
	Promisc *bool              `json:"promisc,omitempty"`
	Mtu     *int               `json:"mtu,omitempty"`
}

// MacEnvArgs represents CNI_ARG
type MacEnvArgs struct {
	types.CommonArgs
	MAC types.UnmarshallableString `json:"mac,omitempty"`
}

func parseConf(data []byte, envArgs string) (*TuningConf, error) {
	conf := TuningConf{Promisc: false}
	if err := json.Unmarshal(data, &conf); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}

	// Parse custom Mac from both env args
	if envArgs != "" {
		e := MacEnvArgs{}
		err := types.LoadArgs(envArgs, &e)
		if err != nil {
			return nil, err
		}

		if e.MAC != "" {
			conf.Mac = string(e.MAC)
		}
	}

	// Parse custom Mac from RuntimeConfig
	if conf.RuntimeConfig.Mac != "" {
		conf.Mac = conf.RuntimeConfig.Mac
	}

	// Get args
	if conf.Args != nil && conf.Args.A != nil {
		if conf.Args.A.SysCtl != nil {
			for k, v := range *conf.Args.A.SysCtl {
				conf.SysCtl[k] = v
			}
		}

		if conf.Args.A.Mac != nil {
			conf.Mac = *conf.Args.A.Mac
		}

		if conf.Args.A.Promisc != nil {
			conf.Promisc = *conf.Args.A.Promisc
		}

		if conf.Args.A.Mtu != nil {
			conf.Mtu = *conf.Args.A.Mtu
		}

	}

	return &conf, nil
}

func changeMacAddr(ifName string, newMacAddr string) error {
	addr, err := net.ParseMAC(newMacAddr)
	if err != nil {
		return fmt.Errorf("invalid args %v for MAC addr: %v", newMacAddr, err)
	}

	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	return netlink.LinkSetHardwareAddr(link, addr)
}

func updateResultsMacAddr(config TuningConf, ifName string, newMacAddr string) {
	// Parse previous result.
	if config.PrevResult == nil {
		return
	}

	version.ParsePrevResult(&config.NetConf)
	result, _ := current.NewResultFromResult(config.PrevResult)

	for _, i := range result.Interfaces {
		if i.Name == ifName {
			i.Mac = newMacAddr
		}
	}
}

func changePromisc(ifName string, val bool) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	if val {
		return netlink.SetPromiscOn(link)
	}
	return netlink.SetPromiscOff(link)
}

func changeMtu(ifName string, mtu int) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}
	return netlink.LinkSetMTU(link, mtu)
}

func cmdAdd(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	// The directory /proc/sys/net is per network namespace. Enter in the
	// network namespace before writing on it.

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		for key, value := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			// Refuse to modify sysctl parameters that don't belong
			// to the network subsystem.
			if !strings.HasPrefix(fileName, "/proc/sys/net/") {
				return fmt.Errorf("invalid net sysctl key: %q", key)
			}
			content := []byte(value)
			err := ioutil.WriteFile(fileName, content, 0644)
			if err != nil {
				return err
			}
		}

		if tuningConf.Mac != "" {
			if err = changeMacAddr(args.IfName, tuningConf.Mac); err != nil {
				return err
			}
			updateResultsMacAddr(*tuningConf, args.IfName, tuningConf.Mac)
		}

		if tuningConf.Promisc != false {
			if err = changePromisc(args.IfName, true); err != nil {
				return err
			}
		}

		if tuningConf.Mtu != 0 {
			if err = changeMtu(args.IfName, tuningConf.Mtu); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return types.PrintResult(tuningConf.PrevResult, tuningConf.CNIVersion)
}

func cmdDel(args *skel.CmdArgs) error {
	// TODO: the settings are not reverted to the previous values. Reverting the
	// settings is not useful when the whole container goes away but it could be
	// useful in scenarios where plugins are added and removed at runtime.
	return nil
}

func main() {
	skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, bv.BuildString("tuning"))
}

func cmdCheck(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		// Check each configured value vs what's currently in the container
		for key, confValue := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			contents, err := ioutil.ReadFile(fileName)
			if err != nil {
				return err
			}
			curValue := strings.TrimSuffix(string(contents), "\n")
			if confValue != curValue {
				return fmt.Errorf("Error: Tuning configured value of %s is %s, current value is %s", fileName, confValue, curValue)
			}
		}

		link, err := netlink.LinkByName(args.IfName)
		if err != nil {
			return fmt.Errorf("Cannot find container link %v", args.IfName)
		}

		if tuningConf.Mac != "" {
			if tuningConf.Mac != link.Attrs().HardwareAddr.String() {
				return fmt.Errorf("Error: Tuning configured Ethernet of %s is %s, current value is %s",
					args.IfName, tuningConf.Mac, link.Attrs().HardwareAddr)
			}
		}

		if tuningConf.Promisc {
			if link.Attrs().Promisc == 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		} else {
			if link.Attrs().Promisc != 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		}

		if tuningConf.Mtu != 0 {
			if tuningConf.Mtu != link.Attrs().MTU {
				return fmt.Errorf("Error: Tuning configured MTU of %s is %d, current value is %d",
					args.IfName, tuningConf.Mtu, link.Attrs().MTU)
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Sending GratuitousArp in case of MAC address update<commit_after>// Copyright 2016 CNI authors
//
// 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.

// This is a "meta-plugin". It reads in its own netconf, it does not create
// any network interface but just changes the network sysctl.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strings"

	"github.com/j-keck/arping"
	"github.com/vishvananda/netlink"

	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/containernetworking/cni/pkg/version"

	"github.com/containernetworking/plugins/pkg/ns"
	bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
)

// TuningConf represents the network tuning configuration.
type TuningConf struct {
	types.NetConf
	SysCtl  map[string]string `json:"sysctl"`
	Mac     string            `json:"mac,omitempty"`
	Promisc bool              `json:"promisc,omitempty"`
	Mtu     int               `json:"mtu,omitempty"`

	RuntimeConfig struct {
		Mac string `json:"mac,omitempty"`
	} `json:"runtimeConfig,omitempty"`
	Args *struct {
		A *IPAMArgs `json:"cni"`
	} `json:"args"`
}

type IPAMArgs struct {
	SysCtl  *map[string]string `json:"sysctl"`
	Mac     *string            `json:"mac,omitempty"`
	Promisc *bool              `json:"promisc,omitempty"`
	Mtu     *int               `json:"mtu,omitempty"`
}

// MacEnvArgs represents CNI_ARG
type MacEnvArgs struct {
	types.CommonArgs
	MAC types.UnmarshallableString `json:"mac,omitempty"`
}

func parseConf(data []byte, envArgs string) (*TuningConf, error) {
	conf := TuningConf{Promisc: false}
	if err := json.Unmarshal(data, &conf); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}

	// Parse custom Mac from both env args
	if envArgs != "" {
		e := MacEnvArgs{}
		err := types.LoadArgs(envArgs, &e)
		if err != nil {
			return nil, err
		}

		if e.MAC != "" {
			conf.Mac = string(e.MAC)
		}
	}

	// Parse custom Mac from RuntimeConfig
	if conf.RuntimeConfig.Mac != "" {
		conf.Mac = conf.RuntimeConfig.Mac
	}

	// Get args
	if conf.Args != nil && conf.Args.A != nil {
		if conf.Args.A.SysCtl != nil {
			for k, v := range *conf.Args.A.SysCtl {
				conf.SysCtl[k] = v
			}
		}

		if conf.Args.A.Mac != nil {
			conf.Mac = *conf.Args.A.Mac
		}

		if conf.Args.A.Promisc != nil {
			conf.Promisc = *conf.Args.A.Promisc
		}

		if conf.Args.A.Mtu != nil {
			conf.Mtu = *conf.Args.A.Mtu
		}

	}

	return &conf, nil
}

func changeMacAddr(ifName string, newMacAddr string) error {
	addr, err := net.ParseMAC(newMacAddr)
	if err != nil {
		return fmt.Errorf("invalid args %v for MAC addr: %v", newMacAddr, err)
	}

	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	return netlink.LinkSetHardwareAddr(link, addr)
}

func updateResultsMacAddr(config TuningConf, ifName string, newMacAddr string) {
	// Parse previous result.
	if config.PrevResult == nil {
		return
	}

	version.ParsePrevResult(&config.NetConf)
	result, _ := current.NewResultFromResult(config.PrevResult)

	for _, i := range result.Interfaces {
		if i.Name == ifName {
			i.Mac = newMacAddr
		}
	}
}

func changePromisc(ifName string, val bool) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	if val {
		return netlink.SetPromiscOn(link)
	}
	return netlink.SetPromiscOff(link)
}

func changeMtu(ifName string, mtu int) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}
	return netlink.LinkSetMTU(link, mtu)
}

func cmdAdd(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	result, err := current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	// The directory /proc/sys/net is per network namespace. Enter in the
	// network namespace before writing on it.

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		for key, value := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			// Refuse to modify sysctl parameters that don't belong
			// to the network subsystem.
			if !strings.HasPrefix(fileName, "/proc/sys/net/") {
				return fmt.Errorf("invalid net sysctl key: %q", key)
			}
			content := []byte(value)
			err := ioutil.WriteFile(fileName, content, 0644)
			if err != nil {
				return err
			}
		}

		if tuningConf.Mac != "" {
			if err = changeMacAddr(args.IfName, tuningConf.Mac); err != nil {
				return err
			}

			for _, ipc := range result.IPs {
				if ipc.Version == "4" {
					_ = arping.GratuitousArpOverIfaceByName(ipc.Address.IP, args.IfName)
				}
			}

			updateResultsMacAddr(*tuningConf, args.IfName, tuningConf.Mac)
		}

		if tuningConf.Promisc != false {
			if err = changePromisc(args.IfName, true); err != nil {
				return err
			}
		}

		if tuningConf.Mtu != 0 {
			if err = changeMtu(args.IfName, tuningConf.Mtu); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return types.PrintResult(tuningConf.PrevResult, tuningConf.CNIVersion)
}

func cmdDel(args *skel.CmdArgs) error {
	// TODO: the settings are not reverted to the previous values. Reverting the
	// settings is not useful when the whole container goes away but it could be
	// useful in scenarios where plugins are added and removed at runtime.
	return nil
}

func main() {
	skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, bv.BuildString("tuning"))
}

func cmdCheck(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		// Check each configured value vs what's currently in the container
		for key, confValue := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			contents, err := ioutil.ReadFile(fileName)
			if err != nil {
				return err
			}
			curValue := strings.TrimSuffix(string(contents), "\n")
			if confValue != curValue {
				return fmt.Errorf("Error: Tuning configured value of %s is %s, current value is %s", fileName, confValue, curValue)
			}
		}

		link, err := netlink.LinkByName(args.IfName)
		if err != nil {
			return fmt.Errorf("Cannot find container link %v", args.IfName)
		}

		if tuningConf.Mac != "" {
			if tuningConf.Mac != link.Attrs().HardwareAddr.String() {
				return fmt.Errorf("Error: Tuning configured Ethernet of %s is %s, current value is %s",
					args.IfName, tuningConf.Mac, link.Attrs().HardwareAddr)
			}
		}

		if tuningConf.Promisc {
			if link.Attrs().Promisc == 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		} else {
			if link.Attrs().Promisc != 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		}

		if tuningConf.Mtu != 0 {
			if tuningConf.Mtu != link.Attrs().MTU {
				return fmt.Errorf("Error: Tuning configured MTU of %s is %d, current value is %d",
					args.IfName, tuningConf.Mtu, link.Attrs().MTU)
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"syscall"
)

const (
	StateNil = iota
	StateInitialized
	StateRunning
)

type Program struct {
	config *ProgramConfig
	// internal program logger to capture all program output
	logger *log.Logger
	// actual user struct data based on Username lookup
	user  *user.User
	state int
	cmd   *exec.Cmd
}

// ProgramConfig holds all the parameters for going to run and maintain the
// state of the supervised process. These variables are all configurable via
// the program's yaml format config file, except for non primitive types such
// as ProgramConfig.Log.
type ProgramConfig struct {
	Command     string
	Environment map[string]string
	Log         logConfig
	// internal identifier
	Name        string
	ProcessName string
	StopSignal  syscall.Signal
	Username    string
	Dir         string
}

// init sets up other data and structs and performs checks to make sure
// everything is available to properly run. The logger param is sent by the
// parent going struct.
func (p *Program) init() error {
	var err error

	p.user, err = user.Lookup(p.config.Username)
	if err != nil {
		return fmt.Errorf(
			"Could not lookup username \"%s\" for program \"%s\".",
			p.config.Username,
			p.config.Name,
		)
	}

	err = p.loadLogger()
	if err != nil {
		return fmt.Errorf(
			"Could not load logger for program \"%s\".",
			p.config.Name,
		)
	}

	p.cmd = exec.Command(p.config.Command)
	p.cmd.Dir = p.config.Dir
	for key, value := range p.config.Environment {
		p.cmd.Env = append(p.cmd.Env, key+"="+value)
	}

	p.state = StateInitialized

	return err
}

func (p *Program) run() {
	p.cmd.Run()

}

func (p *Program) loadLogger() error {
	var file *os.File
	var err error
	logFile := filepath.Join(p.config.Log.Dir, p.config.Name+".log")
	if fileExists(logFile) {
		file, err = os.OpenFile(logFile, os.O_APPEND, os.ModeAppend)
	} else {
		file, err = os.Create(logFile)
	}
	if err != nil {
		return err
	}
	p.logger = log.New(file, "", log.LstdFlags)
	return nil
}

func newProgramConfig(filename string) (*ProgramConfig, error) {
	c := new(ProgramConfig)
	err := loadYaml(filename, c)

	if err != nil {
		err = fmt.Errorf("Could not load program config file \"%s\": %s", filename, err)
	}
	return c, err
}
<commit_msg>corrected docs<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"syscall"
)

const (
	StateNil = iota
	StateInitialized
	StateRunning
)

type Program struct {
	config *ProgramConfig
	// internal program logger to capture all program output
	logger *log.Logger
	// actual user struct data based on Username lookup
	user  *user.User
	state int
	cmd   *exec.Cmd
}

// ProgramConfig holds all the parameters for going to run and maintain the
// state of the supervised process. These variables are all configurable via
// the program's yaml format config file.
type ProgramConfig struct {
	Command     string
	Environment map[string]string
	Log         logConfig
	// internal identifier
	Name        string
	ProcessName string
	StopSignal  syscall.Signal
	Username    string
	Dir         string
}

// init sets up other data and structs and performs checks to make sure
// everything is available to properly run. The logger param is sent by the
// parent going struct.
func (p *Program) init() error {
	var err error

	p.user, err = user.Lookup(p.config.Username)
	if err != nil {
		return fmt.Errorf(
			"Could not lookup username \"%s\" for program \"%s\".",
			p.config.Username,
			p.config.Name,
		)
	}

	err = p.loadLogger()
	if err != nil {
		return fmt.Errorf(
			"Could not load logger for program \"%s\".",
			p.config.Name,
		)
	}

	p.cmd = exec.Command(p.config.Command)
	p.cmd.Dir = p.config.Dir
	for key, value := range p.config.Environment {
		p.cmd.Env = append(p.cmd.Env, key+"="+value)
	}

	p.state = StateInitialized

	return err
}

func (p *Program) run() {
	p.cmd.Run()

}

func (p *Program) loadLogger() error {
	var file *os.File
	var err error
	logFile := filepath.Join(p.config.Log.Dir, p.config.Name+".log")
	if fileExists(logFile) {
		file, err = os.OpenFile(logFile, os.O_APPEND, os.ModeAppend)
	} else {
		file, err = os.Create(logFile)
	}
	if err != nil {
		return err
	}
	p.logger = log.New(file, "", log.LstdFlags)
	return nil
}

func newProgramConfig(filename string) (*ProgramConfig, error) {
	c := new(ProgramConfig)
	err := loadYaml(filename, c)

	if err != nil {
		err = fmt.Errorf("Could not load program config file \"%s\": %s", filename, err)
	}
	return c, err
}
<|endoftext|>


<commit_before>// Copyright 2013 Chris McGee <sirnewton_01@yahoo.ca>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package gdblib

import (
	"go/build"
	"os"
	"os/exec"
)

var (
	sendSignalPath string
)

func init() {
	gopath := build.Default.GOPATH
	sendSignalPath = gopath + "\\src\\github.com\\sirnewton01\\gdblib\\SendSignal.exe"
}

func fixCmd(cmd *exec.Cmd) {
	// No process group separation is required on Windows.
	// Processes do not share signals like they can on Unix.
}

func interruptInferior(process *os.Process, pid string) {
	// Invoke the included "sendsignal" program to send the
	// Ctrl-break to the inferior process to interrupt it

	initCommand := exec.Command("cmd", "/c", "start", sendSignalPath, pid)
	initCommand.Run()
}
<commit_msg>Handle multiple gopaths on windows.<commit_after>// Copyright 2013 Chris McGee <sirnewton_01@yahoo.ca>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package gdblib

import (
	"go/build"
	"os"
	"os/exec"
	"path/filepath"
)

var (
	sendSignalPath string
)

func init() {
	gopath := build.Default.GOPATH
	gopaths := strins.Split(gopath, filepath.ListSeparator)
	for _,path := range(gopaths) {
		p := path + "\\src\\github.com\\sirnewton01\\gdblib\\SendSignal.exe"
		_,err := os.Stat(p)
		if err == nil {
			sendSignalPath = p
			break
		}
	}
}

func fixCmd(cmd *exec.Cmd) {
	// No process group separation is required on Windows.
	// Processes do not share signals like they can on Unix.
}

func interruptInferior(process *os.Process, pid string) {
	// Invoke the included "sendsignal" program to send the
	// Ctrl-break to the inferior process to interrupt it

	initCommand := exec.Command("cmd", "/c", "start", sendSignalPath, pid)
	initCommand.Run()
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Daniel Oaks <daniel@danieloaks.net>
// Copyright (c) 2018-2019 Shivaram Lingamneni <slingamn@cs.stanford.edu>

// released under the ISC license

package ircmsg

import (
	"bytes"
	"errors"
	"strings"
)

const (
	// "The size limit for message tags is 8191 bytes, including the leading
	//  '@' (0x40) and trailing space ' ' (0x20) characters."
	MaxlenTags = 8191

	// MaxlenTags - ('@' + ' ')
	MaxlenTagData = MaxlenTags - 2

	// "Clients MUST NOT send messages with tag data exceeding 4094 bytes,
	//  this includes tags with or without the client-only prefix."
	MaxlenClientTagData = 4094

	// "Servers MUST NOT add tag data exceeding 4094 bytes to messages."
	MaxlenServerTagData = 4094

	// '@' + MaxlenClientTagData + ' '
	// this is the analogue of MaxlenTags when the source of the message is a client
	MaxlenTagsFromClient = MaxlenClientTagData + 2
)

var (
	// ErrorLineIsEmpty indicates that the given IRC line was empty.
	ErrorLineIsEmpty = errors.New("Line is empty")
	// ErrorLineContainsBadChar indicates that the line contained invalid characters
	ErrorLineContainsBadChar = errors.New("Line contains invalid characters")
	// ErrorLineTooLong indicates that the message exceeded the maximum tag length
	// (the name references 417 ERR_INPUTTOOLONG; we reserve the right to return it
	// for messages that exceed the non-tag length limit)
	ErrorLineTooLong = errors.New("Line could not be parsed because a specified length limit was exceeded")

	ErrorCommandMissing = errors.New("IRC messages MUST have a command")
	ErrorBadParam       = errors.New("Cannot have an empty param, a param with spaces, or a param that starts with ':' before the last parameter")
)

// IrcMessage represents an IRC message, as defined by the RFCs and as
// extended by the IRCv3 Message Tags specification with the introduction
// of message tags.
type IrcMessage struct {
	Prefix         string
	Command        string
	Params         []string
	forceTrailing  bool
	tags           map[string]string
	clientOnlyTags map[string]string
}

// ForceTrailing ensures that when the message is serialized, the final parameter
// will be encoded as a "trailing parameter", i.e., preceded by a colon. This is
// necessary for compatibility with incorrect implementations.
func (msg *IrcMessage) ForceTrailing() {
	msg.forceTrailing = true
}

// GetTag returns whether a tag is present, and if so, what its value is.
func (msg *IrcMessage) GetTag(tagName string) (present bool, value string) {
	if len(tagName) == 0 {
		return
	} else if tagName[0] == '+' {
		value, present = msg.clientOnlyTags[tagName]
		return
	} else {
		value, present = msg.tags[tagName]
		return
	}
}

// HasTag returns whether a tag is present.
func (msg *IrcMessage) HasTag(tagName string) (present bool) {
	present, _ = msg.GetTag(tagName)
	return
}

// SetTag sets a tag.
func (msg *IrcMessage) SetTag(tagName, tagValue string) {
	if len(tagName) == 0 {
		return
	} else if tagName[0] == '+' {
		if msg.clientOnlyTags == nil {
			msg.clientOnlyTags = make(map[string]string)
		}
		msg.clientOnlyTags[tagName] = tagValue
	} else {
		if msg.tags == nil {
			msg.tags = make(map[string]string)
		}
		msg.tags[tagName] = tagValue
	}
}

// DeleteTag deletes a tag.
func (msg *IrcMessage) DeleteTag(tagName string) {
	if len(tagName) == 0 {
		return
	} else if tagName[0] == '+' {
		delete(msg.clientOnlyTags, tagName)
	} else {
		delete(msg.tags, tagName)
	}
}

// UpdateTags is a convenience to set multiple tags at once.
func (msg *IrcMessage) UpdateTags(tags map[string]string) {
	for name, value := range tags {
		msg.SetTag(name, value)
	}
}

// AllTags returns all tags as a single map.
func (msg *IrcMessage) AllTags() (result map[string]string) {
	result = make(map[string]string, len(msg.tags)+len(msg.clientOnlyTags))
	for name, value := range msg.tags {
		result[name] = value
	}
	for name, value := range msg.clientOnlyTags {
		result[name] = value
	}
	return
}

// ClientOnlyTags returns the client-only tags (the tags with the + prefix).
// The returned map may be internal storage of the IrcMessage object and
// should not be modified.
func (msg *IrcMessage) ClientOnlyTags() map[string]string {
	return msg.clientOnlyTags
}

// ParseLine creates and returns a message from the given IRC line.
func ParseLine(line string) (ircmsg IrcMessage, err error) {
	return parseLine(line, 0, 0)
}

// ParseLineStrict creates and returns an IrcMessage from the given IRC line,
// taking the maximum length into account and truncating the message as appropriate.
// If fromClient is true, it enforces the client limit on tag data length (4094 bytes),
// allowing the server to return ERR_INPUTTOOLONG as appropriate. If truncateLen is
// nonzero, it is the length at which the non-tag portion of the message is truncated.
func ParseLineStrict(line string, fromClient bool, truncateLen int) (ircmsg IrcMessage, err error) {
	maxTagDataLength := MaxlenTagData
	if fromClient {
		maxTagDataLength = MaxlenClientTagData
	}
	return parseLine(line, maxTagDataLength, truncateLen)
}

// slice off any amount of ' ' from the front of the string
func trimInitialSpaces(str string) string {
	var i int
	for i = 0; i < len(str) && str[i] == ' '; i += 1 {
	}
	return str[i:]
}

func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg IrcMessage, err error) {
	if strings.IndexByte(line, '\x00') != -1 {
		err = ErrorLineContainsBadChar
		return
	}

	// trim to the first appearance of either '\r' or '\n':
	lineEnd := strings.IndexByte(line, '\r')
	newlineIndex := strings.IndexByte(line, '\n')
	if newlineIndex != -1 && (lineEnd == -1 || newlineIndex < lineEnd) {
		lineEnd = newlineIndex
	}
	if lineEnd != -1 {
		line = line[:lineEnd]
	}

	if len(line) < 1 {
		return ircmsg, ErrorLineIsEmpty
	}

	// tags
	if line[0] == '@' {
		tagEnd := strings.IndexByte(line, ' ')
		if tagEnd == -1 {
			return ircmsg, ErrorLineIsEmpty
		}
		tags := line[1:tagEnd]
		if 0 < maxTagDataLength && maxTagDataLength < len(tags) {
			return ircmsg, ErrorLineTooLong
		}
		err = ircmsg.parseTags(tags)
		if err != nil {
			return
		}
		// skip over the tags and the separating space
		line = line[tagEnd+1:]
	}

	// truncate if desired
	if 0 < truncateLen && truncateLen < len(line) {
		line = line[:truncateLen]
	}

	// modern: "These message parts, and parameters themselves, are separated
	// by one or more ASCII SPACE characters"
	line = trimInitialSpaces(line)

	// prefix
	if 0 < len(line) && line[0] == ':' {
		prefixEnd := strings.IndexByte(line, ' ')
		if prefixEnd == -1 {
			return ircmsg, ErrorLineIsEmpty
		}
		ircmsg.Prefix = line[1:prefixEnd]
		// skip over the prefix and the separating space
		line = line[prefixEnd+1:]
	}

	line = trimInitialSpaces(line)

	// command
	commandEnd := strings.IndexByte(line, ' ')
	paramStart := commandEnd + 1
	if commandEnd == -1 {
		commandEnd = len(line)
		paramStart = len(line)
	}
	// normalize command to uppercase:
	ircmsg.Command = strings.ToUpper(line[:commandEnd])
	if len(ircmsg.Command) == 0 {
		return ircmsg, ErrorLineIsEmpty
	}
	line = line[paramStart:]

	for {
		line = trimInitialSpaces(line)
		if len(line) == 0 {
			break
		}
		// handle trailing
		if line[0] == ':' {
			ircmsg.Params = append(ircmsg.Params, line[1:])
			break
		}
		paramEnd := strings.IndexByte(line, ' ')
		if paramEnd == -1 {
			ircmsg.Params = append(ircmsg.Params, line)
			break
		}
		ircmsg.Params = append(ircmsg.Params, line[:paramEnd])
		line = line[paramEnd+1:]
	}

	return ircmsg, nil
}

// helper to parse tags
func (ircmsg *IrcMessage) parseTags(tags string) (err error) {
	for 0 < len(tags) {
		tagEnd := strings.IndexByte(tags, ';')
		endPos := tagEnd
		nextPos := tagEnd + 1
		if tagEnd == -1 {
			endPos = len(tags)
			nextPos = len(tags)
		}
		tagPair := tags[:endPos]
		equalsIndex := strings.IndexByte(tagPair, '=')
		var tagName, tagValue string
		if equalsIndex == -1 {
			// tag with no value
			tagName = tagPair
		} else {
			tagName, tagValue = tagPair[:equalsIndex], tagPair[equalsIndex+1:]
		}
		ircmsg.SetTag(tagName, UnescapeTagValue(tagValue))
		// skip over the tag just processed, plus the delimiting ; if any
		tags = tags[nextPos:]
	}
	return nil
}

// MakeMessage provides a simple way to create a new IrcMessage.
func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg IrcMessage) {
	ircmsg.Prefix = prefix
	ircmsg.Command = command
	ircmsg.Params = params
	ircmsg.UpdateTags(tags)
	return ircmsg
}

// Line returns a sendable line created from an IrcMessage.
func (ircmsg *IrcMessage) Line() (result string, err error) {
	bytes, err := ircmsg.line(0, 0, 0, 0)
	if err == nil {
		result = string(bytes)
	}
	return
}

// LineBytes returns a sendable line created from an IrcMessage.
func (ircmsg *IrcMessage) LineBytes() (result []byte, err error) {
	result, err = ircmsg.line(0, 0, 0, 0)
	return
}

// LineBytesStrict returns a sendable line, as a []byte, created from an IrcMessage.
// fromClient controls whether the server-side or client-side tag length limit
// is enforced. If truncateLen is nonzero, it is the length at which the
// non-tag portion of the message is truncated.
func (ircmsg *IrcMessage) LineBytesStrict(fromClient bool, truncateLen int) ([]byte, error) {
	var tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit int
	if fromClient {
		// enforce client max tags:
		// <client_max>   (4096)  :: '@' <tag_data 4094> ' '
		tagLimit = MaxlenTagsFromClient
	} else {
		// on the server side, enforce separate client-only and server-added tag budgets:
		// "Servers MUST NOT add tag data exceeding 4094 bytes to messages."
		// <combined_max> (8191)  :: '@' <tag_data 4094> ';' <tag_data 4094> ' '
		clientOnlyTagDataLimit = MaxlenClientTagData
		serverAddedTagDataLimit = MaxlenServerTagData
	}
	return ircmsg.line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen)
}

func paramRequiresTrailing(param string) bool {
	return len(param) == 0 || strings.IndexByte(param, ' ') != -1 || param[0] == ':'
}

// line returns a sendable line created from an IrcMessage.
func (ircmsg *IrcMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) ([]byte, error) {
	if len(ircmsg.Command) < 1 {
		return nil, ErrorCommandMissing
	}

	var buf bytes.Buffer

	// write the tags, computing the budgets for client-only tags and regular tags
	var lenRegularTags, lenClientOnlyTags, lenTags int
	if 0 < len(ircmsg.tags) || 0 < len(ircmsg.clientOnlyTags) {
		buf.WriteByte('@')
		firstTag := true
		writeTags := func(tags map[string]string) {
			for tag, val := range tags {
				if !firstTag {
					buf.WriteByte(';') // delimiter
				}
				buf.WriteString(tag)
				if val != "" {
					buf.WriteByte('=')
					buf.WriteString(EscapeTagValue(val))
				}
				firstTag = false
			}
		}
		writeTags(ircmsg.tags)
		lenRegularTags = buf.Len() - 1 // '@' is not counted
		writeTags(ircmsg.clientOnlyTags)
		lenClientOnlyTags = (buf.Len() - 1) - lenRegularTags // '@' is not counted
		if lenRegularTags != 0 {
			// semicolon between regular and client-only tags is not counted
			lenClientOnlyTags -= 1
		}
		buf.WriteByte(' ')
	}
	lenTags = buf.Len()

	if 0 < tagLimit && tagLimit < buf.Len() {
		return nil, ErrorLineTooLong
	}
	if (0 < clientOnlyTagDataLimit && clientOnlyTagDataLimit < lenClientOnlyTags) || (0 < serverAddedTagDataLimit && serverAddedTagDataLimit < lenRegularTags) {
		return nil, ErrorLineTooLong
	}

	if len(ircmsg.Prefix) > 0 {
		buf.WriteByte(':')
		buf.WriteString(ircmsg.Prefix)
		buf.WriteByte(' ')
	}

	buf.WriteString(ircmsg.Command)

	for i, param := range ircmsg.Params {
		buf.WriteByte(' ')
		requiresTrailing := paramRequiresTrailing(param)
		lastParam := i == len(ircmsg.Params)-1
		if (requiresTrailing || ircmsg.forceTrailing) && lastParam {
			buf.WriteByte(':')
		} else if requiresTrailing && !lastParam {
			return nil, ErrorBadParam
		}
		buf.WriteString(param)
	}

	// truncate if desired
	// -2 for \r\n
	restLen := buf.Len() - lenTags
	if 0 < truncateLen && (truncateLen-2) < restLen {
		buf.Truncate(lenTags + (truncateLen - 2))
	}
	buf.WriteString("\r\n")

	result := buf.Bytes()
	if bytes.IndexByte(result, '\x00') != -1 {
		return nil, ErrorLineContainsBadChar
	}
	return result, nil
}
<commit_msg>fix comment<commit_after>// Copyright (c) 2016-2019 Daniel Oaks <daniel@danieloaks.net>
// Copyright (c) 2018-2019 Shivaram Lingamneni <slingamn@cs.stanford.edu>

// released under the ISC license

package ircmsg

import (
	"bytes"
	"errors"
	"strings"
)

const (
	// "The size limit for message tags is 8191 bytes, including the leading
	//  '@' (0x40) and trailing space ' ' (0x20) characters."
	MaxlenTags = 8191

	// MaxlenTags - ('@' + ' ')
	MaxlenTagData = MaxlenTags - 2

	// "Clients MUST NOT send messages with tag data exceeding 4094 bytes,
	//  this includes tags with or without the client-only prefix."
	MaxlenClientTagData = 4094

	// "Servers MUST NOT add tag data exceeding 4094 bytes to messages."
	MaxlenServerTagData = 4094

	// '@' + MaxlenClientTagData + ' '
	// this is the analogue of MaxlenTags when the source of the message is a client
	MaxlenTagsFromClient = MaxlenClientTagData + 2
)

var (
	// ErrorLineIsEmpty indicates that the given IRC line was empty.
	ErrorLineIsEmpty = errors.New("Line is empty")
	// ErrorLineContainsBadChar indicates that the line contained invalid characters
	ErrorLineContainsBadChar = errors.New("Line contains invalid characters")
	// ErrorLineTooLong indicates that the message exceeded the maximum tag length
	// (the name references 417 ERR_INPUTTOOLONG; we reserve the right to return it
	// for messages that exceed the non-tag length limit)
	ErrorLineTooLong = errors.New("Line could not be parsed because a specified length limit was exceeded")

	ErrorCommandMissing = errors.New("IRC messages MUST have a command")
	ErrorBadParam       = errors.New("Cannot have an empty param, a param with spaces, or a param that starts with ':' before the last parameter")
)

// IrcMessage represents an IRC message, as defined by the RFCs and as
// extended by the IRCv3 Message Tags specification with the introduction
// of message tags.
type IrcMessage struct {
	Prefix         string
	Command        string
	Params         []string
	forceTrailing  bool
	tags           map[string]string
	clientOnlyTags map[string]string
}

// ForceTrailing ensures that when the message is serialized, the final parameter
// will be encoded as a "trailing parameter" (preceded by a colon). This is
// almost never necessary and should not be used except when having to interact
// with broken implementations that don't correctly interpret IRC messages.
func (msg *IrcMessage) ForceTrailing() {
	msg.forceTrailing = true
}

// GetTag returns whether a tag is present, and if so, what its value is.
func (msg *IrcMessage) GetTag(tagName string) (present bool, value string) {
	if len(tagName) == 0 {
		return
	} else if tagName[0] == '+' {
		value, present = msg.clientOnlyTags[tagName]
		return
	} else {
		value, present = msg.tags[tagName]
		return
	}
}

// HasTag returns whether a tag is present.
func (msg *IrcMessage) HasTag(tagName string) (present bool) {
	present, _ = msg.GetTag(tagName)
	return
}

// SetTag sets a tag.
func (msg *IrcMessage) SetTag(tagName, tagValue string) {
	if len(tagName) == 0 {
		return
	} else if tagName[0] == '+' {
		if msg.clientOnlyTags == nil {
			msg.clientOnlyTags = make(map[string]string)
		}
		msg.clientOnlyTags[tagName] = tagValue
	} else {
		if msg.tags == nil {
			msg.tags = make(map[string]string)
		}
		msg.tags[tagName] = tagValue
	}
}

// DeleteTag deletes a tag.
func (msg *IrcMessage) DeleteTag(tagName string) {
	if len(tagName) == 0 {
		return
	} else if tagName[0] == '+' {
		delete(msg.clientOnlyTags, tagName)
	} else {
		delete(msg.tags, tagName)
	}
}

// UpdateTags is a convenience to set multiple tags at once.
func (msg *IrcMessage) UpdateTags(tags map[string]string) {
	for name, value := range tags {
		msg.SetTag(name, value)
	}
}

// AllTags returns all tags as a single map.
func (msg *IrcMessage) AllTags() (result map[string]string) {
	result = make(map[string]string, len(msg.tags)+len(msg.clientOnlyTags))
	for name, value := range msg.tags {
		result[name] = value
	}
	for name, value := range msg.clientOnlyTags {
		result[name] = value
	}
	return
}

// ClientOnlyTags returns the client-only tags (the tags with the + prefix).
// The returned map may be internal storage of the IrcMessage object and
// should not be modified.
func (msg *IrcMessage) ClientOnlyTags() map[string]string {
	return msg.clientOnlyTags
}

// ParseLine creates and returns a message from the given IRC line.
func ParseLine(line string) (ircmsg IrcMessage, err error) {
	return parseLine(line, 0, 0)
}

// ParseLineStrict creates and returns an IrcMessage from the given IRC line,
// taking the maximum length into account and truncating the message as appropriate.
// If fromClient is true, it enforces the client limit on tag data length (4094 bytes),
// allowing the server to return ERR_INPUTTOOLONG as appropriate. If truncateLen is
// nonzero, it is the length at which the non-tag portion of the message is truncated.
func ParseLineStrict(line string, fromClient bool, truncateLen int) (ircmsg IrcMessage, err error) {
	maxTagDataLength := MaxlenTagData
	if fromClient {
		maxTagDataLength = MaxlenClientTagData
	}
	return parseLine(line, maxTagDataLength, truncateLen)
}

// slice off any amount of ' ' from the front of the string
func trimInitialSpaces(str string) string {
	var i int
	for i = 0; i < len(str) && str[i] == ' '; i += 1 {
	}
	return str[i:]
}

func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg IrcMessage, err error) {
	if strings.IndexByte(line, '\x00') != -1 {
		err = ErrorLineContainsBadChar
		return
	}

	// trim to the first appearance of either '\r' or '\n':
	lineEnd := strings.IndexByte(line, '\r')
	newlineIndex := strings.IndexByte(line, '\n')
	if newlineIndex != -1 && (lineEnd == -1 || newlineIndex < lineEnd) {
		lineEnd = newlineIndex
	}
	if lineEnd != -1 {
		line = line[:lineEnd]
	}

	if len(line) < 1 {
		return ircmsg, ErrorLineIsEmpty
	}

	// tags
	if line[0] == '@' {
		tagEnd := strings.IndexByte(line, ' ')
		if tagEnd == -1 {
			return ircmsg, ErrorLineIsEmpty
		}
		tags := line[1:tagEnd]
		if 0 < maxTagDataLength && maxTagDataLength < len(tags) {
			return ircmsg, ErrorLineTooLong
		}
		err = ircmsg.parseTags(tags)
		if err != nil {
			return
		}
		// skip over the tags and the separating space
		line = line[tagEnd+1:]
	}

	// truncate if desired
	if 0 < truncateLen && truncateLen < len(line) {
		line = line[:truncateLen]
	}

	// modern: "These message parts, and parameters themselves, are separated
	// by one or more ASCII SPACE characters"
	line = trimInitialSpaces(line)

	// prefix
	if 0 < len(line) && line[0] == ':' {
		prefixEnd := strings.IndexByte(line, ' ')
		if prefixEnd == -1 {
			return ircmsg, ErrorLineIsEmpty
		}
		ircmsg.Prefix = line[1:prefixEnd]
		// skip over the prefix and the separating space
		line = line[prefixEnd+1:]
	}

	line = trimInitialSpaces(line)

	// command
	commandEnd := strings.IndexByte(line, ' ')
	paramStart := commandEnd + 1
	if commandEnd == -1 {
		commandEnd = len(line)
		paramStart = len(line)
	}
	// normalize command to uppercase:
	ircmsg.Command = strings.ToUpper(line[:commandEnd])
	if len(ircmsg.Command) == 0 {
		return ircmsg, ErrorLineIsEmpty
	}
	line = line[paramStart:]

	for {
		line = trimInitialSpaces(line)
		if len(line) == 0 {
			break
		}
		// handle trailing
		if line[0] == ':' {
			ircmsg.Params = append(ircmsg.Params, line[1:])
			break
		}
		paramEnd := strings.IndexByte(line, ' ')
		if paramEnd == -1 {
			ircmsg.Params = append(ircmsg.Params, line)
			break
		}
		ircmsg.Params = append(ircmsg.Params, line[:paramEnd])
		line = line[paramEnd+1:]
	}

	return ircmsg, nil
}

// helper to parse tags
func (ircmsg *IrcMessage) parseTags(tags string) (err error) {
	for 0 < len(tags) {
		tagEnd := strings.IndexByte(tags, ';')
		endPos := tagEnd
		nextPos := tagEnd + 1
		if tagEnd == -1 {
			endPos = len(tags)
			nextPos = len(tags)
		}
		tagPair := tags[:endPos]
		equalsIndex := strings.IndexByte(tagPair, '=')
		var tagName, tagValue string
		if equalsIndex == -1 {
			// tag with no value
			tagName = tagPair
		} else {
			tagName, tagValue = tagPair[:equalsIndex], tagPair[equalsIndex+1:]
		}
		ircmsg.SetTag(tagName, UnescapeTagValue(tagValue))
		// skip over the tag just processed, plus the delimiting ; if any
		tags = tags[nextPos:]
	}
	return nil
}

// MakeMessage provides a simple way to create a new IrcMessage.
func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg IrcMessage) {
	ircmsg.Prefix = prefix
	ircmsg.Command = command
	ircmsg.Params = params
	ircmsg.UpdateTags(tags)
	return ircmsg
}

// Line returns a sendable line created from an IrcMessage.
func (ircmsg *IrcMessage) Line() (result string, err error) {
	bytes, err := ircmsg.line(0, 0, 0, 0)
	if err == nil {
		result = string(bytes)
	}
	return
}

// LineBytes returns a sendable line created from an IrcMessage.
func (ircmsg *IrcMessage) LineBytes() (result []byte, err error) {
	result, err = ircmsg.line(0, 0, 0, 0)
	return
}

// LineBytesStrict returns a sendable line, as a []byte, created from an IrcMessage.
// fromClient controls whether the server-side or client-side tag length limit
// is enforced. If truncateLen is nonzero, it is the length at which the
// non-tag portion of the message is truncated.
func (ircmsg *IrcMessage) LineBytesStrict(fromClient bool, truncateLen int) ([]byte, error) {
	var tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit int
	if fromClient {
		// enforce client max tags:
		// <client_max>   (4096)  :: '@' <tag_data 4094> ' '
		tagLimit = MaxlenTagsFromClient
	} else {
		// on the server side, enforce separate client-only and server-added tag budgets:
		// "Servers MUST NOT add tag data exceeding 4094 bytes to messages."
		// <combined_max> (8191)  :: '@' <tag_data 4094> ';' <tag_data 4094> ' '
		clientOnlyTagDataLimit = MaxlenClientTagData
		serverAddedTagDataLimit = MaxlenServerTagData
	}
	return ircmsg.line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen)
}

func paramRequiresTrailing(param string) bool {
	return len(param) == 0 || strings.IndexByte(param, ' ') != -1 || param[0] == ':'
}

// line returns a sendable line created from an IrcMessage.
func (ircmsg *IrcMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) ([]byte, error) {
	if len(ircmsg.Command) < 1 {
		return nil, ErrorCommandMissing
	}

	var buf bytes.Buffer

	// write the tags, computing the budgets for client-only tags and regular tags
	var lenRegularTags, lenClientOnlyTags, lenTags int
	if 0 < len(ircmsg.tags) || 0 < len(ircmsg.clientOnlyTags) {
		buf.WriteByte('@')
		firstTag := true
		writeTags := func(tags map[string]string) {
			for tag, val := range tags {
				if !firstTag {
					buf.WriteByte(';') // delimiter
				}
				buf.WriteString(tag)
				if val != "" {
					buf.WriteByte('=')
					buf.WriteString(EscapeTagValue(val))
				}
				firstTag = false
			}
		}
		writeTags(ircmsg.tags)
		lenRegularTags = buf.Len() - 1 // '@' is not counted
		writeTags(ircmsg.clientOnlyTags)
		lenClientOnlyTags = (buf.Len() - 1) - lenRegularTags // '@' is not counted
		if lenRegularTags != 0 {
			// semicolon between regular and client-only tags is not counted
			lenClientOnlyTags -= 1
		}
		buf.WriteByte(' ')
	}
	lenTags = buf.Len()

	if 0 < tagLimit && tagLimit < buf.Len() {
		return nil, ErrorLineTooLong
	}
	if (0 < clientOnlyTagDataLimit && clientOnlyTagDataLimit < lenClientOnlyTags) || (0 < serverAddedTagDataLimit && serverAddedTagDataLimit < lenRegularTags) {
		return nil, ErrorLineTooLong
	}

	if len(ircmsg.Prefix) > 0 {
		buf.WriteByte(':')
		buf.WriteString(ircmsg.Prefix)
		buf.WriteByte(' ')
	}

	buf.WriteString(ircmsg.Command)

	for i, param := range ircmsg.Params {
		buf.WriteByte(' ')
		requiresTrailing := paramRequiresTrailing(param)
		lastParam := i == len(ircmsg.Params)-1
		if (requiresTrailing || ircmsg.forceTrailing) && lastParam {
			buf.WriteByte(':')
		} else if requiresTrailing && !lastParam {
			return nil, ErrorBadParam
		}
		buf.WriteString(param)
	}

	// truncate if desired
	// -2 for \r\n
	restLen := buf.Len() - lenTags
	if 0 < truncateLen && (truncateLen-2) < restLen {
		buf.Truncate(lenTags + (truncateLen - 2))
	}
	buf.WriteString("\r\n")

	result := buf.Bytes()
	if bytes.IndexByte(result, '\x00') != -1 {
		return nil, ErrorLineContainsBadChar
	}
	return result, nil
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla 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 json

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/rpc"
)

var ErrResponseError = errors.New("response error")

type Service1Request struct {
	A int
	B int
}

type Service1BadRequest struct {
	M string `json:"method"`
}

type Service1Response struct {
	Result int
}

type Service1 struct {
}

func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error {
	res.Result = req.A * req.B
	return nil
}

func (t *Service1) ResponseError(r *http.Request, req *Service1Request, res *Service1Response) error {
	return ErrResponseError
}

func execute(t *testing.T, s *rpc.Server, method string, req, res interface{}) error {
	if !s.HasMethod(method) {
		t.Fatal("Expected to be registered:", method)
	}

	buf, _ := EncodeClientRequest(method, req)
	body := bytes.NewBuffer(buf)
	r, _ := http.NewRequest("POST", "http://localhost:8080/", body)
	r.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	s.ServeHTTP(w, r)

	return DecodeClientResponse(w.Body, res)
}

func executeRaw(t *testing.T, s *rpc.Server, req interface{}, res interface{}) int {
	j, _ := json.Marshal(req)
	r, _ := http.NewRequest("POST", "http://localhost:8080/", bytes.NewBuffer(j))
	r.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	s.ServeHTTP(w, r)

	return w.Code
}

func TestService(t *testing.T) {
	s := rpc.NewServer()
	s.RegisterCodec(NewCodec(), "application/json")
	s.RegisterService(new(Service1), "")

	var res Service1Response
	if err := execute(t, s, "Service1.Multiply", &Service1Request{4, 2}, &res); err != nil {
		t.Error("Expected err to be nil, but got:", err)
	}
	if res.Result != 8 {
		t.Errorf("Wrong response: %v.", res.Result)
	}

	if err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err == nil {
		t.Errorf("Expected to get %q, but got nil", ErrResponseError)
	} else if err.Error() != ErrResponseError.Error() {
		t.Errorf("Expected to get %q, but got %q", ErrResponseError, err)
	}

	if code := executeRaw(t, s, &Service1BadRequest{"Service1.Multiply"}, &res); code != 400 {
		t.Errorf("Expected http response code 400, but got %v", code)
	}
}
<commit_msg>Test before/after flow in json package<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla 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 json

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/context"
	"github.com/gorilla/rpc"
)

var ErrResponseError = errors.New("response error")

type Service1Request struct {
	A int
	B int
}

type Service1BadRequest struct {
	M string `json:"method"`
}

type Service1Response struct {
	Result int
}

type Service1 struct {
}

func (t *Service1) Multiply(r *http.Request, req *Service1Request, res *Service1Response) error {
	res.Result = req.A * req.B
	return nil
}

func (t *Service1) ResponseError(r *http.Request, req *Service1Request, res *Service1Response) error {
	return ErrResponseError
}

func (t *Service1) BeforeAfter(r *http.Request, req *Service1Request, res *Service1Response) error {
	if _, ok := context.GetOk(r, "before"); !ok {
		return fmt.Errorf("before value not found")
	}
	context.Set(r, "result", 1)
	res.Result = 1
	return nil
}

func execute(t *testing.T, s *rpc.Server, method string, req, res interface{}) error {
	if !s.HasMethod(method) {
		t.Fatal("Expected to be registered:", method)
	}

	buf, _ := EncodeClientRequest(method, req)
	body := bytes.NewBuffer(buf)
	r, _ := http.NewRequest("POST", "http://localhost:8080/", body)
	r.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	s.ServeHTTP(w, r)

	return DecodeClientResponse(w.Body, res)
}

func executeRaw(t *testing.T, s *rpc.Server, req interface{}, res interface{}) int {
	j, _ := json.Marshal(req)
	r, _ := http.NewRequest("POST", "http://localhost:8080/", bytes.NewBuffer(j))
	r.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	s.ServeHTTP(w, r)

	return w.Code
}

func TestService(t *testing.T) {
	s := rpc.NewServer()
	s.RegisterCodec(NewCodec(), "application/json")
	s.RegisterService(new(Service1), "")

	var res Service1Response
	if err := execute(t, s, "Service1.Multiply", &Service1Request{4, 2}, &res); err != nil {
		t.Error("Expected err to be nil, but got:", err)
	}
	if res.Result != 8 {
		t.Errorf("Wrong response: %v.", res.Result)
	}

	if err := execute(t, s, "Service1.ResponseError", &Service1Request{4, 2}, &res); err == nil {
		t.Errorf("Expected to get %q, but got nil", ErrResponseError)
	} else if err.Error() != ErrResponseError.Error() {
		t.Errorf("Expected to get %q, but got %q", ErrResponseError, err)
	}

	if code := executeRaw(t, s, &Service1BadRequest{"Service1.Multiply"}, &res); code != 400 {
		t.Errorf("Expected http response code 400, but got %v", code)
	}
}

func TestServiceBeforeAfter(t *testing.T) {
	s := rpc.NewServer()
	s.RegisterCodec(NewCodec(), "application/json")
	s.RegisterService(new(Service1), "")

	buf, _ := EncodeClientRequest("Service1.BeforeAfter", nil)
	body := bytes.NewBuffer(buf)
	r, _ := http.NewRequest("POST", "http://localhost:8080/", body)

	s.RegisterBeforeFunc(func(i *rpc.RequestInfo) {
		context.Set(r, "before", "Before is true")
	})
	s.RegisterAfterFunc(func(i *rpc.RequestInfo) {
		context.Set(r, "after", "After is true")
	})

	var res Service1Response
	r.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	s.ServeHTTP(w, r)

	err := DecodeClientResponse(w.Body, &res)
	if err != nil {
		t.Errorf("Expected no error, got %s", err.Error())
	}

	if afterValue := context.Get(r, "after").(string); afterValue != "After is true" {
		t.Errorf("Expected after in context to be 'After is true', got %s", afterValue)
	}

	if reqValue := context.Get(r, "result").(int); reqValue != res.Result {
		t.Errorf("Expected context result value to be equal to res.Result, got %d", reqValue)
	}

}
<|endoftext|>


<commit_before>package build

import (
	"errors"
	"fmt"
	"io/ioutil"
	"koding/kite/kd/util"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"text/template"
)

type Build struct {
	appName    string
	version    string
	output     string
	binaryPath string
}

func NewBuild() *Build {
	return &Build{}
}

func (b *Build) Definition() string {
	return "Build deployable install packages"
}

func (b *Build) Exec(args []string) error {
	if len(args) == 0 {
		return errors.New("Usage: kd build <importPath>")
	}

	// use binary name as appName
	appName := filepath.Base(args[0])

	build := &Build{
		appName:    appName,
		version:    "0.0.1",
		binaryPath: args[0],
	}

	err := build.do()
	if err != nil {
		return err
	}

	fmt.Println("build successfull")
	return nil
}

func (b *Build) do() error {
	switch runtime.GOOS {
	case "darwin":
		return b.darwin()
	default:
		return fmt.Errorf("not supported os: %s.\n", runtime.GOOS)
	}
}

func (b *Build) linux() error {
	return nil
}

// darwin is building a new .pkg installer for darwin based OS'es.
func (b *Build) darwin() error {
	version := b.version
	if b.output == "" {
		b.output = fmt.Sprintf("koding-%s", b.appName)
	}

	scriptDir := "./darwin/scripts"
	installRoot := "./root" // TODO REMOVE

	os.RemoveAll(installRoot) // clean up old build before we continue
	installRootUsr := filepath.Join(installRoot, "/usr/local/bin")

	os.MkdirAll(installRootUsr, 0755)
	err := util.CopyFile(b.binaryPath, installRootUsr+"/"+b.appName)
	if err != nil {
		return err
	}

	tempDest, err := ioutil.TempDir("", "tempDest")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tempDest)

	b.createScripts(scriptDir)
	b.createLaunchAgent(installRoot)

	cmdPkg := exec.Command("pkgbuild",
		"--identifier", fmt.Sprintf("com.koding.kite.%s.pkg", b.appName),
		"--version", version,
		"--scripts", scriptDir,
		"--root", installRoot,
		"--install-location", "/",
		fmt.Sprintf("%s/com.koding.kite.%s.pkg", tempDest, b.appName),
		// used for next step, also set up for distribution.xml
	)

	_, err = cmdPkg.CombinedOutput()
	if err != nil {
		return err
	}

	distributionFile := "./darwin/Distribution.xml"
	resources := "./darwin/Resources"
	targetFile := b.output + ".pkg"

	b.createDistribution(distributionFile)

	cmdBuild := exec.Command("productbuild",
		"--distribution", distributionFile,
		"--resources", resources,
		"--package-path", tempDest,
		targetFile,
	)

	_, err = cmdBuild.CombinedOutput()
	if err != nil {
		return err
	}

	return nil
}

func (b *Build) createLaunchAgent(rootDir string) {
	launchDir := fmt.Sprintf("%s/Library/LaunchAgents/", rootDir)
	os.MkdirAll(launchDir, 0700)

	launchFile := fmt.Sprintf("%s/com.koding.kite.%s.plist", launchDir, b.appName)

	lFile, err := os.Create(launchFile)
	if err != nil {
		log.Fatalln(err)
	}

	t := template.Must(template.New("launchAgent").Parse(launchAgent))
	t.Execute(lFile, b.appName)

}

func (b *Build) createDistribution(file string) {
	distFile, err := os.Create(file)
	if err != nil {
		log.Fatalln(err)
	}

	t := template.Must(template.New("distribution").Parse(distribution))
	t.Execute(distFile, b.appName)

}

func (b *Build) createScripts(scriptDir string) {
	os.MkdirAll(scriptDir, 0700) // does return nil if exists

	postInstallFile, err := os.Create(scriptDir + "/postInstall")
	if err != nil {
		log.Fatalln(err)
	}
	postInstallFile.Chmod(0755)

	preInstallFile, err := os.Create(scriptDir + "/preInstall")
	if err != nil {
		log.Fatalln(err)
	}
	preInstallFile.Chmod(0755)

	t := template.Must(template.New("postInstall").Parse(postInstall))
	t.Execute(postInstallFile, b.appName)

	t = template.Must(template.New("preInstall").Parse(preInstall))
	t.Execute(preInstallFile, b.appName)
}

func fileExist(dir string) bool {
	var err error
	_, err = os.Stat(dir)
	if err == nil {
		return true // file exist
	}

	if os.IsNotExist(err) {
		return false // file does not exist
	}

	panic(err) // permission errors or something else bad
}
<commit_msg>build: implement linux interface, wio<commit_after>package build

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"koding/kite/kd/util"
	"koding/tools/deps"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"text/template"

	"github.com/fatih/file"
)

type Build struct {
	appName    string
	version    string
	output     string
	binaryPath string
	importPath string
}

func NewBuild() *Build {
	return &Build{}
}

func (b *Build) Definition() string {
	return "Build deployable install packages"
}

func (b *Build) Exec(args []string) error {
	usage := "Usage: kd build --import <importPath> || --bin <binaryPath>"

	if len(args) == 0 {
		return errors.New(usage)
	}

	if len(args) == 2 && (args[0] != "--bin" || args[0] != "--import") {
		return errors.New(usage)
	}

	build := &Build{
		version: "0.0.1",
	}

	switch args[0] {
	case "--bin":
		b.binaryPath = args[1]
	case "--import":
		b.importPath = args[1]
	}

	b.appName = filepath.Base(args[0])

	err := build.do()
	if err != nil {
		return err
	}

	fmt.Println("build successfull")
	return nil
}

func (b *Build) do() error {
	switch runtime.GOOS {
	case "darwin":
		return b.darwin()
	default:
		return fmt.Errorf("not supported os: %s.\n", runtime.GOOS)
	}
}

func (b *Build) linux() error {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return errors.New("GOPATH is not set")
	}

	pkgname := path.Base(b.importPath)

	// or use "go list koding/..." for all packages and commands
	packages := []string{b.importPath}

	d, err := deps.LoadDeps(packages...)
	if err != nil {
		return err
	}

	err = d.WriteJSON()
	if err != nil {
		return err
	}

	out, err := json.MarshalIndent(d, "", "  ")
	if err != nil {
		return err
	}

	fmt.Printf("installing packages to '%s'\n%s\n", d.BuildGoPath, string(out))
	err = d.InstallDeps()
	if err != nil {
		return err
	}

	packagePath := filepath.Join(d.BuildGoPath, pkgname)

	// prepare config folder
	// configPath := filepath.Join(packagePath, "config")
	// os.MkdirAll(configPath, 0755)

	// config, err := exec.Command("node", "-e", "require('koding-config-manager').printJson('main."+*profile+"')").CombinedOutput()
	// if err != nil {
	// 	return err
	// }

	// configFile := fmt.Sprintf("%s/main.%s.json", configPath, *profile)
	// err = ioutil.WriteFile(configFile, config, 0755)
	// if err != nil {
	// 	return err
	// }

	// copy package files, such as templates
	assets := []string{filepath.Join(gopath, "src", b.importPath, "files")}
	for _, assetDir := range assets {
		err := file.Copy(assetDir, packagePath)
		if err != nil {
			log.Println("copy assets", err)
		}
	}

	// create tar.gz file from final director
	tarFile := fmt.Sprintf("%s.%s-%s.tar.gz", pkgname, runtime.GOOS, runtime.GOARCH)
	err = util.MakeTar(tarFile, packagePath)
	if err != nil {
		return err
	}

	fmt.Printf("'%s' is created and ready for deploy\n", tarFile)
	return nil
}

// darwin is building a new .pkg installer for darwin based OS'es.
func (b *Build) darwin() error {
	version := b.version
	if b.output == "" {
		b.output = fmt.Sprintf("koding-%s", b.appName)
	}

	scriptDir := "./darwin/scripts"
	installRoot := "./root" // TODO REMOVE

	os.RemoveAll(installRoot) // clean up old build before we continue
	installRootUsr := filepath.Join(installRoot, "/usr/local/bin")

	os.MkdirAll(installRootUsr, 0755)
	err := util.CopyFile(b.binaryPath, installRootUsr+"/"+b.appName)
	if err != nil {
		return err
	}

	tempDest, err := ioutil.TempDir("", "tempDest")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tempDest)

	b.createScripts(scriptDir)
	b.createLaunchAgent(installRoot)

	cmdPkg := exec.Command("pkgbuild",
		"--identifier", fmt.Sprintf("com.koding.kite.%s.pkg", b.appName),
		"--version", version,
		"--scripts", scriptDir,
		"--root", installRoot,
		"--install-location", "/",
		fmt.Sprintf("%s/com.koding.kite.%s.pkg", tempDest, b.appName),
		// used for next step, also set up for distribution.xml
	)

	_, err = cmdPkg.CombinedOutput()
	if err != nil {
		return err
	}

	distributionFile := "./darwin/Distribution.xml"
	resources := "./darwin/Resources"
	targetFile := b.output + ".pkg"

	b.createDistribution(distributionFile)

	cmdBuild := exec.Command("productbuild",
		"--distribution", distributionFile,
		"--resources", resources,
		"--package-path", tempDest,
		targetFile,
	)

	_, err = cmdBuild.CombinedOutput()
	if err != nil {
		return err
	}

	return nil
}

func (b *Build) createLaunchAgent(rootDir string) {
	launchDir := fmt.Sprintf("%s/Library/LaunchAgents/", rootDir)
	os.MkdirAll(launchDir, 0700)

	launchFile := fmt.Sprintf("%s/com.koding.kite.%s.plist", launchDir, b.appName)

	lFile, err := os.Create(launchFile)
	if err != nil {
		log.Fatalln(err)
	}

	t := template.Must(template.New("launchAgent").Parse(launchAgent))
	t.Execute(lFile, b.appName)

}

func (b *Build) createDistribution(file string) {
	distFile, err := os.Create(file)
	if err != nil {
		log.Fatalln(err)
	}

	t := template.Must(template.New("distribution").Parse(distribution))
	t.Execute(distFile, b.appName)

}

func (b *Build) createScripts(scriptDir string) {
	os.MkdirAll(scriptDir, 0700) // does return nil if exists

	postInstallFile, err := os.Create(scriptDir + "/postInstall")
	if err != nil {
		log.Fatalln(err)
	}
	postInstallFile.Chmod(0755)

	preInstallFile, err := os.Create(scriptDir + "/preInstall")
	if err != nil {
		log.Fatalln(err)
	}
	preInstallFile.Chmod(0755)

	t := template.Must(template.New("postInstall").Parse(postInstall))
	t.Execute(postInstallFile, b.appName)

	t = template.Must(template.New("preInstall").Parse(preInstall))
	t.Execute(preInstallFile, b.appName)
}

func fileExist(dir string) bool {
	var err error
	_, err = os.Stat(dir)
	if err == nil {
		return true // file exist
	}

	if os.IsNotExist(err) {
		return false // file does not exist
	}

	panic(err) // permission errors or something else bad
}
<|endoftext|>


<commit_before>package seccomp

import (
	"fmt"
	"syscall"
)

var protocols = map[uint]string{
	syscall.IPPROTO_IP:   "IPPROTO_IP",
	syscall.IPPROTO_ICMP: "IPPROTO_ICMP",
	syscall.IPPROTO_IGMP: "IPPROTO_IGMP",
	syscall.IPPROTO_IPIP: "IPPROTO_IPIP",
	syscall.IPPROTO_TCP:  "IPPROTO_TCP",
	syscall.IPPROTO_EGP:  "IPPROTO_EGP",
	syscall.IPPROTO_PUP:  "IPPROTO_PUP",
	syscall.IPPROTO_UDP:  "IPPROTO_UDP",
	syscall.IPPROTO_IDP:  "IPPROTO_IDP",
	syscall.IPPROTO_TP:   "IPPROTO_TP",
	syscall.IPPROTO_DCCP: "IPPROTO_DCCP",
	syscall.IPPROTO_IPV6: "IPPROTO_IPV6",
	syscall.IPPROTO_RSVP: "IPPROTO_RSVP",
	syscall.IPPROTO_GRE:  "IPPROTO_GRE",
	syscall.IPPROTO_ESP:  "IPPROTO_ESP",
	syscall.IPPROTO_AH:   "IPPROTO_AH",
	syscall.IPPROTO_MTP:  "IPPROTO_MTP",
	//syscall.IPPROTO_BEETPH: "IPPROTO_BEETPH",
	syscall.IPPROTO_ENCAP:   "IPPROTO_ENCAP",
	syscall.IPPROTO_PIM:     "IPPROTO_PIM",
	syscall.IPPROTO_COMP:    "IPPROTO_COMP",
	syscall.IPPROTO_SCTP:    "IPPROTO_SCTP",
	syscall.IPPROTO_UDPLITE: "IPPROTO_UDPLITE",
	syscall.IPPROTO_RAW:     "IPPROTO_RAW",
}

var domainflags = map[uint]string{
	syscall.AF_UNIX:      "AF_UNIX",
	syscall.AF_INET:      "AF_INET",
	syscall.AF_INET6:     "AF_INET6",
	syscall.AF_IPX:       "AF_IPX",
	syscall.AF_NETLINK:   "AF_NETLINK",
	syscall.AF_X25:       "AF_X25",
	syscall.AF_AX25:      "AF_AX25",
	syscall.AF_ATMPVC:    "AF_ATMPVC",
	syscall.AF_APPLETALK: "AF_APPLETALK",
	syscall.AF_PACKET:    "AF_PACKET",
	//	syscall.ALG: "AF_ALG",
}

var socktypes = map[uint]string{
	syscall.SOCK_STREAM:    "SOCK_STREAM",
	syscall.SOCK_DGRAM:     "SOCK_DGRAM",
	syscall.SOCK_SEQPACKET: "SOCK_SEQPACKET",
	syscall.SOCK_RAW:       "SOCK_RAW",
	syscall.SOCK_RDM:       "SOCK_RDM",
	syscall.SOCK_PACKET:    "SOCK_PACKET",
}

var socktypeflags = map[uint]string{
	syscall.SOCK_NONBLOCK: "SOCK_NONBLOCK",
	syscall.SOCK_CLOEXEC:  "SOCK_CLOEXEC",
}

func render_socket(pid int, args RegisterArgs) (string, error) {

	domain := ""
	socktype := ""

	prot := fmt.Sprintf("%d", uint(args[2]))

	if uint(args[0]) == syscall.AF_INET || uint(args[0]) == syscall.AF_INET6 {
		if _, y := protocols[uint(args[2])]; y {
			prot = protocols[uint(args[2])]
		}
	}
	if _, y := domainflags[uint(args[0])]; y {
		domain = domainflags[uint(args[0])]
	} else {
		domain = fmt.Sprintf("%d", args[0])
	}

	socktype = socktypes[uint(args[1]&0xFF)]
	socktypestr := socktype

	tmp := renderFlags(socktypeflags, uint(args[1]))

	if tmp != "" {
		socktypestr += "|"
	}

	socktypestr += tmp

	callrep := fmt.Sprintf("socket(%s, %s, %s)", domain, socktypestr, prot)
	return callrep, nil
}

<commit_msg>Renderer for connect(2)<commit_after>package seccomp

import (
	"fmt"
	"syscall"
)

var protocols = map[uint]string{
	syscall.IPPROTO_IP:   "IPPROTO_IP",
	syscall.IPPROTO_ICMP: "IPPROTO_ICMP",
	syscall.IPPROTO_IGMP: "IPPROTO_IGMP",
	syscall.IPPROTO_IPIP: "IPPROTO_IPIP",
	syscall.IPPROTO_TCP:  "IPPROTO_TCP",
	syscall.IPPROTO_EGP:  "IPPROTO_EGP",
	syscall.IPPROTO_PUP:  "IPPROTO_PUP",
	syscall.IPPROTO_UDP:  "IPPROTO_UDP",
	syscall.IPPROTO_IDP:  "IPPROTO_IDP",
	syscall.IPPROTO_TP:   "IPPROTO_TP",
	syscall.IPPROTO_DCCP: "IPPROTO_DCCP",
	syscall.IPPROTO_IPV6: "IPPROTO_IPV6",
	syscall.IPPROTO_RSVP: "IPPROTO_RSVP",
	syscall.IPPROTO_GRE:  "IPPROTO_GRE",
	syscall.IPPROTO_ESP:  "IPPROTO_ESP",
	syscall.IPPROTO_AH:   "IPPROTO_AH",
	syscall.IPPROTO_MTP:  "IPPROTO_MTP",
	//syscall.IPPROTO_BEETPH: "IPPROTO_BEETPH",
	syscall.IPPROTO_ENCAP:   "IPPROTO_ENCAP",
	syscall.IPPROTO_PIM:     "IPPROTO_PIM",
	syscall.IPPROTO_COMP:    "IPPROTO_COMP",
	syscall.IPPROTO_SCTP:    "IPPROTO_SCTP",
	syscall.IPPROTO_UDPLITE: "IPPROTO_UDPLITE",
	syscall.IPPROTO_RAW:     "IPPROTO_RAW",
}

var domainflags = map[uint]string{
	syscall.AF_UNIX:      "AF_UNIX",
	syscall.AF_INET:      "AF_INET",
	syscall.AF_INET6:     "AF_INET6",
	syscall.AF_IPX:       "AF_IPX",
	syscall.AF_NETLINK:   "AF_NETLINK",
	syscall.AF_X25:       "AF_X25",
	syscall.AF_AX25:      "AF_AX25",
	syscall.AF_ATMPVC:    "AF_ATMPVC",
	syscall.AF_APPLETALK: "AF_APPLETALK",
	syscall.AF_PACKET:    "AF_PACKET",
	//	syscall.ALG: "AF_ALG",
}

var socktypes = map[uint]string{
	syscall.SOCK_STREAM:    "SOCK_STREAM",
	syscall.SOCK_DGRAM:     "SOCK_DGRAM",
	syscall.SOCK_SEQPACKET: "SOCK_SEQPACKET",
	syscall.SOCK_RAW:       "SOCK_RAW",
	syscall.SOCK_RDM:       "SOCK_RDM",
	syscall.SOCK_PACKET:    "SOCK_PACKET",
}

var socktypeflags = map[uint]string{
	syscall.SOCK_NONBLOCK: "SOCK_NONBLOCK",
	syscall.SOCK_CLOEXEC:  "SOCK_CLOEXEC",
}

func render_socket(pid int, args RegisterArgs) (string, error) {

	domain := ""
	socktype := ""

	prot := fmt.Sprintf("%d", uint(args[2]))

	if uint(args[0]) == syscall.AF_INET || uint(args[0]) == syscall.AF_INET6 {
		if _, y := protocols[uint(args[2])]; y {
			prot = protocols[uint(args[2])]
		}
	}
	if _, y := domainflags[uint(args[0])]; y {
		domain = domainflags[uint(args[0])]
	} else {
		domain = fmt.Sprintf("%d", args[0])
	}

	socktype = socktypes[uint(args[1]&0xFF)]
	socktypestr := socktype

	tmp := renderFlags(socktypeflags, uint(args[1]))

	if tmp != "" {
		socktypestr += "|"
	}

	socktypestr += tmp

	callrep := fmt.Sprintf("socket(%s, %s, %s)", domain, socktypestr, prot)
	return callrep, nil
}

func render_connect(pid int, args RegisterArgs) (string, error) {

	// TODO Watch the length supplied by the process

	buf, err := readBytesArg(pid, int(args[2]), uintptr(args[1]))
	if err != nil {
		return "", err
	}

	fam := bytestoint16(buf[:2])
	addrstruct := ""
	addrstruct = render_inetaddr(buf)
	switch fam {
	case syscall.AF_INET:
		addrstruct = render_inetaddr(buf)
	case syscall.AF_UNIX:
		addrstruct = render_unixaddr(buf)
	}

	callrep := fmt.Sprintf("connect(%d, %s, %d)", args[0], addrstruct, args[2])

	return callrep, nil

}
<|endoftext|>


<commit_before>package mocknet

import (
	"bytes"
	"errors"
	"io"
	"net"
	"time"

	inet "github.com/libp2p/go-libp2p-net"
	protocol "github.com/libp2p/go-libp2p-protocol"
)

// stream implements inet.Stream
type stream struct {
	write     *io.PipeWriter
	read      *io.PipeReader
	conn      *conn
	toDeliver chan *transportObject
	control   chan int
	state     int
	closed    chan struct{}

	protocol protocol.ID
}

var ErrReset error = errors.New("stream reset")
var ErrClosed error = errors.New("stream closed")

const (
	stateOpen = iota
	stateClose
	stateReset
)

type transportObject struct {
	msg         []byte
	arrivalTime time.Time
}

func NewStream(w *io.PipeWriter, r *io.PipeReader) *stream {
	s := &stream{
		read:      r,
		write:     w,
		control:   make(chan int),
		closed:    make(chan struct{}),
		toDeliver: make(chan *transportObject),
	}

	go s.transport()
	return s
}

//  How to handle errors with writes?
func (s *stream) Write(p []byte) (n int, err error) {
	l := s.conn.link
	delay := l.GetLatency() + l.RateLimit(len(p))
	t := time.Now().Add(delay)
	select {
	case <-s.closed: // bail out if we're closing.
		switch s.state {
		case stateReset:
			return 0, ErrReset
		case stateClose:
			return 0, ErrClosed
		}
	case s.toDeliver <- &transportObject{msg: p, arrivalTime: t}:
	}
	return len(p), nil
}

func (s *stream) Protocol() protocol.ID {
	return s.protocol
}

func (s *stream) SetProtocol(proto protocol.ID) {
	s.protocol = proto
}

func (s *stream) Close() error {
	select {
	case s.control <- stateClose:
	case <-s.closed:
	}
	<-s.closed
	if s.state == stateReset {
		return nil
	} else {
		return ErrClosed
	}
}

func (s *stream) Reset() error {
	// Cancel any pending reads.
	s.write.Close()

	select {
	case s.control <- stateReset:
	case <-s.closed:
	}
	<-s.closed
	if s.state == stateReset {
		return nil
	} else {
		return ErrClosed
	}
}

func (s *stream) teardown() {
	s.write.Close()

	// at this point, no streams are writing.
	s.conn.removeStream(s)

	// Mark as closed.
	close(s.closed)

	s.conn.net.notifyAll(func(n inet.Notifiee) {
		n.ClosedStream(s.conn.net, s)
	})
}

func (s *stream) Conn() inet.Conn {
	return s.conn
}

func (s *stream) SetDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (p *stream) SetReadDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (p *stream) SetWriteDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (s *stream) Read(b []byte) (int, error) {
	return s.read.Read(b)
}

// transport will grab message arrival times, wait until that time, and
// then write the message out when it is scheduled to arrive
func (s *stream) transport() {
	defer s.teardown()

	bufsize := 256
	buf := new(bytes.Buffer)
	timer := time.NewTimer(0)
	if !timer.Stop() {
		select {
		case <-timer.C:
		default:
		}
	}

	// cleanup
	defer timer.Stop()

	// writeBuf writes the contents of buf through to the s.Writer.
	// done only when arrival time makes sense.
	drainBuf := func() {
		if buf.Len() > 0 {
			_, err := s.write.Write(buf.Bytes())
			if err != nil {
				return
			}
			buf.Reset()
		}
	}

	// deliverOrWait is a helper func that processes
	// an incoming packet. it waits until the arrival time,
	// and then writes things out.
	deliverOrWait := func(o *transportObject) {
		buffered := len(o.msg) + buf.Len()

		// Yes, we can end up extending a timer multiple times if we
		// keep on making small writes but that shouldn't be too much of an
		// issue. Fixing that would be painful.
		if !timer.Stop() {
			// FIXME: So, we *shouldn't* need to do this but we hang
			// here if we don't... Go bug?
			select {
			case <-timer.C:
			default:
			}
		}
		delay := o.arrivalTime.Sub(time.Now())
		if delay >= 0 {
			timer.Reset(delay)
		} else {
			timer.Reset(0)
		}

		if buffered >= bufsize {
			select {
			case <-timer.C:
			case s.state = <-s.control:
				return
			}
			drainBuf()
			// write this message.
			_, err := s.write.Write(o.msg)
			if err != nil {
				log.Error("mock_stream", err)
			}
		} else {
			buf.Write(o.msg)
		}
	}

	for {
		switch s.state {
		case stateClose:
			drainBuf()
			return
		case stateReset:
			s.read.CloseWithError(ErrReset)
			return
		default:
			panic("invalid state")
		case stateOpen:
		}

		select {
		case s.state = <-s.control:
			continue
		case o, ok := <-s.toDeliver:
			if !ok {
				return
			}
			deliverOrWait(o)
		case <-timer.C: // ok, due to write it out.
			drainBuf()
		}
	}
}
<commit_msg>make sure to not drop writes on close<commit_after>package mocknet

import (
	"bytes"
	"errors"
	"io"
	"net"
	"time"

	inet "github.com/libp2p/go-libp2p-net"
	protocol "github.com/libp2p/go-libp2p-protocol"
)

// stream implements inet.Stream
type stream struct {
	write     *io.PipeWriter
	read      *io.PipeReader
	conn      *conn
	toDeliver chan *transportObject

	reset  chan struct{}
	close  chan struct{}
	closed chan struct{}

	state error

	protocol protocol.ID
}

var ErrReset error = errors.New("stream reset")
var ErrClosed error = errors.New("stream closed")

type transportObject struct {
	msg         []byte
	arrivalTime time.Time
}

func NewStream(w *io.PipeWriter, r *io.PipeReader) *stream {
	s := &stream{
		read:      r,
		write:     w,
		reset:     make(chan struct{}, 1),
		close:     make(chan struct{}, 1),
		closed:    make(chan struct{}),
		toDeliver: make(chan *transportObject),
	}

	go s.transport()
	return s
}

//  How to handle errors with writes?
func (s *stream) Write(p []byte) (n int, err error) {
	l := s.conn.link
	delay := l.GetLatency() + l.RateLimit(len(p))
	t := time.Now().Add(delay)
	select {
	case <-s.closed: // bail out if we're closing.
		return 0, s.state
	case s.toDeliver <- &transportObject{msg: p, arrivalTime: t}:
	}
	return len(p), nil
}

func (s *stream) Protocol() protocol.ID {
	return s.protocol
}

func (s *stream) SetProtocol(proto protocol.ID) {
	s.protocol = proto
}

func (s *stream) Close() error {
	select {
	case s.close <- struct{}{}:
	default:
	}
	<-s.closed
	if s.state != ErrClosed {
		return s.state
	}
	return nil
}

func (s *stream) Reset() error {
	// Cancel any pending writes.
	s.write.Close()

	select {
	case s.reset <- struct{}{}:
	default:
	}
	<-s.closed
	if s.state != ErrReset {
		return s.state
	}
	return nil
}

func (s *stream) teardown() {
	s.write.Close()

	// at this point, no streams are writing.
	s.conn.removeStream(s)

	// Mark as closed.
	close(s.closed)

	s.conn.net.notifyAll(func(n inet.Notifiee) {
		n.ClosedStream(s.conn.net, s)
	})
}

func (s *stream) Conn() inet.Conn {
	return s.conn
}

func (s *stream) SetDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (s *stream) SetReadDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (s *stream) SetWriteDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (s *stream) Read(b []byte) (int, error) {
	return s.read.Read(b)
}

// transport will grab message arrival times, wait until that time, and
// then write the message out when it is scheduled to arrive
func (s *stream) transport() {
	defer s.teardown()

	bufsize := 256
	buf := new(bytes.Buffer)
	timer := time.NewTimer(0)
	if !timer.Stop() {
		select {
		case <-timer.C:
		default:
		}
	}

	// cleanup
	defer timer.Stop()

	// writeBuf writes the contents of buf through to the s.Writer.
	// done only when arrival time makes sense.
	drainBuf := func() {
		if buf.Len() > 0 {
			_, err := s.write.Write(buf.Bytes())
			if err != nil {
				return
			}
			buf.Reset()
		}
	}

	// deliverOrWait is a helper func that processes
	// an incoming packet. it waits until the arrival time,
	// and then writes things out.
	deliverOrWait := func(o *transportObject) {
		buffered := len(o.msg) + buf.Len()

		// Yes, we can end up extending a timer multiple times if we
		// keep on making small writes but that shouldn't be too much of an
		// issue. Fixing that would be painful.
		if !timer.Stop() {
			// FIXME: So, we *shouldn't* need to do this but we hang
			// here if we don't... Go bug?
			select {
			case <-timer.C:
			default:
			}
		}
		delay := o.arrivalTime.Sub(time.Now())
		if delay >= 0 {
			timer.Reset(delay)
		} else {
			timer.Reset(0)
		}

		if buffered >= bufsize {
			select {
			case <-timer.C:
			case <-s.reset:
				s.reset <- struct{}{}
				return
			}
			drainBuf()
			// write this message.
			_, err := s.write.Write(o.msg)
			if err != nil {
				log.Error("mock_stream", err)
			}
		} else {
			buf.Write(o.msg)
		}
	}

	for {
		// Reset takes precedent.
		select {
		case <-s.reset:
			s.state = ErrReset
			s.read.CloseWithError(ErrReset)
			return
		default:
		}

		select {
		case <-s.reset:
			s.state = ErrReset
			s.read.CloseWithError(ErrReset)
			return
		case <-s.close:
			s.state = ErrClosed
			drainBuf()
			return
		case o := <-s.toDeliver:
			deliverOrWait(o)
		case <-timer.C: // ok, due to write it out.
			drainBuf()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"fmt"
)

const constantGlobalVariable string = "constant global variable"

// Utilities: a source, a sink and an error struct:

func source() string {
	return "tainted"
}

func sink(s string) {}

func getRandomString() string {
	buff := make([]byte, 10)
	rand.Read(buff)
	return fmt.Sprintf("%x", buff)
}

func getConstantString() string {
	return "constant return value"
}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

// Candidate functions which compare the input against a list of constants:

func switchStatementReturningTrueOnlyWhenConstant(s string) bool {
	switch s {
	case constantGlobalVariable, "string literal":
		return true
	case getRandomString():
		return false
	case "another string literal":
		return false
	default:
		return false
	}
}

func switchStatementReturningFalseOnlyWhenConstant(r string, s string) bool {
	switch s {
	case "string literal":
		return false
	case constantGlobalVariable:
		return false
	case "another string literal":
		return true
	}
	return true
}

func switchStatementReturningNonNilOnlyWhenConstant(s string) (string, error) {
	switch s {
	case constantGlobalVariable, "string literal":
		return "error", &errorString{"a"}
	case getRandomString():
		return "no error", nil
	case "another string literal":
		return "no error", nil
	default:
		return "no error", nil
	}
}

func switchStatementReturningNilOnlyWhenConstant(s string) *string {
	t := s
	switch t {
	case "string literal":
		return nil
	case constantGlobalVariable, "another string literal":
		str := "matches random string"
		return &str
	}
	str := "no matches"
	return &str
}

func multipleSwitchStatementReturningTrueOnlyWhenConstant(s string, t string) bool {
	switch s {
	case constantGlobalVariable, "string literal":
		return true
	case getRandomString():
		return false
	}
	switch s {
	case "another string literal":
		return true
	}
	switch t {
	case "another string literal":
		return false
	default:
		return false
	}
}

func switchStatementWithoutUsefulInfo(s string) bool {
	switch s {
	case constantGlobalVariable, "string literal":
		return false
	case getRandomString():
		return true
	default:
		return false
	}
}

func switchStatementOverRandomString(s string) bool {
	switch getRandomString() {
	case "string literal":
		return true
	default:
		return false
	}
}

// Tests

func main() {

	// Switch statements in functions

	{
		s := source()
		if switchStatementReturningTrueOnlyWhenConstant(s) {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementReturningFalseOnlyWhenConstant("", s) {
			sink(s) // $dataflow=s
		} else {
			sink(s)
		}
	}

	{
		s := source()
		_, err := switchStatementReturningNonNilOnlyWhenConstant(s)
		if err != nil {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementReturningNilOnlyWhenConstant(s) == nil {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if multipleSwitchStatementReturningTrueOnlyWhenConstant(s, getRandomString()) {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementWithoutUsefulInfo(s) {
			sink(s) // $dataflow=s
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementOverRandomString(s) {
			sink(s) // $dataflow=s
		} else {
			sink(s) // $dataflow=s
		}
	}

}
<commit_msg>Add `fallthrough` statements to switch statement tests<commit_after>package main

import (
	"crypto/rand"
	"fmt"
)

const constantGlobalVariable string = "constant global variable"

// Utilities: a source, a sink and an error struct:

func source() string {
	return "tainted"
}

func sink(s string) {}

func getRandomString() string {
	buff := make([]byte, 10)
	rand.Read(buff)
	return fmt.Sprintf("%x", buff)
}

func getConstantString() string {
	return "constant return value"
}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

// Candidate functions which compare the input against a list of constants:

func switchStatementReturningTrueOnlyWhenConstant(s string) bool {
	switch s {
	case constantGlobalVariable, "string literal":
		return true
	case getRandomString():
		return false
	case "another string literal":
		return false
	default:
		return false
	}
}

func switchStatementReturningFalseOnlyWhenConstant(r string, s string) bool {
	switch s {
	case "string literal":
		return false
	case constantGlobalVariable:
		return false
	case "another string literal":
		return true
	}
	return true
}

func switchStatementReturningNonNilOnlyWhenConstant(s string) (string, error) {
	switch s {
	case constantGlobalVariable, "string literal":
		return "error", &errorString{"a"}
	case getRandomString():
		return "no error", nil
	case "another string literal":
		fallthrough
	default:
		return "no error", nil
	}
}

func switchStatementReturningNilOnlyWhenConstant(s string) *string {
	t := s
	switch t {
	case "string literal":
		fallthrough
	case constantGlobalVariable:
		return nil
	case "another string literal":
		str := "matches random string"
		return &str
	}
	str := "no matches"
	return &str
}

func multipleSwitchStatementReturningTrueOnlyWhenConstant(s string, t string) bool {
	switch s {
	case constantGlobalVariable, "string literal":
		return true
	case getRandomString():
		return false
	}
	switch s {
	case "another string literal":
		return true
	}
	switch t {
	case "another string literal":
		return false
	default:
		return false
	}
}

func switchStatementWithoutUsefulInfo(s string) bool {
	switch s {
	case constantGlobalVariable, "string literal":
		return false
	case getRandomString():
		return true
	default:
		return false
	}
}

func switchStatementOverRandomString(s string) bool {
	switch getRandomString() {
	case "string literal":
		return true
	default:
		return false
	}
}

// Tests

func main() {

	// Switch statements in functions

	{
		s := source()
		if switchStatementReturningTrueOnlyWhenConstant(s) {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementReturningFalseOnlyWhenConstant("", s) {
			sink(s) // $dataflow=s
		} else {
			sink(s)
		}
	}

	{
		s := source()
		_, err := switchStatementReturningNonNilOnlyWhenConstant(s)
		if err != nil {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementReturningNilOnlyWhenConstant(s) == nil {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if multipleSwitchStatementReturningTrueOnlyWhenConstant(s, getRandomString()) {
			sink(s)
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementWithoutUsefulInfo(s) {
			sink(s) // $dataflow=s
		} else {
			sink(s) // $dataflow=s
		}
	}

	{
		s := source()
		if switchStatementOverRandomString(s) {
			sink(s) // $dataflow=s
		} else {
			sink(s) // $dataflow=s
		}
	}

}
<|endoftext|>