<commit_before>// Copyright 2015 Google Inc. 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.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lease_test

import (
	"io"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/googlecloudplatform/gcsfuse/lease"
	"github.com/googlecloudplatform/gcsfuse/lease/mock_lease"
	. "github.com/jacobsa/ogletest"
)

func TestAutoRefreshingReadLease(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

const contents = "taco"

// A function that always successfully returns our contents constant.
func returnContents() (rc io.ReadCloser, err error) {
	rc = ioutil.NopCloser(strings.NewReader(contents))
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type AutoRefreshingReadLeaseTest struct {
	// A function that will be invoked for each call to the function given to
	// NewAutoRefreshingReadLease.
	f func() (io.ReadCloser, error)

	leaser mock_lease.MockFileLeaser
	lease  lease.ReadLease
}

var _ SetUpInterface = &AutoRefreshingReadLeaseTest{}

func init() { RegisterTestSuite(&AutoRefreshingReadLeaseTest{}) }

func (t *AutoRefreshingReadLeaseTest) SetUp(ti *TestInfo) {
	// Set up a function that defers to whatever is currently set as t.f.
	f := func() (rc io.ReadCloser, err error) {
		AssertNe(nil, t.f)
		rc, err = t.f()
		return
	}

	// Set up the leaser.
	t.leaser = mock_lease.NewMockFileLeaser(ti.MockController, "leaser")

	// Set up the lease.
	t.lease = lease.NewAutoRefreshingReadLease(
		t.leaser,
		int64(len(contents)),
		f)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *AutoRefreshingReadLeaseTest) Size() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) LeaserReturnsError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) CallsFunc() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) FuncReturnsError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) ContentsReturnReadError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) ContentsReturnCloseError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) ContentsAreWrongLength() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) DowngradesAfterRead() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) DowngradesAfterReadAt() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) DowngradesAfterSeek() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Upgrade_Error() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Upgrade_Success() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Upgrade_Failure() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) SecondRead_StillValid() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) SecondRead_Revoked_ErrorReading() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) SecondRead_Revoked_Successful() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Revoke() {
	AssertTrue(false, "TODO")
}
<commit_msg>AutoRefreshingReadLeaseTest.Size<commit_after>// Copyright 2015 Google Inc. 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.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lease_test

import (
	"io"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/googlecloudplatform/gcsfuse/lease"
	"github.com/googlecloudplatform/gcsfuse/lease/mock_lease"
	. "github.com/jacobsa/ogletest"
)

func TestAutoRefreshingReadLease(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

const contents = "taco"

// A function that always successfully returns our contents constant.
func returnContents() (rc io.ReadCloser, err error) {
	rc = ioutil.NopCloser(strings.NewReader(contents))
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type AutoRefreshingReadLeaseTest struct {
	// A function that will be invoked for each call to the function given to
	// NewAutoRefreshingReadLease.
	f func() (io.ReadCloser, error)

	leaser mock_lease.MockFileLeaser
	lease  lease.ReadLease
}

var _ SetUpInterface = &AutoRefreshingReadLeaseTest{}

func init() { RegisterTestSuite(&AutoRefreshingReadLeaseTest{}) }

func (t *AutoRefreshingReadLeaseTest) SetUp(ti *TestInfo) {
	// Set up a function that defers to whatever is currently set as t.f.
	f := func() (rc io.ReadCloser, err error) {
		AssertNe(nil, t.f)
		rc, err = t.f()
		return
	}

	// Set up the leaser.
	t.leaser = mock_lease.NewMockFileLeaser(ti.MockController, "leaser")

	// Set up the lease.
	t.lease = lease.NewAutoRefreshingReadLease(
		t.leaser,
		int64(len(contents)),
		f)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *AutoRefreshingReadLeaseTest) Size() {
	ExpectEq(len(contents), t.lease.Size())
}

func (t *AutoRefreshingReadLeaseTest) LeaserReturnsError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) CallsFunc() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) FuncReturnsError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) ContentsReturnReadError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) ContentsReturnCloseError() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) ContentsAreWrongLength() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) DowngradesAfterRead() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) DowngradesAfterReadAt() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) DowngradesAfterSeek() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Upgrade_Error() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Upgrade_Success() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Upgrade_Failure() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) SecondRead_StillValid() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) SecondRead_Revoked_ErrorReading() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) SecondRead_Revoked_Successful() {
	AssertTrue(false, "TODO")
}

func (t *AutoRefreshingReadLeaseTest) Revoke() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>/* https://leetcode.com/problems/split-linked-list-in-parts/
Given a (singly) linked list with head node root, write a function to split the linked list into k consecutive linked list "parts".

The length of each part should be as equal as possible: no two parts should have a size differing by more than 1.
This may lead to some parts being null.

The parts should be in order of occurrence in the input list,
and parts occurring earlier should always have a size greater than or equal parts occurring later.

Return a List of ListNode's representing the linked list parts that are formed.

Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ]

Example 1:
	Input:
	root = [1, 2, 3], k = 5
	Output: [[1],[2],[3],[],[]]
	Explanation:
		The input and each element of the output are ListNodes, not arrays.
		For example, the input root has root.val = 1, root.next.val = 2, \root.next.next.val = 3, and root.next.next.next = null.
		The first element output[0] has output[0].val = 1, output[0].next = null.
		The last element output[4] is null, but it's string representation as a ListNode is [].

Example 2:
	Input:
	root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
	Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
	Explanation:
		The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.

Note:

	The length of root will be in the range [0, 1000].
	Each value of a node in the input will be an integer in the range [0, 999].
	k will be an integer in the range [1, 50].
*/

package lll

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func splitListToParts(root *ListNode, k int) []*ListNode {
	length := 0
	for c := root; c != nil; c = c.Next {
		length++
	}

	div, mod := length/k, length%k
	res := make([]*ListNode, k, k)
	var pre, node *ListNode
	for idx, c := 0, root; idx < k; idx++ {
		lenSum := div
		if idx < mod {
			lenSum = div + 1
		}
		for i := 0; i < lenSum && c != nil; i++ {
			node = &ListNode{Val: c.Val}
			if i == 0 {
				res[idx] = node
			} else {
				pre.Next = node
			}
			pre = node
			c = c.Next
		}
	}
	return res
}
<commit_msg>split: old root ListNode can changed<commit_after>/* https://leetcode.com/problems/split-linked-list-in-parts/
Given a (singly) linked list with head node root, write a function to split the linked list into k consecutive linked list "parts".

The length of each part should be as equal as possible: no two parts should have a size differing by more than 1.
This may lead to some parts being null.

The parts should be in order of occurrence in the input list,
and parts occurring earlier should always have a size greater than or equal parts occurring later.

Return a List of ListNode's representing the linked list parts that are formed.

Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ]

Example 1:
	Input:
	root = [1, 2, 3], k = 5
	Output: [[1],[2],[3],[],[]]
	Explanation:
		The input and each element of the output are ListNodes, not arrays.
		For example, the input root has root.val = 1, root.next.val = 2, \root.next.next.val = 3, and root.next.next.next = null.
		The first element output[0] has output[0].val = 1, output[0].next = null.
		The last element output[4] is null, but it's string representation as a ListNode is [].

Example 2:
	Input:
	root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
	Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
	Explanation:
		The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.

Note:

	The length of root will be in the range [0, 1000].
	Each value of a node in the input will be an integer in the range [0, 999].
	k will be an integer in the range [1, 50].
*/

package lll

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func splitListToParts(root *ListNode, k int) []*ListNode {
	length := 0
	for c := root; c != nil; c = c.Next {
		length++
	}

	div, mod := length/k, length%k
	res := make([]*ListNode, k, k)
	for i, c := 0, root; i < k; i++ {
		res[i] = c
		num := div
		if i < mod {
			num++
		}
		for j := 0; j < num-1; j++ {
			c = c.Next
		}
		if c != nil {
			c, c.Next = c.Next, nil
		}
	}
	return res
}
<|endoftext|>


<commit_before>package drouter

import (
	"net"
	"strconv"
	"errors"
	"strings"
	//"os/exec"
	//"fmt"
	"time"
	"os"
	"bufio"
	//"os/signal"
	//"syscall"
	//"bytes"
	//"io/ioutil"

	log "github.com/Sirupsen/logrus"
	//"github.com/samalba/dockerclient"
	dockerclient "github.com/docker/engine-api/client"
	dockertypes "github.com/docker/engine-api/types"
	dockerfilters "github.com/docker/engine-api/types/filters"
	dockernetworks "github.com/docker/engine-api/types/network"
	"golang.org/x/net/context"
	"github.com/vishvananda/netlink"
	"github.com/vishvananda/netns"
	"github.com/ziutek/utils/netaddr"
)

var (
	docker                *dockerclient.Client
	self_container        dockertypes.ContainerJSON
	networks              = make(map[string]bool)
	host_ns_h             *netlink.Handle
	self_ns_h             *netlink.Handle
	host_route_link_index int
	host_route_gw		    net.IP
	my_pid                = os.Getpid()
)

func init() {
	var err error

	if my_pid == 1 {
		log.Fatal("Running as Pid 1. drouter must be run with --pid=host")
	}

	defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
	docker, err = dockerclient.NewClient("unix:///var/run/docker.sock", "v1.23", nil, defaultHeaders)
	if err != nil {
		log.Error("Error connecting to docker socket")
		log.Fatal(err)
	}
	self_container, err = getSelf()
	if err != nil {
		log.Error("Error getting self container. Is this processs running in a container? Is the docker socket passed through?")
		log.Fatal(err)
	}

	// Prepopulate networks that this container is a member of
	for _, settings := range self_container.NetworkSettings.Networks {
		networks[settings.NetworkID] = true
	}

	self_ns, err := netns.Get()
	if err != nil {
		log.Error("Error getting self namespace.")
		log.Fatal(err)
	}
	self_ns_h, err = netlink.NewHandleAt(self_ns)
	if err != nil {
		log.Error("Error getting handle at self namespace.")
		log.Fatal(err)
	}
	host_ns, err := netns.GetFromPid(1)
	if err != nil {
		log.Error("Error getting host namespace. Is this container running in priveleged mode?")
		log.Fatal(err)
	}
	host_ns_h, err = netlink.NewHandleAt(host_ns)
	if err != nil {
		log.Error("Error getting handle at host namespace.")
		log.Fatal(err)
	}
}

// Loop to watch for new networks created and create interfaces when needed
func WatchNetworks() {
	log.Info("Watching Networks")
	for {
		nets, err := docker.NetworkList(context.Background(), dockertypes.NetworkListOptions{ Filters: dockerfilters.NewArgs(), })
		if err != nil {
			log.Error("Error getting network list")
			log.Error(err)
		}
		for i := range nets {
			drouter_str := nets[i].Options["drouter"]
			drouter := false
			if drouter_str != "" {
				drouter, err = strconv.ParseBool(drouter_str)
				if err != nil {
					log.Errorf("Error parsing drouter option: %v", drouter_str)
					log.Error(err)
				}
			}

			if drouter && !networks[nets[i].ID] {
				log.Debugf("Joining Net: %+v", nets[i])
				err := joinNet(&nets[i])
				if err != nil {
					log.Errorf("Error joining network: %v", nets[i])
					log.Error(err)
				}
			} else if !drouter && networks[nets[i].ID] {
				log.Debugf("Leaving Net: %+v", nets[i])
				err := leaveNet(&nets[i])
				if err != nil {
					log.Errorf("Error leaving network: %v", nets[i])
					log.Error(err)
				}
			}
		}
		time.Sleep(5 * time.Second)
	}
}

func WatchEvents() {
	for {
		time.Sleep(1 * time.Second)
	}
}

func joinNet(n *dockertypes.NetworkResource) error {
	err := docker.NetworkConnect(context.Background(), n.ID, self_container.ID, &dockernetworks.EndpointSettings{})
	if err != nil {
		return err
	}
	networks[n.ID] = true
	_, dst, err := net.ParseCIDR(n.IPAM.Config.Subnet)
	if err != nil {
		return err
	}
	route := &netlink.Route{
		LinkIndex: host_route_link_index,
		Gw: host_route_gw,
		Dst: dst,
	}
	err = host_ns_h.RouteAdd(route)
	if err != nil {
		return err
	}
	return nil
}

func leaveNet(n *dockertypes.NetworkResource) error {
	err := docker.NetworkDisconnect(context.Background(), n.ID, self_container.ID, true)
	if err != nil {
		return err
	}
	networks[n.ID] = false
	return nil
}

func getSelf() (dockertypes.ContainerJSON, error) {
	cgroup, err := os.Open("/proc/self/cgroup")
	if err != nil {
		return dockertypes.ContainerJSON{}, err
	}
	defer cgroup.Close()

	scanner := bufio.NewScanner(cgroup)
	for scanner.Scan() {
		line := strings.Split(scanner.Text(), "/")
		id := line[len(line) - 1]
		containerInfo, err := docker.ContainerInspect(context.Background(), id)
		if err != nil {
			log.Warnf("Error inspecting container: %v", id)
			log.Warn(err)
			continue
		}
		return containerInfo, nil
	}
	return dockertypes.ContainerJSON{}, errors.New("Container not found")
}

func MakeP2PLink(p2p_addr string) error {
	host_link_veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "drouter_veth0"},
		PeerName:  "drouter_veth1",
	}
	err := host_ns_h.LinkAdd(host_link_veth)
	if err != nil {
		return err
	}
	host_link, err := host_ns_h.LinkByName("drouter_veth0")
	if err != nil {
		return err
	}
	host_route_link_index = host_link.Attrs().Index

	int_link, err := host_ns_h.LinkByName("drouter_veth1")
	if err != nil {
		return err
	}
	err = host_ns_h.LinkSetNsPid(int_link, my_pid)
	if err != nil {
		return err
	}
	int_link, err = self_ns_h.LinkByName("drouter_veth1")
	if err != nil {
		return err
	}

	_, p2p_net, err := net.ParseCIDR(p2p_addr)
	if err != nil {
		return err
	}

	host_addr := *p2p_net
	host_addr.IP = netaddr.IPAdd(host_addr.IP, 1)
	host_netlink_addr := &netlink.Addr{
		IPNet: &host_addr,
		Label: "",
	}
	err = host_ns_h.AddrAdd(host_link, host_netlink_addr)
	if err != nil {
		return err
	}

	int_addr := *p2p_net
	int_addr.IP = netaddr.IPAdd(int_addr.IP, 2)
	int_netlink_addr := &netlink.Addr{
		IPNet: &int_addr,
		Label: "",
	}
	err = self_ns_h.AddrAdd(int_link, int_netlink_addr)
	if err != nil {
		return err
	}

	host_route_gw = int_addr.IP

	err = self_ns_h.LinkSetUp(int_link)
	if err != nil {
		return err
	}

	err = host_ns_h.LinkSetUp(host_link)
	if err != nil {
		return err
	}

	return nil
}

func Cleanup() error {
	log.Info("Cleaning Up")
	return removeP2PLink()
}

func removeP2PLink() error {
	host_link, err := host_ns_h.LinkByName("drouter_veth0")
	if err != nil {
		return err
	}
	return host_ns_h.LinkDel(host_link)
}

<commit_msg>ipamconfig is an array<commit_after>package drouter

import (
	"net"
	"strconv"
	"errors"
	"strings"
	//"os/exec"
	//"fmt"
	"time"
	"os"
	"bufio"
	//"os/signal"
	//"syscall"
	//"bytes"
	//"io/ioutil"

	log "github.com/Sirupsen/logrus"
	//"github.com/samalba/dockerclient"
	dockerclient "github.com/docker/engine-api/client"
	dockertypes "github.com/docker/engine-api/types"
	dockerfilters "github.com/docker/engine-api/types/filters"
	dockernetworks "github.com/docker/engine-api/types/network"
	"golang.org/x/net/context"
	"github.com/vishvananda/netlink"
	"github.com/vishvananda/netns"
	"github.com/ziutek/utils/netaddr"
)

var (
	docker                *dockerclient.Client
	self_container        dockertypes.ContainerJSON
	networks              = make(map[string]bool)
	host_ns_h             *netlink.Handle
	self_ns_h             *netlink.Handle
	host_route_link_index int
	host_route_gw		    net.IP
	my_pid                = os.Getpid()
)

func init() {
	var err error

	if my_pid == 1 {
		log.Fatal("Running as Pid 1. drouter must be run with --pid=host")
	}

	defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
	docker, err = dockerclient.NewClient("unix:///var/run/docker.sock", "v1.23", nil, defaultHeaders)
	if err != nil {
		log.Error("Error connecting to docker socket")
		log.Fatal(err)
	}
	self_container, err = getSelf()
	if err != nil {
		log.Error("Error getting self container. Is this processs running in a container? Is the docker socket passed through?")
		log.Fatal(err)
	}

	// Prepopulate networks that this container is a member of
	for _, settings := range self_container.NetworkSettings.Networks {
		networks[settings.NetworkID] = true
	}

	self_ns, err := netns.Get()
	if err != nil {
		log.Error("Error getting self namespace.")
		log.Fatal(err)
	}
	self_ns_h, err = netlink.NewHandleAt(self_ns)
	if err != nil {
		log.Error("Error getting handle at self namespace.")
		log.Fatal(err)
	}
	host_ns, err := netns.GetFromPid(1)
	if err != nil {
		log.Error("Error getting host namespace. Is this container running in priveleged mode?")
		log.Fatal(err)
	}
	host_ns_h, err = netlink.NewHandleAt(host_ns)
	if err != nil {
		log.Error("Error getting handle at host namespace.")
		log.Fatal(err)
	}
}

// Loop to watch for new networks created and create interfaces when needed
func WatchNetworks() {
	log.Info("Watching Networks")
	for {
		nets, err := docker.NetworkList(context.Background(), dockertypes.NetworkListOptions{ Filters: dockerfilters.NewArgs(), })
		if err != nil {
			log.Error("Error getting network list")
			log.Error(err)
		}
		for i := range nets {
			drouter_str := nets[i].Options["drouter"]
			drouter := false
			if drouter_str != "" {
				drouter, err = strconv.ParseBool(drouter_str)
				if err != nil {
					log.Errorf("Error parsing drouter option: %v", drouter_str)
					log.Error(err)
				}
			}

			if drouter && !networks[nets[i].ID] {
				log.Debugf("Joining Net: %+v", nets[i])
				err := joinNet(&nets[i])
				if err != nil {
					log.Errorf("Error joining network: %v", nets[i])
					log.Error(err)
				}
			} else if !drouter && networks[nets[i].ID] {
				log.Debugf("Leaving Net: %+v", nets[i])
				err := leaveNet(&nets[i])
				if err != nil {
					log.Errorf("Error leaving network: %v", nets[i])
					log.Error(err)
				}
			}
		}
		time.Sleep(5 * time.Second)
	}
}

func WatchEvents() {
	for {
		time.Sleep(1 * time.Second)
	}
}

func joinNet(n *dockertypes.NetworkResource) error {
	err := docker.NetworkConnect(context.Background(), n.ID, self_container.ID, &dockernetworks.EndpointSettings{})
	if err != nil {
		return err
	}
	networks[n.ID] = true
	for i := range n.IPAM.Config {
		ipamconfig := n.IPAM.Config[i]
		_, dst, err := net.ParseCIDR(ipamconfig.Subnet)
		if err != nil {
			return err
		}
		route := &netlink.Route{
			LinkIndex: host_route_link_index,
			Gw: host_route_gw,
			Dst: dst,
		}
		err = host_ns_h.RouteAdd(route)
		if err != nil {
			return err
		}
	}
	return nil
}

func leaveNet(n *dockertypes.NetworkResource) error {
	err := docker.NetworkDisconnect(context.Background(), n.ID, self_container.ID, true)
	if err != nil {
		return err
	}
	networks[n.ID] = false
	return nil
}

func getSelf() (dockertypes.ContainerJSON, error) {
	cgroup, err := os.Open("/proc/self/cgroup")
	if err != nil {
		return dockertypes.ContainerJSON{}, err
	}
	defer cgroup.Close()

	scanner := bufio.NewScanner(cgroup)
	for scanner.Scan() {
		line := strings.Split(scanner.Text(), "/")
		id := line[len(line) - 1]
		containerInfo, err := docker.ContainerInspect(context.Background(), id)
		if err != nil {
			log.Warnf("Error inspecting container: %v", id)
			log.Warn(err)
			continue
		}
		return containerInfo, nil
	}
	return dockertypes.ContainerJSON{}, errors.New("Container not found")
}

func MakeP2PLink(p2p_addr string) error {
	host_link_veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "drouter_veth0"},
		PeerName:  "drouter_veth1",
	}
	err := host_ns_h.LinkAdd(host_link_veth)
	if err != nil {
		return err
	}
	host_link, err := host_ns_h.LinkByName("drouter_veth0")
	if err != nil {
		return err
	}
	host_route_link_index = host_link.Attrs().Index

	int_link, err := host_ns_h.LinkByName("drouter_veth1")
	if err != nil {
		return err
	}
	err = host_ns_h.LinkSetNsPid(int_link, my_pid)
	if err != nil {
		return err
	}
	int_link, err = self_ns_h.LinkByName("drouter_veth1")
	if err != nil {
		return err
	}

	_, p2p_net, err := net.ParseCIDR(p2p_addr)
	if err != nil {
		return err
	}

	host_addr := *p2p_net
	host_addr.IP = netaddr.IPAdd(host_addr.IP, 1)
	host_netlink_addr := &netlink.Addr{
		IPNet: &host_addr,
		Label: "",
	}
	err = host_ns_h.AddrAdd(host_link, host_netlink_addr)
	if err != nil {
		return err
	}

	int_addr := *p2p_net
	int_addr.IP = netaddr.IPAdd(int_addr.IP, 2)
	int_netlink_addr := &netlink.Addr{
		IPNet: &int_addr,
		Label: "",
	}
	err = self_ns_h.AddrAdd(int_link, int_netlink_addr)
	if err != nil {
		return err
	}

	host_route_gw = int_addr.IP

	err = self_ns_h.LinkSetUp(int_link)
	if err != nil {
		return err
	}

	err = host_ns_h.LinkSetUp(host_link)
	if err != nil {
		return err
	}

	return nil
}

func Cleanup() error {
	log.Info("Cleaning Up")
	return removeP2PLink()
}

func removeP2PLink() error {
	host_link, err := host_ns_h.LinkByName("drouter_veth0")
	if err != nil {
		return err
	}
	return host_ns_h.LinkDel(host_link)
}

<|endoftext|>


<commit_before>package session
<commit_msg>增加session.go测试用例.<commit_after>package session

import (
	"testing"
	"github.com/devfeel/dotweb/test"
)

const (
	IP="0.0.0.0"
)

func TestGetSessionStore(t *testing.T) {
	defaultConfig:=NewDefaultRuntimeConfig()

	defaultSessionStore:=GetSessionStore(defaultConfig)

	test.Equal(t,SessionMode_Runtime,defaultConfig.StoreName)
	test.Equal(t,int64(DefaultSessionMaxLifeTime),defaultConfig.Maxlifetime)
	test.Equal(t,"",defaultConfig.ServerIP)

	test.NotNil(t,defaultSessionStore)

	defaultRedisConfig:=NewDefaultRedisConfig(IP)

	defaultRedisSessionStore:=GetSessionStore(defaultRedisConfig)

	test.Equal(t,SessionMode_Redis,defaultRedisConfig.StoreName)
	test.Equal(t,int64(DefaultSessionMaxLifeTime),defaultRedisConfig.Maxlifetime)
	test.Equal(t,IP,defaultRedisConfig.ServerIP)

	test.NotNil(t,defaultRedisSessionStore)
}

func TestNewDefaultSessionManager(t *testing.T) {
	defaultRedisConfig:=NewDefaultRedisConfig(IP)
	manager,err:=NewDefaultSessionManager(defaultRedisConfig)

	test.Nil(t,err)
	test.NotNil(t, manager)

	test.NotNil(t, manager.store)
	test.Equal(t,int64(DefaultSessionGCLifeTime),manager.GCLifetime)
	test.Equal(t,DefaultSessionCookieName,manager.CookieName)
	test.Equal(t,defaultRedisConfig,manager.storeConfig)

	sessionId:=manager.NewSessionID()

	test.Equal(t,32,len(sessionId))

	sessionState,err:=manager.GetSessionState(sessionId)
	test.Nil(t,err)
	test.NotNil(t, sessionState)
	test.Equal(t,sessionId,sessionState.sessionId)
}

<|endoftext|>


<commit_before>// Package contentenc encrypts and decrypts file blocks.
package contentenc

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"errors"

	"github.com/rfjakob/gocryptfs/internal/cryptocore"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

// NonceMode determines how nonces are created.
type NonceMode int

const (
	// DefaultBS is the default plaintext block size
	DefaultBS = 4096
	// DefaultIVBits is the default length of IV, in bits.
	// We always use 128-bit IVs for file content, but the
	// key in the config file is encrypted with a 96-bit IV.
	DefaultIVBits = 128

	_ = iota // skip zero
	// RandomNonce chooses a random nonce.
	RandomNonce NonceMode = iota
	// ReverseDeterministicNonce chooses a deterministic nonce, suitable for
	// use in reverse mode.
	ReverseDeterministicNonce NonceMode = iota
	// ExternalNonce derives a nonce from external sources.
	ExternalNonce NonceMode = iota
)

// ContentEnc is used to encipher and decipher file content.
type ContentEnc struct {
	// Cryptographic primitives
	cryptoCore *cryptocore.CryptoCore
	// Plaintext block size
	plainBS uint64
	// Ciphertext block size
	cipherBS uint64
	// All-zero block of size cipherBS, for fast compares
	allZeroBlock []byte
	// All-zero block of size IVBitLen/8, for fast compares
	allZeroNonce []byte
}

// New returns an initialized ContentEnc instance.
func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc {
	cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen

	return &ContentEnc{
		cryptoCore:   cc,
		plainBS:      plainBS,
		cipherBS:     cipherBS,
		allZeroBlock: make([]byte, cipherBS),
		allZeroNonce: make([]byte, cc.IVLen),
	}
}

// PlainBS returns the plaintext block size
func (be *ContentEnc) PlainBS() uint64 {
	return be.plainBS
}

// CipherBS returns the ciphertext block size
func (be *ContentEnc) CipherBS() uint64 {
	return be.cipherBS
}

// DecryptBlocks decrypts a number of blocks
// TODO refactor to three-param for
func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileID []byte) ([]byte, error) {
	cBuf := bytes.NewBuffer(ciphertext)
	var err error
	var pBuf bytes.Buffer
	for cBuf.Len() > 0 {
		cBlock := cBuf.Next(int(be.cipherBS))
		var pBlock []byte
		pBlock, err = be.DecryptBlock(cBlock, firstBlockNo, fileID)
		if err != nil {
			break
		}
		pBuf.Write(pBlock)
		firstBlockNo++
	}
	return pBuf.Bytes(), err
}

// DecryptBlock - Verify and decrypt GCM block
//
// Corner case: A full-sized block of all-zero ciphertext bytes is translated
// to an all-zero plaintext block, i.e. file hole passtrough.
func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []byte) ([]byte, error) {

	// Empty block?
	if len(ciphertext) == 0 {
		return ciphertext, nil
	}

	// All-zero block?
	if bytes.Equal(ciphertext, be.allZeroBlock) {
		tlog.Debug.Printf("DecryptBlock: file hole encountered")
		return make([]byte, be.plainBS), nil
	}

	if len(ciphertext) < be.cryptoCore.IVLen {
		tlog.Warn.Printf("DecryptBlock: Block is too short: %d bytes", len(ciphertext))
		return nil, errors.New("Block is too short")
	}

	// Extract nonce
	nonce := ciphertext[:be.cryptoCore.IVLen]
	if bytes.Equal(nonce, be.allZeroNonce) {
		panic("Hit an all-zero nonce. This MUST NOT happen!")
	}
	ciphertextOrig := ciphertext
	ciphertext = ciphertext[be.cryptoCore.IVLen:]

	// Decrypt
	var plaintext []byte
	aData := make([]byte, 8)
	aData = append(aData, fileID...)
	binary.BigEndian.PutUint64(aData, blockNo)
	plaintext, err := be.cryptoCore.AEADCipher.Open(plaintext, nonce, ciphertext, aData)

	if err != nil {
		tlog.Warn.Printf("DecryptBlock: %s, len=%d", err.Error(), len(ciphertextOrig))
		tlog.Debug.Println(hex.Dump(ciphertextOrig))
		return nil, err
	}

	return plaintext, nil
}

// EncryptBlock - Encrypt plaintext using a random nonce.
// blockNo and fileID are used as associated data.
// The output is nonce + ciphertext + tag.
func (be *ContentEnc) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte {
	// Get a fresh random nonce
	nonce := be.cryptoCore.IVGenerator.Get()
	return be.doEncryptBlock(plaintext, blockNo, fileID, nonce)
}

// EncryptBlockNonce - Encrypt plaintext using a nonce chosen by the caller.
// blockNo and fileID are used as associated data.
// The output is nonce + ciphertext + tag.
// This function can only be used in SIV mode.
func (be *ContentEnc) EncryptBlockNonce(plaintext []byte, blockNo uint64, fileID []byte, nonce []byte) []byte {
	if be.cryptoCore.AEADBackend != cryptocore.BackendAESSIV {
		panic("deterministic nonces are only secure in SIV mode")
	}
	return be.doEncryptBlock(plaintext, blockNo, fileID, nonce)
}

// doEncryptBlock is the backend for EncryptBlock and EncryptBlockNonce.
// blockNo and fileID are used as associated data.
// The output is nonce + ciphertext + tag.
func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID []byte, nonce []byte) []byte {
	// Empty block?
	if len(plaintext) == 0 {
		return plaintext
	}
	if len(nonce) != be.cryptoCore.IVLen {
		panic("wrong nonce length")
	}

	// Authenticate block with block number and file ID
	aData := make([]byte, 8)
	binary.BigEndian.PutUint64(aData, blockNo)
	aData = append(aData, fileID...)

	// Encrypt plaintext and append to nonce
	ciphertext := be.cryptoCore.AEADCipher.Seal(nonce, nonce, plaintext, aData)

	return ciphertext
}

// MergeBlocks - Merge newData into oldData at offset
// New block may be bigger than both newData and oldData
func (be *ContentEnc) MergeBlocks(oldData []byte, newData []byte, offset int) []byte {

	// Make block of maximum size
	out := make([]byte, be.plainBS)

	// Copy old and new data into it
	copy(out, oldData)
	l := len(newData)
	copy(out[offset:offset+l], newData)

	// Crop to length
	outLen := len(oldData)
	newLen := offset + len(newData)
	if outLen < newLen {
		outLen = newLen
	}
	return out[0:outLen]
}
<commit_msg>fusefrontend: I/O error instead of panic on all-zero nonce<commit_after>// Package contentenc encrypts and decrypts file blocks.
package contentenc

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"errors"

	"github.com/rfjakob/gocryptfs/internal/cryptocore"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

// NonceMode determines how nonces are created.
type NonceMode int

const (
	// DefaultBS is the default plaintext block size
	DefaultBS = 4096
	// DefaultIVBits is the default length of IV, in bits.
	// We always use 128-bit IVs for file content, but the
	// key in the config file is encrypted with a 96-bit IV.
	DefaultIVBits = 128

	_ = iota // skip zero
	// RandomNonce chooses a random nonce.
	RandomNonce NonceMode = iota
	// ReverseDeterministicNonce chooses a deterministic nonce, suitable for
	// use in reverse mode.
	ReverseDeterministicNonce NonceMode = iota
	// ExternalNonce derives a nonce from external sources.
	ExternalNonce NonceMode = iota
)

// ContentEnc is used to encipher and decipher file content.
type ContentEnc struct {
	// Cryptographic primitives
	cryptoCore *cryptocore.CryptoCore
	// Plaintext block size
	plainBS uint64
	// Ciphertext block size
	cipherBS uint64
	// All-zero block of size cipherBS, for fast compares
	allZeroBlock []byte
	// All-zero block of size IVBitLen/8, for fast compares
	allZeroNonce []byte
}

// New returns an initialized ContentEnc instance.
func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc {
	cipherBS := plainBS + uint64(cc.IVLen) + cryptocore.AuthTagLen

	return &ContentEnc{
		cryptoCore:   cc,
		plainBS:      plainBS,
		cipherBS:     cipherBS,
		allZeroBlock: make([]byte, cipherBS),
		allZeroNonce: make([]byte, cc.IVLen),
	}
}

// PlainBS returns the plaintext block size
func (be *ContentEnc) PlainBS() uint64 {
	return be.plainBS
}

// CipherBS returns the ciphertext block size
func (be *ContentEnc) CipherBS() uint64 {
	return be.cipherBS
}

// DecryptBlocks decrypts a number of blocks
// TODO refactor to three-param for
func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, fileID []byte) ([]byte, error) {
	cBuf := bytes.NewBuffer(ciphertext)
	var err error
	var pBuf bytes.Buffer
	for cBuf.Len() > 0 {
		cBlock := cBuf.Next(int(be.cipherBS))
		var pBlock []byte
		pBlock, err = be.DecryptBlock(cBlock, firstBlockNo, fileID)
		if err != nil {
			break
		}
		pBuf.Write(pBlock)
		firstBlockNo++
	}
	return pBuf.Bytes(), err
}

// DecryptBlock - Verify and decrypt GCM block
//
// Corner case: A full-sized block of all-zero ciphertext bytes is translated
// to an all-zero plaintext block, i.e. file hole passtrough.
func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []byte) ([]byte, error) {

	// Empty block?
	if len(ciphertext) == 0 {
		return ciphertext, nil
	}

	// All-zero block?
	if bytes.Equal(ciphertext, be.allZeroBlock) {
		tlog.Debug.Printf("DecryptBlock: file hole encountered")
		return make([]byte, be.plainBS), nil
	}

	if len(ciphertext) < be.cryptoCore.IVLen {
		tlog.Warn.Printf("DecryptBlock: Block is too short: %d bytes", len(ciphertext))
		return nil, errors.New("Block is too short")
	}

	// Extract nonce
	nonce := ciphertext[:be.cryptoCore.IVLen]
	if bytes.Equal(nonce, be.allZeroNonce) {
		// Bug in tmpfs?
		// https://github.com/rfjakob/gocryptfs/issues/56
		// http://www.spinics.net/lists/kernel/msg2370127.html
		return nil, errors.New("all-zero nonce")
	}
	ciphertextOrig := ciphertext
	ciphertext = ciphertext[be.cryptoCore.IVLen:]

	// Decrypt
	var plaintext []byte
	aData := make([]byte, 8)
	aData = append(aData, fileID...)
	binary.BigEndian.PutUint64(aData, blockNo)
	plaintext, err := be.cryptoCore.AEADCipher.Open(plaintext, nonce, ciphertext, aData)

	if err != nil {
		tlog.Warn.Printf("DecryptBlock: %s, len=%d", err.Error(), len(ciphertextOrig))
		tlog.Debug.Println(hex.Dump(ciphertextOrig))
		return nil, err
	}

	return plaintext, nil
}

// EncryptBlock - Encrypt plaintext using a random nonce.
// blockNo and fileID are used as associated data.
// The output is nonce + ciphertext + tag.
func (be *ContentEnc) EncryptBlock(plaintext []byte, blockNo uint64, fileID []byte) []byte {
	// Get a fresh random nonce
	nonce := be.cryptoCore.IVGenerator.Get()
	return be.doEncryptBlock(plaintext, blockNo, fileID, nonce)
}

// EncryptBlockNonce - Encrypt plaintext using a nonce chosen by the caller.
// blockNo and fileID are used as associated data.
// The output is nonce + ciphertext + tag.
// This function can only be used in SIV mode.
func (be *ContentEnc) EncryptBlockNonce(plaintext []byte, blockNo uint64, fileID []byte, nonce []byte) []byte {
	if be.cryptoCore.AEADBackend != cryptocore.BackendAESSIV {
		panic("deterministic nonces are only secure in SIV mode")
	}
	return be.doEncryptBlock(plaintext, blockNo, fileID, nonce)
}

// doEncryptBlock is the backend for EncryptBlock and EncryptBlockNonce.
// blockNo and fileID are used as associated data.
// The output is nonce + ciphertext + tag.
func (be *ContentEnc) doEncryptBlock(plaintext []byte, blockNo uint64, fileID []byte, nonce []byte) []byte {
	// Empty block?
	if len(plaintext) == 0 {
		return plaintext
	}
	if len(nonce) != be.cryptoCore.IVLen {
		panic("wrong nonce length")
	}

	// Authenticate block with block number and file ID
	aData := make([]byte, 8)
	binary.BigEndian.PutUint64(aData, blockNo)
	aData = append(aData, fileID...)

	// Encrypt plaintext and append to nonce
	ciphertext := be.cryptoCore.AEADCipher.Seal(nonce, nonce, plaintext, aData)

	return ciphertext
}

// MergeBlocks - Merge newData into oldData at offset
// New block may be bigger than both newData and oldData
func (be *ContentEnc) MergeBlocks(oldData []byte, newData []byte, offset int) []byte {

	// Make block of maximum size
	out := make([]byte, be.plainBS)

	// Copy old and new data into it
	copy(out, oldData)
	l := len(newData)
	copy(out[offset:offset+l], newData)

	// Crop to length
	outLen := len(oldData)
	newLen := offset + len(newData)
	if outLen < newLen {
		outLen = newLen
	}
	return out[0:outLen]
}
<|endoftext|>


<commit_before>package mpdtest

import (
	"bufio"
	"context"
	"fmt"
	"net"
	"strings"
	"sync"
)

// Server is mock mpd server.
type Server struct {
	ln         net.Listener
	Proto      string
	URL        string
	disconnect chan struct{}
	rc         chan *rConn
	mu         sync.Mutex
	closed     bool
}

type rConn struct {
	read string
	wc   chan string
}

// Disconnect closes current connection.
func (s *Server) Disconnect(ctx context.Context) {
	s.mu.Lock()
	if s.closed {
		s.mu.Unlock()
		return
	}
	select {
	case s.disconnect <- struct{}{}:
	case <-ctx.Done():
	}
	s.mu.Unlock()
}

// Close closes connection
func (s *Server) Close() {
	s.mu.Lock()
	defer s.mu.Unlock()
	if !s.closed {
		s.closed = true
		close(s.disconnect)
		s.ln.Close()
	}
}

// WR represents testserver Write / Read string
type WR struct {
	Read  string
	Write string
}

// Expect expects mpd read/write message
func (s *Server) Expect(ctx context.Context, m *WR) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	case r := <-s.rc:
		w := m.Write
		if r.read != m.Read {
			got, want := strings.TrimSuffix(r.read, "\n"), strings.TrimSuffix(m.Read, "\n")
			w = fmt.Sprintf("ACK [5@0] {%s} got %q; want %q\n", got, got, want)
		}
		select {
		case <-ctx.Done():
		case r.wc <- w:
		}
	}
	return nil
}

// NewServer creates new mpd mock Server for idle command.
func NewServer(firstResp string) *Server {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(fmt.Sprintf("mpdtest: failed to listen on a port: %v", err))
	}
	rc := make(chan *rConn)
	s := &Server{
		ln:         ln,
		Proto:      "tcp",
		URL:        ln.Addr().String(),
		disconnect: make(chan struct{}, 1),
		rc:         rc,
	}
	go func(ln net.Listener) {
		var wg sync.WaitGroup
		for {
			conn, err := ln.Accept()
			if err != nil {
				return
			}
			if _, err := fmt.Fprintln(conn, firstResp); err != nil {
				break
			}
			wg.Add(1)
			go func(conn net.Conn) {
				defer wg.Done()
				ctx, cancel := context.WithCancel(context.Background())
				defer cancel()
				wg.Add(1)
				go func() {
					defer wg.Done()
					defer cancel()
					defer conn.Close()
					r := bufio.NewReader(conn)
					wc := make(chan string, 1)
					for {
						nl, err := r.ReadString('\n')
						if err != nil {
							return
						}
						rc <- &rConn{
							read: nl,
							wc:   wc,
						}
						select {
						case <-ctx.Done():
							return
						case l := <-wc:
							if len(l) != 0 {
								if _, err := fmt.Fprint(conn, l); err != nil {
									return
								}
							}
						}
					}
				}()
				select {
				case <-ctx.Done():
				case <-s.disconnect:
				}
				conn.Close()
			}(conn)
		}
	}(ln)
	return s
}
<commit_msg>closes mpdtest.Server when the first response fails<commit_after>package mpdtest

import (
	"bufio"
	"context"
	"fmt"
	"net"
	"strings"
	"sync"
)

// Server is mock mpd server.
type Server struct {
	ln         net.Listener
	Proto      string
	URL        string
	disconnect chan struct{}
	rc         chan *rConn
	mu         sync.Mutex
	closed     bool
}

type rConn struct {
	read string
	wc   chan string
}

// Disconnect closes current connection.
func (s *Server) Disconnect(ctx context.Context) {
	s.mu.Lock()
	if s.closed {
		s.mu.Unlock()
		return
	}
	select {
	case s.disconnect <- struct{}{}:
	case <-ctx.Done():
	}
	s.mu.Unlock()
}

// Close closes connection
func (s *Server) Close() {
	s.mu.Lock()
	defer s.mu.Unlock()
	if !s.closed {
		s.closed = true
		close(s.disconnect)
		s.ln.Close()
	}
}

// WR represents testserver Write / Read string
type WR struct {
	Read  string
	Write string
}

// Expect expects mpd read/write message
func (s *Server) Expect(ctx context.Context, m *WR) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	case r := <-s.rc:
		w := m.Write
		if r.read != m.Read {
			got, want := strings.TrimSuffix(r.read, "\n"), strings.TrimSuffix(m.Read, "\n")
			w = fmt.Sprintf("ACK [5@0] {%s} got %q; want %q\n", got, got, want)
		}
		select {
		case <-ctx.Done():
		case r.wc <- w:
		}
	}
	return nil
}

// NewServer creates new mpd mock Server for idle command.
func NewServer(firstResp string) *Server {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(fmt.Sprintf("mpdtest: failed to listen on a port: %v", err))
	}
	rc := make(chan *rConn)
	s := &Server{
		ln:         ln,
		Proto:      "tcp",
		URL:        ln.Addr().String(),
		disconnect: make(chan struct{}, 1),
		rc:         rc,
	}
	go func(ln net.Listener) {
		for {
			conn, err := ln.Accept()
			if err != nil {
				return
			}
			go func(conn net.Conn) {
				ctx, cancel := context.WithCancel(context.Background())
				defer cancel()
				go func() {
					defer cancel()
					defer conn.Close()
					if _, err := fmt.Fprintln(conn, firstResp); err != nil {
						return
					}
					r := bufio.NewReader(conn)
					wc := make(chan string, 1)
					for {
						nl, err := r.ReadString('\n')
						if err != nil {
							return
						}
						rc <- &rConn{
							read: nl,
							wc:   wc,
						}
						select {
						case <-ctx.Done():
							return
						case l := <-wc:
							if len(l) != 0 {
								if _, err := fmt.Fprint(conn, l); err != nil {
									return
								}
							}
						}
					}
				}()
				select {
				case <-ctx.Done():
				case <-s.disconnect:
				}
				conn.Close()
			}(conn)
		}
	}(ln)
	return s
}
<|endoftext|>


<commit_before>package shared

import (
	"fmt"
	"io"

	"golang.org/x/net/html/charset"
)

func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
	conv, err := charset.NewReaderLabel(label, input)

	if err != nil {
		return nil, err
	}

	// Wrap the charset decoder reader with a XML sanitizer
	//clean := NewXMLSanitizerReader(conv)
	return conv, nil
}
<commit_msg>Remove unused pkg fmt (#67)<commit_after>package shared

import (
	"io"

	"golang.org/x/net/html/charset"
)

func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
	conv, err := charset.NewReaderLabel(label, input)

	if err != nil {
		return nil, err
	}

	// Wrap the charset decoder reader with a XML sanitizer
	//clean := NewXMLSanitizerReader(conv)
	return conv, nil
}
<|endoftext|>


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

package splunk

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"go.opentelemetry.io/collector/consumer/pdata"
	"go.opentelemetry.io/collector/translator/conventions"
)

var (
	ec2Resource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeCloudRegion, "us-west-2")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
	ec2WithHost = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeCloudRegion, "us-west-2")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		attr.InsertString(conventions.AttributeHostName, "localhost")
		return res
	}()
	ec2PartialResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
	gcpResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderGCP)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
	gcpPartialResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderGCP)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		return res
	}()
	azureResource = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudInfrastructureService, conventions.AttributeCloudProviderAzureVM)
		attrs.InsertString(conventions.AttributeHostName, "myHostName")
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.vm.size", "42")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		return res
	}()
	azureScalesetResource = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudInfrastructureService, conventions.AttributeCloudProviderAzureVM)
		attrs.InsertString(conventions.AttributeHostName, "myVMScalesetName_1")
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.vm.size", "42")
		attrs.InsertString("azure.vm.scaleset.name", "myVMScalesetName")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		return res
	}()
	azureMissingCloudAcct = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudInfrastructureService, conventions.AttributeCloudProviderAzureVM)
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString("azure.vm.size", "42")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		return res
	}()
	azureMissingResourceGroup = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudInfrastructureService, conventions.AttributeCloudProviderAzureVM)
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.vm.size", "42")
		return res
	}()
	azureMissingHostName = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudInfrastructureService, conventions.AttributeCloudProviderAzureVM)
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		attrs.InsertString("azure.vm.size", "42")
		return res
	}()
	hostResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeHostName, "localhost")
		return res
	}()
	unknownResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, "unknown")
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
)

func TestResourceToHostID(t *testing.T) {
	type args struct {
		res pdata.Resource
	}
	tests := []struct {
		name string
		args args
		want HostID
		ok   bool
	}{
		{
			name: "nil resource",
			args: args{pdata.NewResource()},
			want: HostID{},
			ok:   false,
		},
		{
			name: "ec2",
			args: args{ec2Resource},
			want: HostID{
				Key: "AWSUniqueId",
				ID:  "i-abcd_us-west-2_1234",
			},
			ok: true,
		},
		{
			name: "ec2 with hostname prefers ec2",
			args: args{ec2WithHost},
			want: HostID{
				Key: "AWSUniqueId",
				ID:  "i-abcd_us-west-2_1234",
			},
			ok: true,
		},
		{
			name: "gcp",
			args: args{gcpResource},
			want: HostID{
				Key: "gcp_id",
				ID:  "1234_i-abcd",
			},
			ok: true,
		},
		{
			name: "azure",
			args: args{azureResource},
			want: HostID{
				Key: "azure_resource_id",
				ID:  "mycloudaccount/myresourcegroupname/microsoft.compute/virtualmachines/myhostname",
			},
			ok: true,
		},
		{
			name: "azure scaleset",
			args: args{azureScalesetResource},
			want: HostID{
				Key: "azure_resource_id",
				ID:  "mycloudaccount/myresourcegroupname/microsoft.compute/virtualmachinescalesets/myvmscalesetname/virtualmachines/1",
			},
			ok: true,
		},
		{
			name: "azure cloud account missing",
			args: args{azureMissingCloudAcct},
			want: HostID{},
			ok:   false,
		},
		{
			name: "azure resource group missing",
			args: args{azureMissingResourceGroup},
			want: HostID{},
			ok:   false,
		},
		{
			name: "azure hostname missing",
			args: args{azureMissingHostName},
			want: HostID{},
			ok:   false,
		},
		{
			name: "ec2 attributes missing",
			args: args{ec2PartialResource},
			want: HostID{},
			ok:   false,
		},
		{
			name: "gcp attributes missing",
			args: args{gcpPartialResource},
			want: HostID{},
			ok:   false,
		},
		{
			name: "unknown provider",
			args: args{unknownResource},
			want: HostID{},
			ok:   false,
		},
		{
			name: "host provider",
			args: args{hostResource},
			want: HostID{
				Key: "host.name",
				ID:  "localhost",
			},
			ok: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			hostID, ok := ResourceToHostID(tt.args.res)
			assert.Equal(t, tt.ok, ok)
			assert.Equal(t, tt.want, hostID)
		})
	}
}

func TestAzureID(t *testing.T) {
	attrs := pdata.NewAttributeMap()
	attrs.Insert("azure.resourcegroup.name", pdata.NewAttributeValueString("myResourceGroup"))
	attrs.Insert("azure.vm.scaleset.name", pdata.NewAttributeValueString("myScalesetName"))
	attrs.Insert(conventions.AttributeHostName, pdata.NewAttributeValueString("myScalesetName_1"))
	id := azureID(attrs, "myCloudAccount")
	expected := "mycloudaccount/myresourcegroup/microsoft.compute/virtualmachinescalesets/myscalesetname/virtualmachines/1"
	assert.Equal(t, expected, id)
}
<commit_msg>Fix #2974 (#2975)<commit_after>// Copyright The OpenTelemetry 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.

package splunk

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"go.opentelemetry.io/collector/consumer/pdata"
	"go.opentelemetry.io/collector/translator/conventions"
)

var (
	ec2Resource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeCloudRegion, "us-west-2")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
	ec2WithHost = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeCloudRegion, "us-west-2")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		attr.InsertString(conventions.AttributeHostName, "localhost")
		return res
	}()
	ec2PartialResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAWS)
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
	gcpResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderGCP)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
	gcpPartialResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderGCP)
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		return res
	}()
	azureResource = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudPlatform, conventions.AttributeCloudPlatformAzureVM)
		attrs.InsertString(conventions.AttributeHostName, "myHostName")
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.vm.size", "42")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		return res
	}()
	azureScalesetResource = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudPlatform, conventions.AttributeCloudPlatformAzureVM)
		attrs.InsertString(conventions.AttributeHostName, "myVMScalesetName_1")
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.vm.size", "42")
		attrs.InsertString("azure.vm.scaleset.name", "myVMScalesetName")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		return res
	}()
	azureMissingCloudAcct = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudPlatform, conventions.AttributeCloudPlatformAzureVM)
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString("azure.vm.size", "42")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		return res
	}()
	azureMissingResourceGroup = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudPlatform, conventions.AttributeCloudPlatformAzureVM)
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.vm.size", "42")
		return res
	}()
	azureMissingHostName = func() pdata.Resource {
		res := pdata.NewResource()
		attrs := res.Attributes()
		attrs.InsertString(conventions.AttributeCloudProvider, conventions.AttributeCloudProviderAzure)
		attrs.InsertString(conventions.AttributeCloudPlatform, conventions.AttributeCloudPlatformAzureVM)
		attrs.InsertString(conventions.AttributeCloudRegion, "myCloudRegion")
		attrs.InsertString(conventions.AttributeHostID, "myHostID")
		attrs.InsertString(conventions.AttributeCloudAccount, "myCloudAccount")
		attrs.InsertString("azure.resourcegroup.name", "myResourcegroupName")
		attrs.InsertString("azure.vm.size", "42")
		return res
	}()
	hostResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeHostName, "localhost")
		return res
	}()
	unknownResource = func() pdata.Resource {
		res := pdata.NewResource()
		attr := res.Attributes()
		attr.InsertString(conventions.AttributeCloudProvider, "unknown")
		attr.InsertString(conventions.AttributeCloudAccount, "1234")
		attr.InsertString(conventions.AttributeHostID, "i-abcd")
		return res
	}()
)

func TestResourceToHostID(t *testing.T) {
	type args struct {
		res pdata.Resource
	}
	tests := []struct {
		name string
		args args
		want HostID
		ok   bool
	}{
		{
			name: "nil resource",
			args: args{pdata.NewResource()},
			want: HostID{},
			ok:   false,
		},
		{
			name: "ec2",
			args: args{ec2Resource},
			want: HostID{
				Key: "AWSUniqueId",
				ID:  "i-abcd_us-west-2_1234",
			},
			ok: true,
		},
		{
			name: "ec2 with hostname prefers ec2",
			args: args{ec2WithHost},
			want: HostID{
				Key: "AWSUniqueId",
				ID:  "i-abcd_us-west-2_1234",
			},
			ok: true,
		},
		{
			name: "gcp",
			args: args{gcpResource},
			want: HostID{
				Key: "gcp_id",
				ID:  "1234_i-abcd",
			},
			ok: true,
		},
		{
			name: "azure",
			args: args{azureResource},
			want: HostID{
				Key: "azure_resource_id",
				ID:  "mycloudaccount/myresourcegroupname/microsoft.compute/virtualmachines/myhostname",
			},
			ok: true,
		},
		{
			name: "azure scaleset",
			args: args{azureScalesetResource},
			want: HostID{
				Key: "azure_resource_id",
				ID:  "mycloudaccount/myresourcegroupname/microsoft.compute/virtualmachinescalesets/myvmscalesetname/virtualmachines/1",
			},
			ok: true,
		},
		{
			name: "azure cloud account missing",
			args: args{azureMissingCloudAcct},
			want: HostID{},
			ok:   false,
		},
		{
			name: "azure resource group missing",
			args: args{azureMissingResourceGroup},
			want: HostID{},
			ok:   false,
		},
		{
			name: "azure hostname missing",
			args: args{azureMissingHostName},
			want: HostID{},
			ok:   false,
		},
		{
			name: "ec2 attributes missing",
			args: args{ec2PartialResource},
			want: HostID{},
			ok:   false,
		},
		{
			name: "gcp attributes missing",
			args: args{gcpPartialResource},
			want: HostID{},
			ok:   false,
		},
		{
			name: "unknown provider",
			args: args{unknownResource},
			want: HostID{},
			ok:   false,
		},
		{
			name: "host provider",
			args: args{hostResource},
			want: HostID{
				Key: "host.name",
				ID:  "localhost",
			},
			ok: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			hostID, ok := ResourceToHostID(tt.args.res)
			assert.Equal(t, tt.ok, ok)
			assert.Equal(t, tt.want, hostID)
		})
	}
}

func TestAzureID(t *testing.T) {
	attrs := pdata.NewAttributeMap()
	attrs.Insert("azure.resourcegroup.name", pdata.NewAttributeValueString("myResourceGroup"))
	attrs.Insert("azure.vm.scaleset.name", pdata.NewAttributeValueString("myScalesetName"))
	attrs.Insert(conventions.AttributeHostName, pdata.NewAttributeValueString("myScalesetName_1"))
	id := azureID(attrs, "myCloudAccount")
	expected := "mycloudaccount/myresourcegroup/microsoft.compute/virtualmachinescalesets/myscalesetname/virtualmachines/1"
	assert.Equal(t, expected, id)
}
<|endoftext|>


<commit_before>// Copyright 2016 Hajime Hoshi
//
// 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.

//go:build android || ios
// +build android ios

package mobile

import (
	"fmt"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"unicode"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/gl"

	"github.com/hajimehoshi/ebiten/v2/internal/devicescale"
	"github.com/hajimehoshi/ebiten/v2/internal/driver"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
	"github.com/hajimehoshi/ebiten/v2/internal/hooks"
	"github.com/hajimehoshi/ebiten/v2/internal/restorable"
	"github.com/hajimehoshi/ebiten/v2/internal/thread"
)

var (
	glContextCh = make(chan gl.Context, 1)

	// renderCh receives when updating starts.
	renderCh = make(chan struct{})

	// renderEndCh receives when updating finishes.
	renderEndCh = make(chan struct{})

	theUI = &UserInterface{
		foreground: 1,
		errCh:      make(chan error),

		// Give a default outside size so that the game can start without initializing them.
		outsideWidth:  640,
		outsideHeight: 480,
		sizeChanged:   true,
	}
)

func init() {
	theUI.input.ui = theUI
}

func Get() *UserInterface {
	return theUI
}

// Update is called from mobile/ebitenmobileview.
//
// Update must be called on the rendering thread.
func (u *UserInterface) Update() error {
	select {
	case err := <-u.errCh:
		return err
	default:
	}

	if !u.IsFocused() {
		return nil
	}

	renderCh <- struct{}{}
	go func() {
		<-renderEndCh
		u.t.Call(func() error {
			return thread.BreakLoop
		})
	}()
	u.t.Loop()
	return nil
}

type UserInterface struct {
	outsideWidth  float64
	outsideHeight float64

	sizeChanged bool
	foreground  int32
	errCh       chan error

	// Used for gomobile-build
	gbuildWidthPx   int
	gbuildHeightPx  int
	setGBuildSizeCh chan struct{}
	once            sync.Once

	context driver.UIContext

	input Input

	t *thread.OSThread

	m sync.RWMutex
}

func deviceScale() float64 {
	return devicescale.GetAt(0, 0)
}

// appMain is the main routine for gomobile-build mode.
func (u *UserInterface) appMain(a app.App) {
	var glctx gl.Context
	var sizeInited bool

	touches := map[touch.Sequence]*Touch{}
	keys := map[driver.Key]struct{}{}

	for e := range a.Events() {
		var updateInput bool
		var runes []rune

		switch e := a.Filter(e).(type) {
		case lifecycle.Event:
			switch e.Crosses(lifecycle.StageVisible) {
			case lifecycle.CrossOn:
				if err := u.SetForeground(true); err != nil {
					// There are no other ways than panicking here.
					panic(err)
				}
				restorable.OnContextLost()
				glctx, _ = e.DrawContext.(gl.Context)
				// Assume that glctx is always a same instance.
				// Then, only once initializing should be enough.
				if glContextCh != nil {
					glContextCh <- glctx
					glContextCh = nil
				}
				a.Send(paint.Event{})
			case lifecycle.CrossOff:
				if err := u.SetForeground(false); err != nil {
					// There are no other ways than panicking here.
					panic(err)
				}
				glctx = nil
			}
		case size.Event:
			u.setGBuildSize(e.WidthPx, e.HeightPx)
			sizeInited = true
		case paint.Event:
			if !sizeInited {
				a.Send(paint.Event{})
				continue
			}
			if glctx == nil || e.External {
				continue
			}
			renderCh <- struct{}{}
			<-renderEndCh
			a.Publish()
			a.Send(paint.Event{})
		case touch.Event:
			if !sizeInited {
				continue
			}
			switch e.Type {
			case touch.TypeBegin, touch.TypeMove:
				s := deviceScale()
				x, y := float64(e.X)/s, float64(e.Y)/s
				// TODO: Is it ok to cast from int64 to int here?
				touches[e.Sequence] = &Touch{
					ID: driver.TouchID(e.Sequence),
					X:  int(x),
					Y:  int(y),
				}
			case touch.TypeEnd:
				delete(touches, e.Sequence)
			}
			updateInput = true
		case key.Event:
			k, ok := gbuildKeyToDriverKey[e.Code]
			if ok {
				switch e.Direction {
				case key.DirPress, key.DirNone:
					keys[k] = struct{}{}
				case key.DirRelease:
					delete(keys, k)
				}
			}

			switch e.Direction {
			case key.DirPress, key.DirNone:
				if e.Rune != -1 && unicode.IsPrint(e.Rune) {
					runes = []rune{e.Rune}
				}
			}
			updateInput = true
		}

		if updateInput {
			ts := []*Touch{}
			for _, t := range touches {
				ts = append(ts, t)
			}
			u.input.update(keys, runes, ts, nil)
		}
	}
}

func (u *UserInterface) SetForeground(foreground bool) error {
	var v int32
	if foreground {
		v = 1
	}
	atomic.StoreInt32(&u.foreground, v)

	if foreground {
		return hooks.ResumeAudio()
	} else {
		return hooks.SuspendAudio()
	}
}

func (u *UserInterface) Run(context driver.UIContext) error {
	u.setGBuildSizeCh = make(chan struct{})
	go func() {
		if err := u.run(context, true); err != nil {
			// As mobile apps never ends, Loop can't return. Just panic here.
			panic(err)
		}
	}()
	app.Main(u.appMain)
	return nil
}

func (u *UserInterface) RunWithoutMainLoop(context driver.UIContext) {
	go func() {
		// title is ignored?
		if err := u.run(context, false); err != nil {
			u.errCh <- err
		}
	}()
}

func (u *UserInterface) run(context driver.UIContext, mainloop bool) (err error) {
	// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for
	// Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
	// unfortunately.
	// TODO: Panic on other goroutines cannot be handled here.
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("%v\n%s", r, string(debug.Stack()))
		}
	}()

	u.m.Lock()
	u.sizeChanged = true
	u.m.Unlock()

	u.context = context

	if mainloop {
		// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
		// gl.Context so that they are called on the appropriate thread.
		ctx := <-glContextCh
		u.Graphics().(*opengl.Graphics).SetGomobileGLContext(ctx)
	} else {
		u.t = thread.NewOSThread()
		graphicscommand.SetMainThread(u.t)
	}

	// If gomobile-build is used, wait for the outside size fixed.
	if u.setGBuildSizeCh != nil {
		<-u.setGBuildSizeCh
	}

	// Force to set the screen size
	u.layoutIfNeeded()
	for {
		if err := u.update(); err != nil {
			return err
		}
	}
}

// layoutIfNeeded must be called on the same goroutine as update().
func (u *UserInterface) layoutIfNeeded() {
	var outsideWidth, outsideHeight float64

	u.m.RLock()
	sizeChanged := u.sizeChanged
	if sizeChanged {
		if u.gbuildWidthPx == 0 || u.gbuildHeightPx == 0 {
			outsideWidth = u.outsideWidth
			outsideHeight = u.outsideHeight
		} else {
			// gomobile build
			d := deviceScale()
			outsideWidth = float64(u.gbuildWidthPx) / d
			outsideHeight = float64(u.gbuildHeightPx) / d
		}
	}
	u.sizeChanged = false
	u.m.RUnlock()

	if sizeChanged {
		u.context.Layout(outsideWidth, outsideHeight)
	}
}

func (u *UserInterface) update() error {
	<-renderCh
	defer func() {
		renderEndCh <- struct{}{}
	}()

	if err := u.context.Update(); err != nil {
		return err
	}
	return nil
}

func (u *UserInterface) ScreenSizeInFullscreen() (int, int) {
	// TODO: This function should return gbuildWidthPx, gbuildHeightPx,
	// but these values are not initialized until the main loop starts.
	return 0, 0
}

// SetOutsideSize is called from mobile/ebitenmobileview.
//
// SetOutsideSize is concurrent safe.
func (u *UserInterface) SetOutsideSize(outsideWidth, outsideHeight float64) {
	u.m.Lock()
	if u.outsideWidth != outsideWidth || u.outsideHeight != outsideHeight {
		u.outsideWidth = outsideWidth
		u.outsideHeight = outsideHeight
		u.sizeChanged = true
	}
	u.m.Unlock()
}

func (u *UserInterface) setGBuildSize(widthPx, heightPx int) {
	u.m.Lock()
	u.gbuildWidthPx = widthPx
	u.gbuildHeightPx = heightPx
	u.sizeChanged = true
	u.m.Unlock()

	u.once.Do(func() {
		close(u.setGBuildSizeCh)
	})
}

func (u *UserInterface) adjustPosition(x, y int) (int, int) {
	xf, yf := u.context.AdjustPosition(float64(x), float64(y), deviceScale())
	return int(xf), int(yf)
}

func (u *UserInterface) CursorMode() driver.CursorMode {
	return driver.CursorModeHidden
}

func (u *UserInterface) SetCursorMode(mode driver.CursorMode) {
	// Do nothing
}

func (u *UserInterface) CursorShape() driver.CursorShape {
	return driver.CursorShapeDefault
}

func (u *UserInterface) SetCursorShape(shape driver.CursorShape) {
	// Do nothing
}

func (u *UserInterface) IsFullscreen() bool {
	return false
}

func (u *UserInterface) SetFullscreen(fullscreen bool) {
	// Do nothing
}

func (u *UserInterface) IsFocused() bool {
	return atomic.LoadInt32(&u.foreground) != 0
}

func (u *UserInterface) IsRunnableOnUnfocused() bool {
	return false
}

func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
	// Do nothing
}

func (u *UserInterface) IsVsyncEnabled() bool {
	return true
}

func (u *UserInterface) SetVsyncEnabled(enabled bool) {
	// Do nothing
}

func (u *UserInterface) DeviceScaleFactor() float64 {
	return deviceScale()
}

func (u *UserInterface) SetScreenTransparent(transparent bool) {
	// Do nothing
}

func (u *UserInterface) IsScreenTransparent() bool {
	return false
}

func (u *UserInterface) ResetForFrame() {
	u.layoutIfNeeded()
	u.input.resetForFrame()
}

func (u *UserInterface) SetInitFocused(focused bool) {
	// Do nothing
}

func (u *UserInterface) Input() driver.Input {
	return &u.input
}

func (u *UserInterface) Window() driver.Window {
	return nil
}

type Touch struct {
	ID driver.TouchID
	X  int
	Y  int
}

type Gamepad struct {
	ID        driver.GamepadID
	SDLID     string
	Name      string
	Buttons   [driver.GamepadButtonNum]bool
	ButtonNum int
	Axes      [32]float32
	AxisNum   int
}

func (u *UserInterface) UpdateInput(keys map[driver.Key]struct{}, runes []rune, touches []*Touch, gamepads []Gamepad) {
	u.input.update(keys, runes, touches, gamepads)
}
<commit_msg>internal/uidriver: Remove invalid comments<commit_after>// Copyright 2016 Hajime Hoshi
//
// 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.

//go:build android || ios
// +build android ios

package mobile

import (
	"fmt"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"unicode"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/gl"

	"github.com/hajimehoshi/ebiten/v2/internal/devicescale"
	"github.com/hajimehoshi/ebiten/v2/internal/driver"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
	"github.com/hajimehoshi/ebiten/v2/internal/hooks"
	"github.com/hajimehoshi/ebiten/v2/internal/restorable"
	"github.com/hajimehoshi/ebiten/v2/internal/thread"
)

var (
	glContextCh = make(chan gl.Context, 1)

	// renderCh receives when updating starts.
	renderCh = make(chan struct{})

	// renderEndCh receives when updating finishes.
	renderEndCh = make(chan struct{})

	theUI = &UserInterface{
		foreground: 1,
		errCh:      make(chan error),

		// Give a default outside size so that the game can start without initializing them.
		outsideWidth:  640,
		outsideHeight: 480,
		sizeChanged:   true,
	}
)

func init() {
	theUI.input.ui = theUI
}

func Get() *UserInterface {
	return theUI
}

// Update is called from mobile/ebitenmobileview.
//
// Update must be called on the rendering thread.
func (u *UserInterface) Update() error {
	select {
	case err := <-u.errCh:
		return err
	default:
	}

	if !u.IsFocused() {
		return nil
	}

	renderCh <- struct{}{}
	go func() {
		<-renderEndCh
		u.t.Call(func() error {
			return thread.BreakLoop
		})
	}()
	u.t.Loop()
	return nil
}

type UserInterface struct {
	outsideWidth  float64
	outsideHeight float64

	sizeChanged bool
	foreground  int32
	errCh       chan error

	// Used for gomobile-build
	gbuildWidthPx   int
	gbuildHeightPx  int
	setGBuildSizeCh chan struct{}
	once            sync.Once

	context driver.UIContext

	input Input

	t *thread.OSThread

	m sync.RWMutex
}

func deviceScale() float64 {
	return devicescale.GetAt(0, 0)
}

// appMain is the main routine for gomobile-build mode.
func (u *UserInterface) appMain(a app.App) {
	var glctx gl.Context
	var sizeInited bool

	touches := map[touch.Sequence]*Touch{}
	keys := map[driver.Key]struct{}{}

	for e := range a.Events() {
		var updateInput bool
		var runes []rune

		switch e := a.Filter(e).(type) {
		case lifecycle.Event:
			switch e.Crosses(lifecycle.StageVisible) {
			case lifecycle.CrossOn:
				if err := u.SetForeground(true); err != nil {
					// There are no other ways than panicking here.
					panic(err)
				}
				restorable.OnContextLost()
				glctx, _ = e.DrawContext.(gl.Context)
				// Assume that glctx is always a same instance.
				// Then, only once initializing should be enough.
				if glContextCh != nil {
					glContextCh <- glctx
					glContextCh = nil
				}
				a.Send(paint.Event{})
			case lifecycle.CrossOff:
				if err := u.SetForeground(false); err != nil {
					// There are no other ways than panicking here.
					panic(err)
				}
				glctx = nil
			}
		case size.Event:
			u.setGBuildSize(e.WidthPx, e.HeightPx)
			sizeInited = true
		case paint.Event:
			if !sizeInited {
				a.Send(paint.Event{})
				continue
			}
			if glctx == nil || e.External {
				continue
			}
			renderCh <- struct{}{}
			<-renderEndCh
			a.Publish()
			a.Send(paint.Event{})
		case touch.Event:
			if !sizeInited {
				continue
			}
			switch e.Type {
			case touch.TypeBegin, touch.TypeMove:
				s := deviceScale()
				x, y := float64(e.X)/s, float64(e.Y)/s
				// TODO: Is it ok to cast from int64 to int here?
				touches[e.Sequence] = &Touch{
					ID: driver.TouchID(e.Sequence),
					X:  int(x),
					Y:  int(y),
				}
			case touch.TypeEnd:
				delete(touches, e.Sequence)
			}
			updateInput = true
		case key.Event:
			k, ok := gbuildKeyToDriverKey[e.Code]
			if ok {
				switch e.Direction {
				case key.DirPress, key.DirNone:
					keys[k] = struct{}{}
				case key.DirRelease:
					delete(keys, k)
				}
			}

			switch e.Direction {
			case key.DirPress, key.DirNone:
				if e.Rune != -1 && unicode.IsPrint(e.Rune) {
					runes = []rune{e.Rune}
				}
			}
			updateInput = true
		}

		if updateInput {
			ts := []*Touch{}
			for _, t := range touches {
				ts = append(ts, t)
			}
			u.input.update(keys, runes, ts, nil)
		}
	}
}

func (u *UserInterface) SetForeground(foreground bool) error {
	var v int32
	if foreground {
		v = 1
	}
	atomic.StoreInt32(&u.foreground, v)

	if foreground {
		return hooks.ResumeAudio()
	} else {
		return hooks.SuspendAudio()
	}
}

func (u *UserInterface) Run(context driver.UIContext) error {
	u.setGBuildSizeCh = make(chan struct{})
	go func() {
		if err := u.run(context, true); err != nil {
			// As mobile apps never ends, Loop can't return. Just panic here.
			panic(err)
		}
	}()
	app.Main(u.appMain)
	return nil
}

func (u *UserInterface) RunWithoutMainLoop(context driver.UIContext) {
	go func() {
		if err := u.run(context, false); err != nil {
			u.errCh <- err
		}
	}()
}

func (u *UserInterface) run(context driver.UIContext, mainloop bool) (err error) {
	// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for
	// Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
	// unfortunately.
	// TODO: Panic on other goroutines cannot be handled here.
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("%v\n%s", r, string(debug.Stack()))
		}
	}()

	u.m.Lock()
	u.sizeChanged = true
	u.m.Unlock()

	u.context = context

	if mainloop {
		// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
		// gl.Context so that they are called on the appropriate thread.
		ctx := <-glContextCh
		u.Graphics().(*opengl.Graphics).SetGomobileGLContext(ctx)
	} else {
		u.t = thread.NewOSThread()
		graphicscommand.SetMainThread(u.t)
	}

	// If gomobile-build is used, wait for the outside size fixed.
	if u.setGBuildSizeCh != nil {
		<-u.setGBuildSizeCh
	}

	// Force to set the screen size
	u.layoutIfNeeded()
	for {
		if err := u.update(); err != nil {
			return err
		}
	}
}

// layoutIfNeeded must be called on the same goroutine as update().
func (u *UserInterface) layoutIfNeeded() {
	var outsideWidth, outsideHeight float64

	u.m.RLock()
	sizeChanged := u.sizeChanged
	if sizeChanged {
		if u.gbuildWidthPx == 0 || u.gbuildHeightPx == 0 {
			outsideWidth = u.outsideWidth
			outsideHeight = u.outsideHeight
		} else {
			// gomobile build
			d := deviceScale()
			outsideWidth = float64(u.gbuildWidthPx) / d
			outsideHeight = float64(u.gbuildHeightPx) / d
		}
	}
	u.sizeChanged = false
	u.m.RUnlock()

	if sizeChanged {
		u.context.Layout(outsideWidth, outsideHeight)
	}
}

func (u *UserInterface) update() error {
	<-renderCh
	defer func() {
		renderEndCh <- struct{}{}
	}()

	if err := u.context.Update(); err != nil {
		return err
	}
	return nil
}

func (u *UserInterface) ScreenSizeInFullscreen() (int, int) {
	// TODO: This function should return gbuildWidthPx, gbuildHeightPx,
	// but these values are not initialized until the main loop starts.
	return 0, 0
}

// SetOutsideSize is called from mobile/ebitenmobileview.
//
// SetOutsideSize is concurrent safe.
func (u *UserInterface) SetOutsideSize(outsideWidth, outsideHeight float64) {
	u.m.Lock()
	if u.outsideWidth != outsideWidth || u.outsideHeight != outsideHeight {
		u.outsideWidth = outsideWidth
		u.outsideHeight = outsideHeight
		u.sizeChanged = true
	}
	u.m.Unlock()
}

func (u *UserInterface) setGBuildSize(widthPx, heightPx int) {
	u.m.Lock()
	u.gbuildWidthPx = widthPx
	u.gbuildHeightPx = heightPx
	u.sizeChanged = true
	u.m.Unlock()

	u.once.Do(func() {
		close(u.setGBuildSizeCh)
	})
}

func (u *UserInterface) adjustPosition(x, y int) (int, int) {
	xf, yf := u.context.AdjustPosition(float64(x), float64(y), deviceScale())
	return int(xf), int(yf)
}

func (u *UserInterface) CursorMode() driver.CursorMode {
	return driver.CursorModeHidden
}

func (u *UserInterface) SetCursorMode(mode driver.CursorMode) {
	// Do nothing
}

func (u *UserInterface) CursorShape() driver.CursorShape {
	return driver.CursorShapeDefault
}

func (u *UserInterface) SetCursorShape(shape driver.CursorShape) {
	// Do nothing
}

func (u *UserInterface) IsFullscreen() bool {
	return false
}

func (u *UserInterface) SetFullscreen(fullscreen bool) {
	// Do nothing
}

func (u *UserInterface) IsFocused() bool {
	return atomic.LoadInt32(&u.foreground) != 0
}

func (u *UserInterface) IsRunnableOnUnfocused() bool {
	return false
}

func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
	// Do nothing
}

func (u *UserInterface) IsVsyncEnabled() bool {
	return true
}

func (u *UserInterface) SetVsyncEnabled(enabled bool) {
	// Do nothing
}

func (u *UserInterface) DeviceScaleFactor() float64 {
	return deviceScale()
}

func (u *UserInterface) SetScreenTransparent(transparent bool) {
	// Do nothing
}

func (u *UserInterface) IsScreenTransparent() bool {
	return false
}

func (u *UserInterface) ResetForFrame() {
	u.layoutIfNeeded()
	u.input.resetForFrame()
}

func (u *UserInterface) SetInitFocused(focused bool) {
	// Do nothing
}

func (u *UserInterface) Input() driver.Input {
	return &u.input
}

func (u *UserInterface) Window() driver.Window {
	return nil
}

type Touch struct {
	ID driver.TouchID
	X  int
	Y  int
}

type Gamepad struct {
	ID        driver.GamepadID
	SDLID     string
	Name      string
	Buttons   [driver.GamepadButtonNum]bool
	ButtonNum int
	Axes      [32]float32
	AxisNum   int
}

func (u *UserInterface) UpdateInput(keys map[driver.Key]struct{}, runes []rune, touches []*Touch, gamepads []Gamepad) {
	u.input.update(keys, runes, touches, gamepads)
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| io/encoding/encoder_manager.go                           |
|                                                          |
| LastModified: Mar 20, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"reflect"
	"sync"
)

var structEncoderMap = sync.Map{}
var otherEncoderMap = sync.Map{}

func checkType(v interface{}) reflect.Type {
	t := reflect.TypeOf(v)
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}

func registerEncoder(t reflect.Type, valenc ValueEncoder) {
	if t.Kind() == reflect.Struct {
		structEncoderMap.Store(t, valenc)
	} else {
		otherEncoderMap.Store(t, valenc)
	}
}

func getStructEncoder(t reflect.Type) ValueEncoder {
	if valenc, ok := structEncoderMap.Load(t); ok {
		return valenc.(ValueEncoder)
	}
	return newStructEncoder(t, t.Name(), []string{"json"})
}

func getOtherEncoder(t reflect.Type) ValueEncoder {
	if valenc, ok := otherEncoderMap.Load(t); ok {
		return valenc.(ValueEncoder)
	}
	return nil
}

// RegisterEncoder of type(v)
func RegisterEncoder(v interface{}, valenc ValueEncoder) {
	registerEncoder(checkType(v), valenc)
}

// GetEncoder of type(v)
func GetEncoder(v interface{}) ValueEncoder {
	t := checkType(v)
	if t.Kind() == reflect.Struct {
		return getStructEncoder(t)
	}
	return getOtherEncoder(t)
}
<commit_msg>Update encoder_manager.go<commit_after>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| io/encoding/encoder_manager.go                           |
|                                                          |
| LastModified: Mar 21, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"reflect"
	"sync"
)

var structEncoderMap = sync.Map{}
var otherEncoderMap = sync.Map{}

func checkType(v interface{}) reflect.Type {
	t := reflect.TypeOf(v)
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}

func registerEncoder(t reflect.Type, valenc ValueEncoder) {
	if t.Kind() == reflect.Struct {
		structEncoderMap.Store(t, valenc)
	} else {
		otherEncoderMap.Store(t, valenc)
	}
}

func getStructEncoder(t reflect.Type) ValueEncoder {
	if valenc, ok := structEncoderMap.Load(t); ok {
		return valenc.(ValueEncoder)
	}
	name := t.Name()
	if name == "" {
		return newAnonymousStructEncoder(t)
	}
	return newStructEncoder(t, name, []string{"json"})
}

func getOtherEncoder(t reflect.Type) ValueEncoder {
	if valenc, ok := otherEncoderMap.Load(t); ok {
		return valenc.(ValueEncoder)
	}
	return nil
}

// RegisterEncoder of type(v)
func RegisterEncoder(v interface{}, valenc ValueEncoder) {
	registerEncoder(checkType(v), valenc)
}

// GetEncoder of type(v)
func GetEncoder(v interface{}) ValueEncoder {
	t := checkType(v)
	if t.Kind() == reflect.Struct {
		return getStructEncoder(t)
	}
	return getOtherEncoder(t)
}
<|endoftext|>


<commit_before>// +build linux
// +build cgo

package shared

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

/*
#include "../shared/netns_getifaddrs.c"
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"

func NetnsGetifaddrs(initPID int32) (map[string]api.ContainerStateNetwork, error) {
	var netnsid_aware C.bool
	var ifaddrs *C.struct_netns_ifaddrs
	var netnsID C.__s32

	if initPID > 0 {
		f, err := os.Open(fmt.Sprintf("/proc/%d/ns/net", initPID))
		if err != nil {
			return nil, err
		}
		defer f.Close()

		netnsID = C.netns_get_nsid(C.__s32(f.Fd()))
		if netnsID < 0 {
			return nil, fmt.Errorf("Failed to retrieve network namespace id")
		}
	} else {
		netnsID = -1
	}

	ret := C.netns_getifaddrs(&ifaddrs, netnsID, &netnsid_aware)
	if ret < 0 {
		return nil, fmt.Errorf("Failed to retrieve network interfaces and addresses")
	}
	defer C.netns_freeifaddrs(ifaddrs)

	if netnsID >= 0 && !netnsid_aware {
		return nil, fmt.Errorf("Netlink requests are not fully network namespace id aware")
	}

	// We're using the interface name as key here but we should really
	// switch to the ifindex at some point to handle ip aliasing correctly.
	networks := map[string]api.ContainerStateNetwork{}

	for addr := ifaddrs; addr != nil; addr = addr.ifa_next {
		var address [C.INET6_ADDRSTRLEN]C.char
		addNetwork, networkExists := networks[C.GoString(addr.ifa_name)]
		if !networkExists {
			addNetwork = api.ContainerStateNetwork{
				Addresses: []api.ContainerStateNetworkAddress{},
				Counters:  api.ContainerStateNetworkCounters{},
			}
		}

		if addr.ifa_addr.sa_family == C.AF_INET || addr.ifa_addr.sa_family == C.AF_INET6 {
			netState := "down"
			netType := "unknown"

			if (addr.ifa_flags & C.IFF_BROADCAST) > 0 {
				netType = "broadcast"
			}

			if (addr.ifa_flags & C.IFF_LOOPBACK) > 0 {
				netType = "loopback"
			}

			if (addr.ifa_flags & C.IFF_POINTOPOINT) > 0 {
				netType = "point-to-point"
			}

			if (addr.ifa_flags & C.IFF_UP) > 0 {
				netState = "up"
			}

			family := "inet"
			if addr.ifa_addr.sa_family == C.AF_INET6 {
				family = "inet6"
			}

			addr_ptr := C.get_addr_ptr(addr.ifa_addr)
			if addr_ptr == nil {
				return nil, fmt.Errorf("Failed to retrieve valid address pointer")
			}

			address_str := C.inet_ntop(C.int(addr.ifa_addr.sa_family), addr_ptr, &address[0], C.INET6_ADDRSTRLEN)
			if address_str == nil {
				return nil, fmt.Errorf("Failed to retrieve address string")
			}

			if addNetwork.Addresses == nil {
				addNetwork.Addresses = []api.ContainerStateNetworkAddress{}
			}

			goAddrString := C.GoString(address_str)
			scope := "global"
			if strings.HasPrefix(goAddrString, "127") {
				scope = "local"
			}

			if goAddrString == "::1" {
				scope = "local"
			}

			if strings.HasPrefix(goAddrString, "169.254") {
				scope = "link"
			}

			if strings.HasPrefix(goAddrString, "fe80:") {
				scope = "link"
			}

			address := api.ContainerStateNetworkAddress{}
			address.Family = family
			address.Address = goAddrString
			address.Netmask = fmt.Sprintf("%d", int(addr.ifa_prefixlen))
			address.Scope = scope

			addNetwork.Addresses = append(addNetwork.Addresses, address)
			addNetwork.State = netState
			addNetwork.Type = netType
			addNetwork.Mtu = int(addr.ifa_mtu)
		} else if addr.ifa_addr.sa_family == C.AF_PACKET {

			if (addr.ifa_flags & C.IFF_LOOPBACK) == 0 {
				var buf [1024]C.char

				hwaddr := C.get_packet_address(addr.ifa_addr, &buf[0], 1024)
				if hwaddr == nil {
					return nil, fmt.Errorf("Failed to retrieve hardware address")
				}

				addNetwork.Hwaddr = C.GoString(hwaddr)
			}

			stats := (*C.struct_rtnl_link_stats)(addr.ifa_data)
			if stats != nil {
				addNetwork.Counters.BytesReceived = int64(stats.rx_bytes)
				addNetwork.Counters.BytesSent = int64(stats.tx_bytes)
				addNetwork.Counters.PacketsReceived = int64(stats.rx_packets)
				addNetwork.Counters.PacketsSent = int64(stats.tx_packets)
			}
		}
		ifName := C.GoString(addr.ifa_name)

		networks[ifName] = addNetwork
	}

	return networks, nil
}

func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, exited chan bool, fd int) (chan bool, chan bool) {
	readDone := make(chan bool, 1)
	writeDone := make(chan bool, 1)

	go defaultWriter(conn, w, writeDone)

	go func(conn *websocket.Conn, r io.ReadCloser) {
		in := ExecReaderToChannel(r, -1, exited, fd)
		for {
			buf, ok := <-in
			if !ok {
				r.Close()
				logger.Debugf("sending write barrier")
				conn.WriteMessage(websocket.TextMessage, []byte{})
				readDone <- true
				return
			}
			w, err := conn.NextWriter(websocket.BinaryMessage)
			if err != nil {
				logger.Debugf("Got error getting next writer %s", err)
				break
			}

			_, err = w.Write(buf)
			w.Close()
			if err != nil {
				logger.Debugf("Got err writing %s", err)
				break
			}
		}
		closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
		conn.WriteMessage(websocket.CloseMessage, closeMsg)
		readDone <- true
		r.Close()
	}(conn, r)

	return readDone, writeDone
}
<commit_msg>shared/network: Don't crash on VPN devices<commit_after>// +build linux
// +build cgo

package shared

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

/*
#include "../shared/netns_getifaddrs.c"
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"

func NetnsGetifaddrs(initPID int32) (map[string]api.ContainerStateNetwork, error) {
	var netnsid_aware C.bool
	var ifaddrs *C.struct_netns_ifaddrs
	var netnsID C.__s32

	if initPID > 0 {
		f, err := os.Open(fmt.Sprintf("/proc/%d/ns/net", initPID))
		if err != nil {
			return nil, err
		}
		defer f.Close()

		netnsID = C.netns_get_nsid(C.__s32(f.Fd()))
		if netnsID < 0 {
			return nil, fmt.Errorf("Failed to retrieve network namespace id")
		}
	} else {
		netnsID = -1
	}

	ret := C.netns_getifaddrs(&ifaddrs, netnsID, &netnsid_aware)
	if ret < 0 {
		return nil, fmt.Errorf("Failed to retrieve network interfaces and addresses")
	}
	defer C.netns_freeifaddrs(ifaddrs)

	if netnsID >= 0 && !netnsid_aware {
		return nil, fmt.Errorf("Netlink requests are not fully network namespace id aware")
	}

	// We're using the interface name as key here but we should really
	// switch to the ifindex at some point to handle ip aliasing correctly.
	networks := map[string]api.ContainerStateNetwork{}

	for addr := ifaddrs; addr != nil; addr = addr.ifa_next {
		var address [C.INET6_ADDRSTRLEN]C.char
		addNetwork, networkExists := networks[C.GoString(addr.ifa_name)]
		if !networkExists {
			addNetwork = api.ContainerStateNetwork{
				Addresses: []api.ContainerStateNetworkAddress{},
				Counters:  api.ContainerStateNetworkCounters{},
			}
		}

		if addr.ifa_addr == nil {
			continue
		}

		if addr.ifa_addr.sa_family == C.AF_INET || addr.ifa_addr.sa_family == C.AF_INET6 {
			netState := "down"
			netType := "unknown"

			if (addr.ifa_flags & C.IFF_BROADCAST) > 0 {
				netType = "broadcast"
			}

			if (addr.ifa_flags & C.IFF_LOOPBACK) > 0 {
				netType = "loopback"
			}

			if (addr.ifa_flags & C.IFF_POINTOPOINT) > 0 {
				netType = "point-to-point"
			}

			if (addr.ifa_flags & C.IFF_UP) > 0 {
				netState = "up"
			}

			family := "inet"
			if addr.ifa_addr.sa_family == C.AF_INET6 {
				family = "inet6"
			}

			addr_ptr := C.get_addr_ptr(addr.ifa_addr)
			if addr_ptr == nil {
				return nil, fmt.Errorf("Failed to retrieve valid address pointer")
			}

			address_str := C.inet_ntop(C.int(addr.ifa_addr.sa_family), addr_ptr, &address[0], C.INET6_ADDRSTRLEN)
			if address_str == nil {
				return nil, fmt.Errorf("Failed to retrieve address string")
			}

			if addNetwork.Addresses == nil {
				addNetwork.Addresses = []api.ContainerStateNetworkAddress{}
			}

			goAddrString := C.GoString(address_str)
			scope := "global"
			if strings.HasPrefix(goAddrString, "127") {
				scope = "local"
			}

			if goAddrString == "::1" {
				scope = "local"
			}

			if strings.HasPrefix(goAddrString, "169.254") {
				scope = "link"
			}

			if strings.HasPrefix(goAddrString, "fe80:") {
				scope = "link"
			}

			address := api.ContainerStateNetworkAddress{}
			address.Family = family
			address.Address = goAddrString
			address.Netmask = fmt.Sprintf("%d", int(addr.ifa_prefixlen))
			address.Scope = scope

			addNetwork.Addresses = append(addNetwork.Addresses, address)
			addNetwork.State = netState
			addNetwork.Type = netType
			addNetwork.Mtu = int(addr.ifa_mtu)
		} else if addr.ifa_addr.sa_family == C.AF_PACKET {

			if (addr.ifa_flags & C.IFF_LOOPBACK) == 0 {
				var buf [1024]C.char

				hwaddr := C.get_packet_address(addr.ifa_addr, &buf[0], 1024)
				if hwaddr == nil {
					return nil, fmt.Errorf("Failed to retrieve hardware address")
				}

				addNetwork.Hwaddr = C.GoString(hwaddr)
			}

			stats := (*C.struct_rtnl_link_stats)(addr.ifa_data)
			if stats != nil {
				addNetwork.Counters.BytesReceived = int64(stats.rx_bytes)
				addNetwork.Counters.BytesSent = int64(stats.tx_bytes)
				addNetwork.Counters.PacketsReceived = int64(stats.rx_packets)
				addNetwork.Counters.PacketsSent = int64(stats.tx_packets)
			}
		}
		ifName := C.GoString(addr.ifa_name)

		networks[ifName] = addNetwork
	}

	return networks, nil
}

func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, exited chan bool, fd int) (chan bool, chan bool) {
	readDone := make(chan bool, 1)
	writeDone := make(chan bool, 1)

	go defaultWriter(conn, w, writeDone)

	go func(conn *websocket.Conn, r io.ReadCloser) {
		in := ExecReaderToChannel(r, -1, exited, fd)
		for {
			buf, ok := <-in
			if !ok {
				r.Close()
				logger.Debugf("sending write barrier")
				conn.WriteMessage(websocket.TextMessage, []byte{})
				readDone <- true
				return
			}
			w, err := conn.NextWriter(websocket.BinaryMessage)
			if err != nil {
				logger.Debugf("Got error getting next writer %s", err)
				break
			}

			_, err = w.Write(buf)
			w.Close()
			if err != nil {
				logger.Debugf("Got err writing %s", err)
				break
			}
		}
		closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
		conn.WriteMessage(websocket.CloseMessage, closeMsg)
		readDone <- true
		r.Close()
	}(conn, r)

	return readDone, writeDone
}
<|endoftext|>