<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 netlink

import (
	"errors"
	"fmt"
	"reflect"
	"unsafe"
)

/*
#cgo CFLAGS: -I/usr/include/libnl3
#cgo LDFLAGS: -lnl-3 -lnl-genl-3

#include <stdint.h>

#include <netlink/netlink.h>
#include <netlink/genl/genl.h>

int callbackGateway(struct nl_msg *msg, void *arg);
*/
import "C"

// Netlink message flags.
const (
	MFRequest  = C.NLM_F_REQUEST
	MFMulti    = C.NLM_F_MULTI
	MFACK      = C.NLM_F_ACK
	MFEcho     = C.NLM_F_ECHO
	MFDumpIntr = C.NLM_F_DUMP_INTR
	MFRoot     = C.NLM_F_ROOT
	MFMatch    = C.NLM_F_MATCH
	MFAtomic   = C.NLM_F_ATOMIC
	MFDump     = C.NLM_F_DUMP
	MFReplace  = C.NLM_F_REPLACE
	MFExcl     = C.NLM_F_EXCL
	MFCreate   = C.NLM_F_CREATE
	MFAppend   = C.NLM_F_APPEND
)

// CallbackFunc is a netlink message callback function.
type CallbackFunc func(*Message, interface{}) error

// callbackArg contains information passed for libnl callbacks.
type callbackArg struct {
	fn  CallbackFunc
	arg interface{}
	err error
}

// callback is the Go callback trampoline that is called from the
// callbackGateway C function, which in turn gets called from libnl.
//
//export callback
func callback(nlm *C.struct_nl_msg, nla unsafe.Pointer) C.int {
	cbArg := (*callbackArg)(nla)
	cbMsg := &Message{nlm: nlm}
	if err := cbArg.fn(cbMsg, cbArg.arg); err != nil {
		cbArg.err = err
		return C.NL_STOP
	}
	return C.NL_OK
}

func callbackDefault(msg *Message, arg interface{}) error {
	return nil
}

func callbackUnmarshal(msg *Message, arg interface{}) error {
	return msg.Unmarshal(arg)
}

// Message represents a netlink message.
type Message struct {
	nlm *C.struct_nl_msg
}

// NewMessage returns an initialised netlink message.
func NewMessage(command, family, flags int) (*Message, error) {
	nlm := C.nlmsg_alloc()
	if nlm == nil {
		return nil, errors.New("failed to create netlink message")
	}
	C.genlmsg_put(nlm, C.NL_AUTO_PID, C.NL_AUTO_SEQ, C.int(family), 0, C.int(flags), C.uint8_t(command), genlVersion)
	return &Message{nlm: nlm}, nil
}

// NewMessageFromBytes returns a netlink message that is initialised from the
// given byte slice.
func NewMessageFromBytes(nlb []byte) (*Message, error) {
	nlm := C.nlmsg_alloc_size(C.size_t(len(nlb)))
	if nlm == nil {
		return nil, errors.New("failed to create netlink message")
	}
	nlh := C.nlmsg_hdr(nlm)
	copy((*[1 << 20]byte)(unsafe.Pointer(nlh))[:len(nlb)], nlb)
	return &Message{nlm: nlm}, nil
}

// Free frees resources associated with a netlink message.
func (m *Message) Free() {
	C.nlmsg_free(m.nlm)
	m.nlm = nil
}

// Bytes returns the byte slice representation of a netlink message.
func (m *Message) Bytes() ([]byte, error) {
	if m.nlm == nil {
		return nil, errors.New("no netlink message")
	}
	nlh := C.nlmsg_hdr(m.nlm)
	nlb := make([]byte, nlh.nlmsg_len)
	copy(nlb, (*[1 << 20]byte)(unsafe.Pointer(nlh))[:nlh.nlmsg_len])
	return nlb, nil
}

// Marshal converts the given struct into a netlink message. Each field within
// the struct is added as netlink data, with structs and pointers to structs
// being recursively added as nested data.
//
// Supported data types and their netlink mappings are as follows:
//
//	uint8:		NLA_U8
//	uint16:		NLA_U16
//	uint32:		NLA_U32
//	uint64:		NLA_U64
//	string:		NLA_STRING
//	byte array:	NLA_UNSPEC
//	struct:		NLA_NESTED
//	net.IP:		NLA_UNSPEC
//
// Each field must have a `netlink' tag, which can contain the following
// comma separated options:
//
//	attr:x		specify the netlink attribute for this field (required)
//	network		value will be converted to its network byte order
//	omitempty	if the field has a zero value it will be omitted
//	optional	mark the field as being an optional (for unmarshalling)
//
// Other Go data types are unsupported and an error will be returned if one
// is encountered.
func (m *Message) Marshal(v interface{}) error {
	val := reflect.Indirect(reflect.ValueOf(v))
	if val.Kind() != reflect.Struct {
		return fmt.Errorf("%v is not a struct or a pointer to a struct", reflect.TypeOf(v))
	}
	return marshal(val, "", nil, m.nlm)
}

// Unmarshal parses the netlink message and fills the struct referenced by the
// given pointer. The supported data types and netlink encodings are the same
// as for Marshal.
func (m *Message) Unmarshal(v interface{}) error {
	val := reflect.Indirect(reflect.ValueOf(v))
	if val.Kind() != reflect.Struct || !val.CanSet() {
		return fmt.Errorf("%v is not a pointer to a struct", reflect.TypeOf(v))
	}
	maxAttrID, err := structMaxAttrID(val)
	if err != nil {
		return err
	}
	attrs, err := parseMessage(m.nlm, maxAttrID)
	if err != nil {
		return err
	}
	return unmarshal(val, "", nil, attrs)
}

// Send sends the netlink message.
func (m *Message) Send() error {
	return m.SendCallback(callbackDefault, nil)
}

// SendCallback sends the netlink message. The specified callback function
// will be called for each message that is received in response.
func (m *Message) SendCallback(fn CallbackFunc, arg interface{}) error {
	s, err := newSocket()
	if err != nil {
		return err
	}
	defer s.free()

	if errno := C.genl_connect(s.nls); errno != 0 {
		return &Error{errno, "failed to connect to netlink"}
	}
	defer C.nl_close(s.nls)

	cbArg := &callbackArg{fn: fn, arg: arg}
	if errno := C.nl_socket_modify_cb(s.nls, C.NL_CB_VALID, C.NL_CB_CUSTOM, (C.nl_recvmsg_msg_cb_t)(unsafe.Pointer(C.callbackGateway)), unsafe.Pointer(cbArg)); errno != 0 {
		return &Error{errno, "failed to modify callback"}
	}
	// nl_send_auto_complete returns number of bytes sent or a negative
	// errno on failure.
	if errno := C.nl_send_auto_complete(s.nls, m.nlm); errno < 0 {
		return &Error{errno, "failed to send netlink message"}
	}
	if errno := C.nl_recvmsgs_default(s.nls); errno != 0 {
		return &Error{errno, "failed to receive messages"}
	}
	return nil
}

// SendMessage creates and sends a netlink message.
func SendMessage(command, family, flags int) error {
	return SendMessageCallback(command, family, flags, callbackDefault, nil)
}

// SendMessageCallback creates and sends a netlink message. The specified
// callback function will be called for each message that is received in
// response.
func SendMessageCallback(command, family, flags int, cb CallbackFunc, arg interface{}) error {
	msg, err := NewMessage(command, family, flags)
	if err != nil {
		return err
	}
	defer msg.Free()

	return msg.SendCallback(cb, arg)
}

// SendMessageMarshalled creates a netlink message and marshals the given
// struct into the message, before sending it.
func SendMessageMarshalled(command, family, flags int, v interface{}) error {
	msg, err := NewMessage(command, family, flags)
	if err != nil {
		return err
	}
	defer msg.Free()

	if err := msg.Marshal(v); err != nil {
		return err
	}
	return msg.Send()
}

// SendMessageUnmarshal creates and sends a netlink message. All messages
// received in response will be unmarshalled into the given struct.
func SendMessageUnmarshal(command, family, flags int, v interface{}) error {
	return SendMessageCallback(command, family, flags, callbackUnmarshal, v)
}
<commit_msg>netlink: stop passing Go pointers to cgo callbacks.<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 netlink

import (
	"errors"
	"fmt"
	"reflect"
	"sync"
	"unsafe"
)

/*
#cgo CFLAGS: -I/usr/include/libnl3
#cgo LDFLAGS: -lnl-3 -lnl-genl-3

#include <stdint.h>

#include <netlink/netlink.h>
#include <netlink/genl/genl.h>

int callbackGateway(struct nl_msg *msg, void *arg);
*/
import "C"

// Netlink message flags.
const (
	MFRequest  = C.NLM_F_REQUEST
	MFMulti    = C.NLM_F_MULTI
	MFACK      = C.NLM_F_ACK
	MFEcho     = C.NLM_F_ECHO
	MFDumpIntr = C.NLM_F_DUMP_INTR
	MFRoot     = C.NLM_F_ROOT
	MFMatch    = C.NLM_F_MATCH
	MFAtomic   = C.NLM_F_ATOMIC
	MFDump     = C.NLM_F_DUMP
	MFReplace  = C.NLM_F_REPLACE
	MFExcl     = C.NLM_F_EXCL
	MFCreate   = C.NLM_F_CREATE
	MFAppend   = C.NLM_F_APPEND
)

// CallbackFunc is a netlink message callback function.
type CallbackFunc func(*Message, interface{}) error

// callbackArg contains information passed for libnl callbacks.
type callbackArg struct {
	id  uintptr
	fn  CallbackFunc
	arg interface{}
	err error
}

var (
	nextCallbackID uintptr
	callbacks      = make(map[uintptr]*callbackArg)
	callbacksLock  sync.RWMutex
)

// registerCallback registers a callback and returns the allocated callback ID.
func registerCallback(cbArg *callbackArg) uintptr {
	callbacksLock.Lock()
	defer callbacksLock.Unlock()
	cbArg.id = nextCallbackID
	nextCallbackID++
	if _, ok := callbacks[cbArg.id]; ok {
		panic(fmt.Sprintf("Callback ID %d already in use", cbArg.id))
	}
	callbacks[cbArg.id] = cbArg
	return cbArg.id
}

// unregisterCallback unregisters a callback.
func unregisterCallback(cbArg *callbackArg) {
	callbacksLock.Lock()
	defer callbacksLock.Unlock()
	if _, ok := callbacks[cbArg.id]; !ok {
		panic(fmt.Sprintf("Callback ID %d not registered", cbArg.id))
	}
	delete(callbacks, cbArg.id)
}

// callback is the Go callback trampoline that is called from the
// callbackGateway C function, which in turn gets called from libnl.
//
//export callback
func callback(nlm *C.struct_nl_msg, nla unsafe.Pointer) C.int {
	cbID := uintptr(nla)
	callbacksLock.RLock()
	cbArg := callbacks[cbID]
	callbacksLock.RUnlock()

	if cbArg == nil {
		panic(fmt.Sprintf("No netlink callback with ID %d", cbID))
	}

	cbMsg := &Message{nlm: nlm}
	if err := cbArg.fn(cbMsg, cbArg.arg); err != nil {
		cbArg.err = err
		return C.NL_STOP
	}
	return C.NL_OK
}

func callbackDefault(msg *Message, arg interface{}) error {
	return nil
}

func callbackUnmarshal(msg *Message, arg interface{}) error {
	return msg.Unmarshal(arg)
}

// Message represents a netlink message.
type Message struct {
	nlm *C.struct_nl_msg
}

// NewMessage returns an initialised netlink message.
func NewMessage(command, family, flags int) (*Message, error) {
	nlm := C.nlmsg_alloc()
	if nlm == nil {
		return nil, errors.New("failed to create netlink message")
	}
	C.genlmsg_put(nlm, C.NL_AUTO_PID, C.NL_AUTO_SEQ, C.int(family), 0, C.int(flags), C.uint8_t(command), genlVersion)
	return &Message{nlm: nlm}, nil
}

// NewMessageFromBytes returns a netlink message that is initialised from the
// given byte slice.
func NewMessageFromBytes(nlb []byte) (*Message, error) {
	nlm := C.nlmsg_alloc_size(C.size_t(len(nlb)))
	if nlm == nil {
		return nil, errors.New("failed to create netlink message")
	}
	nlh := C.nlmsg_hdr(nlm)
	copy((*[1 << 20]byte)(unsafe.Pointer(nlh))[:len(nlb)], nlb)
	return &Message{nlm: nlm}, nil
}

// Free frees resources associated with a netlink message.
func (m *Message) Free() {
	C.nlmsg_free(m.nlm)
	m.nlm = nil
}

// Bytes returns the byte slice representation of a netlink message.
func (m *Message) Bytes() ([]byte, error) {
	if m.nlm == nil {
		return nil, errors.New("no netlink message")
	}
	nlh := C.nlmsg_hdr(m.nlm)
	nlb := make([]byte, nlh.nlmsg_len)
	copy(nlb, (*[1 << 20]byte)(unsafe.Pointer(nlh))[:nlh.nlmsg_len])
	return nlb, nil
}

// Marshal converts the given struct into a netlink message. Each field within
// the struct is added as netlink data, with structs and pointers to structs
// being recursively added as nested data.
//
// Supported data types and their netlink mappings are as follows:
//
//	uint8:		NLA_U8
//	uint16:		NLA_U16
//	uint32:		NLA_U32
//	uint64:		NLA_U64
//	string:		NLA_STRING
//	byte array:	NLA_UNSPEC
//	struct:		NLA_NESTED
//	net.IP:		NLA_UNSPEC
//
// Each field must have a `netlink' tag, which can contain the following
// comma separated options:
//
//	attr:x		specify the netlink attribute for this field (required)
//	network		value will be converted to its network byte order
//	omitempty	if the field has a zero value it will be omitted
//	optional	mark the field as being an optional (for unmarshalling)
//
// Other Go data types are unsupported and an error will be returned if one
// is encountered.
func (m *Message) Marshal(v interface{}) error {
	val := reflect.Indirect(reflect.ValueOf(v))
	if val.Kind() != reflect.Struct {
		return fmt.Errorf("%v is not a struct or a pointer to a struct", reflect.TypeOf(v))
	}
	return marshal(val, "", nil, m.nlm)
}

// Unmarshal parses the netlink message and fills the struct referenced by the
// given pointer. The supported data types and netlink encodings are the same
// as for Marshal.
func (m *Message) Unmarshal(v interface{}) error {
	val := reflect.Indirect(reflect.ValueOf(v))
	if val.Kind() != reflect.Struct || !val.CanSet() {
		return fmt.Errorf("%v is not a pointer to a struct", reflect.TypeOf(v))
	}
	maxAttrID, err := structMaxAttrID(val)
	if err != nil {
		return err
	}
	attrs, err := parseMessage(m.nlm, maxAttrID)
	if err != nil {
		return err
	}
	return unmarshal(val, "", nil, attrs)
}

// Send sends the netlink message.
func (m *Message) Send() error {
	return m.SendCallback(callbackDefault, nil)
}

// SendCallback sends the netlink message. The specified callback function
// will be called for each message that is received in response.
func (m *Message) SendCallback(fn CallbackFunc, arg interface{}) error {
	s, err := newSocket()
	if err != nil {
		return err
	}
	defer s.free()

	if errno := C.genl_connect(s.nls); errno != 0 {
		return &Error{errno, "failed to connect to netlink"}
	}
	defer C.nl_close(s.nls)

	cbArg := &callbackArg{fn: fn, arg: arg}
	cbID := registerCallback(cbArg)
	defer unregisterCallback(cbArg)

	if errno := C.nl_socket_modify_cb(s.nls, C.NL_CB_VALID, C.NL_CB_CUSTOM, (C.nl_recvmsg_msg_cb_t)(unsafe.Pointer(C.callbackGateway)), unsafe.Pointer(cbID)); errno != 0 {
		return &Error{errno, "failed to modify callback"}
	}
	// nl_send_auto_complete returns number of bytes sent or a negative
	// errno on failure.
	if errno := C.nl_send_auto_complete(s.nls, m.nlm); errno < 0 {
		return &Error{errno, "failed to send netlink message"}
	}
	if errno := C.nl_recvmsgs_default(s.nls); errno != 0 {
		return &Error{errno, "failed to receive messages"}
	}
	return nil
}

// SendMessage creates and sends a netlink message.
func SendMessage(command, family, flags int) error {
	return SendMessageCallback(command, family, flags, callbackDefault, nil)
}

// SendMessageCallback creates and sends a netlink message. The specified
// callback function will be called for each message that is received in
// response.
func SendMessageCallback(command, family, flags int, cb CallbackFunc, arg interface{}) error {
	msg, err := NewMessage(command, family, flags)
	if err != nil {
		return err
	}
	defer msg.Free()

	return msg.SendCallback(cb, arg)
}

// SendMessageMarshalled creates a netlink message and marshals the given
// struct into the message, before sending it.
func SendMessageMarshalled(command, family, flags int, v interface{}) error {
	msg, err := NewMessage(command, family, flags)
	if err != nil {
		return err
	}
	defer msg.Free()

	if err := msg.Marshal(v); err != nil {
		return err
	}
	return msg.Send()
}

// SendMessageUnmarshal creates and sends a netlink message. All messages
// received in response will be unmarshalled into the given struct.
func SendMessageUnmarshal(command, family, flags int, v interface{}) error {
	return SendMessageCallback(command, family, flags, callbackUnmarshal, v)
}
<|endoftext|>


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

// Package nettest provides utilities for network testing.
package nettest

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	stackOnce     sync.Once
	ipv4Enabled   bool
	ipv6Enabled   bool
	rawSocketSess bool
	aixTechLvl    int

	aLongTimeAgo = time.Unix(233431200, 0)
	neverTimeout = time.Time{}

	errNoAvailableInterface = errors.New("no available interface")
	errNoAvailableAddress   = errors.New("no available address")
)

func probeStack() {
	if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
		ln.Close()
		ipv4Enabled = true
	}
	if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
		ln.Close()
		ipv6Enabled = true
	}
	rawSocketSess = supportsRawSocket()
	if runtime.GOOS == "aix" {
		out, err := exec.Command("oslevel", "-s").Output()
		if err == nil {
			aixTechLvl, _ = strconv.Atoi(string(out[5:7]))
		}
	}
}

func aixTechLevel() int {
	stackOnce.Do(probeStack)
	return aixTechLvl
}

// SupportsIPv4 reports whether the platform supports IPv4 networking
// functionality.
func SupportsIPv4() bool {
	stackOnce.Do(probeStack)
	return ipv4Enabled
}

// SupportsIPv6 reports whether the platform supports IPv6 networking
// functionality.
func SupportsIPv6() bool {
	stackOnce.Do(probeStack)
	return ipv6Enabled
}

// SupportsRawSocket reports whether the current session is available
// to use raw sockets.
func SupportsRawSocket() bool {
	stackOnce.Do(probeStack)
	return rawSocketSess
}

// TestableNetwork reports whether network is testable on the current
// platform configuration.
//
// See func Dial of the standard library for the supported networks.
func TestableNetwork(network string) bool {
	ss := strings.Split(network, ":")
	switch ss[0] {
	case "ip+nopriv":
		// This is an internal network name for testing on the
		// package net of the standard library.
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
			return false
		case "darwin":
			// iOS doesn't support it.
			if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
				return false
			}
		}
	case "ip", "ip4", "ip6":
		switch runtime.GOOS {
		case "fuchsia", "hurd", "js", "nacl", "plan9":
			return false
		default:
			if os.Getuid() != 0 {
				return false
			}
		}
	case "unix", "unixgram":
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
			return false
		case "aix":
			// Unix network isn't properly working on AIX
			// 7.2 with Technical Level < 2.
			if aixTechLevel() < 2 {
				return false
			}
			return true
		case "darwin":
			// iOS does not support unix, unixgram.
			if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
				return false
			}
		}
	case "unixpacket":
		switch runtime.GOOS {
		case "aix", "android", "fuchsia", "hurd", "darwin", "js", "nacl", "plan9", "windows":
			return false
		case "netbsd":
			// It passes on amd64 at least. 386 fails
			// (Issue 22927). arm is unknown.
			if runtime.GOARCH == "386" {
				return false
			}
		}
	}
	switch ss[0] {
	case "tcp4", "udp4", "ip4":
		return SupportsIPv4()
	case "tcp6", "udp6", "ip6":
		return SupportsIPv6()
	}
	return true
}

// TestableAddress reports whether address of network is testable on
// the current platform configuration.
func TestableAddress(network, address string) bool {
	switch ss := strings.Split(network, ":"); ss[0] {
	case "unix", "unixgram", "unixpacket":
		// Abstract unix domain sockets, a Linux-ism.
		if address[0] == '@' && runtime.GOOS != "linux" {
			return false
		}
	}
	return true
}

// NewLocalListener returns a listener which listens to a loopback IP
// address or local file system path.
//
// The provided network must be "tcp", "tcp4", "tcp6", "unix" or
// "unixpacket".
func NewLocalListener(network string) (net.Listener, error) {
	switch network {
	case "tcp":
		if SupportsIPv4() {
			if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
				return ln, nil
			}
		}
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "tcp4":
		if SupportsIPv4() {
			return net.Listen("tcp4", "127.0.0.1:0")
		}
	case "tcp6":
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "unix", "unixpacket":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.Listen(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// NewLocalPacketListener returns a packet listener which listens to a
// loopback IP address or local file system path.
//
// The provided network must be "udp", "udp4", "udp6" or "unixgram".
func NewLocalPacketListener(network string) (net.PacketConn, error) {
	switch network {
	case "udp":
		if SupportsIPv4() {
			if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
				return c, nil
			}
		}
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "udp4":
		if SupportsIPv4() {
			return net.ListenPacket("udp4", "127.0.0.1:0")
		}
	case "udp6":
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "unixgram":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.ListenPacket(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// LocalPath returns a local path that can be used for Unix-domain
// protocol testing.
func LocalPath() (string, error) {
	f, err := ioutil.TempFile("", "go-nettest")
	if err != nil {
		return "", err
	}
	path := f.Name()
	f.Close()
	os.Remove(path)
	return path, nil
}

// MulticastSource returns a unicast IP address on ifi when ifi is an
// IP multicast-capable network interface.
//
// The provided network must be "ip", "ip4" or "ip6".
func MulticastSource(network string, ifi *net.Interface) (net.IP, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableAddress
	}
	if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
		return nil, errNoAvailableAddress
	}
	ip, ok := hasRoutableIP(network, ifi)
	if !ok {
		return nil, errNoAvailableAddress
	}
	return ip, nil
}

// LoopbackInterface returns an available logical network interface
// for loopback test.
func LoopbackInterface() (*net.Interface, error) {
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
			return &ifi, nil
		}
	}
	return nil, errNoAvailableInterface
}

// RoutedInterface returns a network interface that can route IP
// traffic and satisfies flags.
//
// The provided network must be "ip", "ip4" or "ip6".
func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableInterface
	}
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&flags != flags {
			continue
		}
		if _, ok := hasRoutableIP(network, &ifi); !ok {
			continue
		}
		return &ifi, nil
	}
	return nil, errNoAvailableInterface
}

func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
	ifat, err := ifi.Addrs()
	if err != nil {
		return nil, false
	}
	for _, ifa := range ifat {
		switch ifa := ifa.(type) {
		case *net.IPAddr:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		case *net.IPNet:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		}
	}
	return nil, false
}

func routableIP(network string, ip net.IP) (net.IP, bool) {
	if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
		return nil, false
	}
	switch network {
	case "ip4":
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
	case "ip6":
		if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
			return nil, false
		}
		if ip := ip.To16(); ip != nil && ip.To4() == nil {
			return ip, true
		}
	default:
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
		if ip := ip.To16(); ip != nil {
			return ip, true
		}
	}
	return nil, false
}
<commit_msg>nettest: use unixStrmDgramEnabled on AIX<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package nettest provides utilities for network testing.
package nettest

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	stackOnce          sync.Once
	ipv4Enabled        bool
	ipv6Enabled        bool
	unStrmDgramEnabled bool
	rawSocketSess      bool

	aLongTimeAgo = time.Unix(233431200, 0)
	neverTimeout = time.Time{}

	errNoAvailableInterface = errors.New("no available interface")
	errNoAvailableAddress   = errors.New("no available address")
)

func probeStack() {
	if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
		ln.Close()
		ipv4Enabled = true
	}
	if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
		ln.Close()
		ipv6Enabled = true
	}
	rawSocketSess = supportsRawSocket()
	switch runtime.GOOS {
	case "aix":
		// Unix network isn't properly working on AIX 7.2 with
		// Technical Level < 2.
		out, _ := exec.Command("oslevel", "-s").Output()
		if len(out) >= len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM
			ver := string(out[:4])
			tl, _ := strconv.Atoi(string(out[5:7]))
			unStrmDgramEnabled = ver > "7200" || (ver == "7200" && tl >= 2)
		}
	default:
		unStrmDgramEnabled = true
	}
}

func unixStrmDgramEnabled() bool {
	stackOnce.Do(probeStack)
	return unStrmDgramEnabled
}

// SupportsIPv4 reports whether the platform supports IPv4 networking
// functionality.
func SupportsIPv4() bool {
	stackOnce.Do(probeStack)
	return ipv4Enabled
}

// SupportsIPv6 reports whether the platform supports IPv6 networking
// functionality.
func SupportsIPv6() bool {
	stackOnce.Do(probeStack)
	return ipv6Enabled
}

// SupportsRawSocket reports whether the current session is available
// to use raw sockets.
func SupportsRawSocket() bool {
	stackOnce.Do(probeStack)
	return rawSocketSess
}

// TestableNetwork reports whether network is testable on the current
// platform configuration.
//
// See func Dial of the standard library for the supported networks.
func TestableNetwork(network string) bool {
	ss := strings.Split(network, ":")
	switch ss[0] {
	case "ip+nopriv":
		// This is an internal network name for testing on the
		// package net of the standard library.
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
			return false
		case "darwin":
			// iOS doesn't support it.
			if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
				return false
			}
		}
	case "ip", "ip4", "ip6":
		switch runtime.GOOS {
		case "fuchsia", "hurd", "js", "nacl", "plan9":
			return false
		default:
			if os.Getuid() != 0 {
				return false
			}
		}
	case "unix", "unixgram":
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
			return false
		case "aix":
			return unixStrmDgramEnabled()
		case "darwin":
			// iOS does not support unix, unixgram.
			if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
				return false
			}
		}
	case "unixpacket":
		switch runtime.GOOS {
		case "aix", "android", "fuchsia", "hurd", "darwin", "js", "nacl", "plan9", "windows":
			return false
		case "netbsd":
			// It passes on amd64 at least. 386 fails
			// (Issue 22927). arm is unknown.
			if runtime.GOARCH == "386" {
				return false
			}
		}
	}
	switch ss[0] {
	case "tcp4", "udp4", "ip4":
		return SupportsIPv4()
	case "tcp6", "udp6", "ip6":
		return SupportsIPv6()
	}
	return true
}

// TestableAddress reports whether address of network is testable on
// the current platform configuration.
func TestableAddress(network, address string) bool {
	switch ss := strings.Split(network, ":"); ss[0] {
	case "unix", "unixgram", "unixpacket":
		// Abstract unix domain sockets, a Linux-ism.
		if address[0] == '@' && runtime.GOOS != "linux" {
			return false
		}
	}
	return true
}

// NewLocalListener returns a listener which listens to a loopback IP
// address or local file system path.
//
// The provided network must be "tcp", "tcp4", "tcp6", "unix" or
// "unixpacket".
func NewLocalListener(network string) (net.Listener, error) {
	switch network {
	case "tcp":
		if SupportsIPv4() {
			if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
				return ln, nil
			}
		}
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "tcp4":
		if SupportsIPv4() {
			return net.Listen("tcp4", "127.0.0.1:0")
		}
	case "tcp6":
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "unix", "unixpacket":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.Listen(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// NewLocalPacketListener returns a packet listener which listens to a
// loopback IP address or local file system path.
//
// The provided network must be "udp", "udp4", "udp6" or "unixgram".
func NewLocalPacketListener(network string) (net.PacketConn, error) {
	switch network {
	case "udp":
		if SupportsIPv4() {
			if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
				return c, nil
			}
		}
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "udp4":
		if SupportsIPv4() {
			return net.ListenPacket("udp4", "127.0.0.1:0")
		}
	case "udp6":
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "unixgram":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.ListenPacket(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// LocalPath returns a local path that can be used for Unix-domain
// protocol testing.
func LocalPath() (string, error) {
	f, err := ioutil.TempFile("", "go-nettest")
	if err != nil {
		return "", err
	}
	path := f.Name()
	f.Close()
	os.Remove(path)
	return path, nil
}

// MulticastSource returns a unicast IP address on ifi when ifi is an
// IP multicast-capable network interface.
//
// The provided network must be "ip", "ip4" or "ip6".
func MulticastSource(network string, ifi *net.Interface) (net.IP, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableAddress
	}
	if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
		return nil, errNoAvailableAddress
	}
	ip, ok := hasRoutableIP(network, ifi)
	if !ok {
		return nil, errNoAvailableAddress
	}
	return ip, nil
}

// LoopbackInterface returns an available logical network interface
// for loopback test.
func LoopbackInterface() (*net.Interface, error) {
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
			return &ifi, nil
		}
	}
	return nil, errNoAvailableInterface
}

// RoutedInterface returns a network interface that can route IP
// traffic and satisfies flags.
//
// The provided network must be "ip", "ip4" or "ip6".
func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableInterface
	}
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&flags != flags {
			continue
		}
		if _, ok := hasRoutableIP(network, &ifi); !ok {
			continue
		}
		return &ifi, nil
	}
	return nil, errNoAvailableInterface
}

func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
	ifat, err := ifi.Addrs()
	if err != nil {
		return nil, false
	}
	for _, ifa := range ifat {
		switch ifa := ifa.(type) {
		case *net.IPAddr:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		case *net.IPNet:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		}
	}
	return nil, false
}

func routableIP(network string, ip net.IP) (net.IP, bool) {
	if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
		return nil, false
	}
	switch network {
	case "ip4":
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
	case "ip6":
		if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
			return nil, false
		}
		if ip := ip.To16(); ip != nil && ip.To4() == nil {
			return ip, true
		}
	default:
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
		if ip := ip.To16(); ip != nil {
			return ip, true
		}
	}
	return nil, false
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package network

import (
	"strconv"

	"github.com/juju/utils/set"
)

// PortSet is a set-like container of Port values.
type PortSet struct {
	values map[string]set.Strings
}

// NewPortSet creates a map of protocols to sets of stringified port numbers.
func NewPortSet(portRanges ...PortRange) PortSet {
	var portMap PortSet
	portMap.values = make(map[string]set.Strings)
	portMap.AddRanges(portRanges...)
	return portMap
}

// Size returns the number of ports in the set.
func (ps PortSet) Size() int {
	return len(ps.Ports())
}

// IsEmpty returns true if the PortSet is empty.
func (ps PortSet) IsEmpty() bool {
	return len(ps.values) == 0
}

// Values returns a list of all the ports in the set.
func (ps PortSet) Values() []Port {
	return ps.Ports()
}

// Protocols returns a list of protocols known to the PortSet.
func (ps PortSet) Protocols() []string {
	var result []string
	for key := range ps.values {
		result = append(result, key)
	}
	return result
}

// Ports returns a list of all the ports in the set for the
// given protocols. If no protocols are provided all known
// protocols in the set are used.
func (ps PortSet) Ports(protocols ...string) []Port {
	if len(protocols) == 0 {
		protocols = ps.Protocols()
	}

	var result []Port
	for _, protocol := range protocols {
		ports, ok := ps.values[protocol]
		if !ok {
			return nil
		}
		for _, port := range ports.Values() {
			portNum, _ := strconv.Atoi(port)
			result = append(result, Port{protocol, portNum})

		}
	}
	return result
}

// PortStrings returns a list of stringified ports in the set
// for the given protocol.
func (ps PortSet) PortStrings(protocol string) []string {
	ports, ok := ps.values[protocol]
	if !ok {
		return nil
	}
	return ports.Values()
}

// Add adds a Port to the PortSet.
func (ps *PortSet) Add(port Port) {
	if ps.values == nil {
		panic("uninitalised set")
	}
	portNum := strconv.Itoa(port.Number)
	ports, ok := ps.values[port.Protocol]
	if !ok {
		ps.values[port.Protocol] = set.NewStrings(portNum)
	} else {
		ports.Add(portNum)
	}
}

// AddRanges adds port ranges to the PortSet.
func (ps *PortSet) AddRanges(portRanges ...PortRange) {
	for _, port := range PortRangesToPorts(portRanges) {
		ps.Add(port)
	}
}

// Remove removes the given Port from the set.
func (ps *PortSet) Remove(port Port) {
	ports, ok := ps.values[port.Protocol]
	if ok {
		portNum := strconv.Itoa(port.Number)
		ports.Remove(portNum)
	}
}

// Contains returns true if the provided port is in the set.
func (ps *PortSet) Contains(port Port) bool {
	ports, ok := ps.values[port.Protocol]
	if !ok {
		return false
	}
	portNum := strconv.Itoa(port.Number)
	return ports.Contains(portNum)
}

// Union returns a new PortSet of the shared values
// that are common between both PortSets.
func (ps PortSet) Union(other PortSet) PortSet {
	result := NewPortSet()
	for protocol, value := range ps.values {
		result.values[protocol] = value.Union(nil)
	}
	for protocol, value := range other.values {
		ports, ok := result.values[protocol]
		if !ok {
			value = nil
		}
		result.values[protocol] = ports.Union(value)
	}
	return result
}

// Intersection returns a new PortSet of the values that are in both
// this set and the other, but not in just one of either.
func (ps PortSet) Intersection(other PortSet) PortSet {
	result := NewPortSet()
	for protocol, value := range ps.values {
		ports, ok := other.values[protocol]
		if ok {
			result.values[protocol] = value.Intersection(ports)
		}
	}
	return result
}

// Difference returns a new PortSet of the values
// that are not in the other PortSet.
func (ps PortSet) Difference(other PortSet) PortSet {
	result := NewPortSet()
	for protocol, value := range ps.values {
		ports, ok := other.values[protocol]
		if !ok {
			result.values[protocol] = value
		} else {
			result.values[protocol] = value.Difference(ports)
		}
	}
	return result
}
<commit_msg>portMap -> result.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package network

import (
	"strconv"

	"github.com/juju/utils/set"
)

// PortSet is a set-like container of Port values.
type PortSet struct {
	values map[string]set.Strings
}

// NewPortSet creates a map of protocols to sets of stringified port numbers.
func NewPortSet(portRanges ...PortRange) PortSet {
	var result PortSet
	result.values = make(map[string]set.Strings)
	result.AddRanges(portRanges...)
	return result
}

// Size returns the number of ports in the set.
func (ps PortSet) Size() int {
	return len(ps.Ports())
}

// IsEmpty returns true if the PortSet is empty.
func (ps PortSet) IsEmpty() bool {
	return len(ps.values) == 0
}

// Values returns a list of all the ports in the set.
func (ps PortSet) Values() []Port {
	return ps.Ports()
}

// Protocols returns a list of protocols known to the PortSet.
func (ps PortSet) Protocols() []string {
	var result []string
	for key := range ps.values {
		result = append(result, key)
	}
	return result
}

// Ports returns a list of all the ports in the set for the
// given protocols. If no protocols are provided all known
// protocols in the set are used.
func (ps PortSet) Ports(protocols ...string) []Port {
	if len(protocols) == 0 {
		protocols = ps.Protocols()
	}

	var result []Port
	for _, protocol := range protocols {
		ports, ok := ps.values[protocol]
		if !ok {
			return nil
		}
		for _, port := range ports.Values() {
			portNum, _ := strconv.Atoi(port)
			result = append(result, Port{protocol, portNum})

		}
	}
	return result
}

// PortStrings returns a list of stringified ports in the set
// for the given protocol.
func (ps PortSet) PortStrings(protocol string) []string {
	ports, ok := ps.values[protocol]
	if !ok {
		return nil
	}
	return ports.Values()
}

// Add adds a Port to the PortSet.
func (ps *PortSet) Add(port Port) {
	if ps.values == nil {
		panic("uninitalised set")
	}
	portNum := strconv.Itoa(port.Number)
	ports, ok := ps.values[port.Protocol]
	if !ok {
		ps.values[port.Protocol] = set.NewStrings(portNum)
	} else {
		ports.Add(portNum)
	}
}

// AddRanges adds port ranges to the PortSet.
func (ps *PortSet) AddRanges(portRanges ...PortRange) {
	for _, port := range PortRangesToPorts(portRanges) {
		ps.Add(port)
	}
}

// Remove removes the given Port from the set.
func (ps *PortSet) Remove(port Port) {
	ports, ok := ps.values[port.Protocol]
	if ok {
		portNum := strconv.Itoa(port.Number)
		ports.Remove(portNum)
	}
}

// Contains returns true if the provided port is in the set.
func (ps *PortSet) Contains(port Port) bool {
	ports, ok := ps.values[port.Protocol]
	if !ok {
		return false
	}
	portNum := strconv.Itoa(port.Number)
	return ports.Contains(portNum)
}

// Union returns a new PortSet of the shared values
// that are common between both PortSets.
func (ps PortSet) Union(other PortSet) PortSet {
	result := NewPortSet()
	for protocol, value := range ps.values {
		result.values[protocol] = value.Union(nil)
	}
	for protocol, value := range other.values {
		ports, ok := result.values[protocol]
		if !ok {
			value = nil
		}
		result.values[protocol] = ports.Union(value)
	}
	return result
}

// Intersection returns a new PortSet of the values that are in both
// this set and the other, but not in just one of either.
func (ps PortSet) Intersection(other PortSet) PortSet {
	result := NewPortSet()
	for protocol, value := range ps.values {
		ports, ok := other.values[protocol]
		if ok {
			result.values[protocol] = value.Intersection(ports)
		}
	}
	return result
}

// Difference returns a new PortSet of the values
// that are not in the other PortSet.
func (ps PortSet) Difference(other PortSet) PortSet {
	result := NewPortSet()
	for protocol, value := range ps.values {
		ports, ok := other.values[protocol]
		if !ok {
			result.values[protocol] = value
		} else {
			result.values[protocol] = value.Difference(ports)
		}
	}
	return result
}
<|endoftext|>


<commit_before>/*
    Command line utility for concatenating MP3 files without re-encoding.

    Supports both constant bit rate (CBR) and variable bit rate (VBR) files.
    Strips ID3 tags and garbage data from the output.

      * Author: Darren Mulholland <dmulholland@outlook.ie>
      * License: Public Domain

*/
package main

import (
    "fmt"
    "io"
    "os"
    "flag"
    "github.com/dmulholland/mp3cat/mp3lib"
)

const version = "0.4.1"

const usage = `Usage: mp3cat [FLAGS] ARGUMENTS

Concatenates MP3 files without re-encoding. Supports both CBR and VBR files.
Strips ID3 tags and garbage data from the output.

Arguments:

  <outfile>        Output file.
  <infiles>        List of input files to concatenate.

Flags:

  -f, --force      Force overwriting of existing output files.
  -v, --verbose    Report progress.
  --help           Display this help text and exit.
  --version        Display version number and exit.`

var helpFlag = flag.Bool("help", false, "print help text and exit")
var versionFlag = flag.Bool("version", false, "print version and exit")
var debugFlag = flag.Bool("debug", false, "print debug information")
var forceFlag = flag.Bool("force", false, "force overwriting of existing output files")
var verboseFlag = flag.Bool("verbose", false, "increase verbosity")

func init() {
    flag.BoolVar(forceFlag, "f", false, "force overwriting of existing output files")
    flag.BoolVar(verboseFlag, "v", false, "increase verbosity")
}

func main() {

    flag.Usage = func() {
        fmt.Println()
        fmt.Println(usage)
    }

    flag.Parse()

    if *helpFlag {
        fmt.Println(usage)
        os.Exit(0)
    }

    if *versionFlag {
        fmt.Println(version)
        os.Exit(0)
    }

    if *debugFlag {
        mp3lib.DebugMode = true
    }

    if flag.NArg() < 2 {
        fmt.Fprintln(os.Stderr, "Error: you must supply at least two arguments.\n")
        fmt.Fprintln(os.Stderr, usage)
        os.Exit(1)
    }

    mergeFiles(flag.Arg(0), flag.Args()[1:])
}

func mergeFiles(outputPath string, inputPaths []string) {

    var totalFrames uint32
    var totalBytes uint32
    var totalFiles int
    var firstBitRate int
    var isVBR bool

    if _, err := os.Stat(outputPath); err == nil {
        if !(*forceFlag) {
            fmt.Fprintf(os.Stderr, "Error: \"%v\" already exists.\n", outputPath)
            fmt.Fprintf(os.Stderr, "Use the --force flag to overwrite it.\n")
            os.Exit(1)
        }
    }

    for _, filepath := range inputPaths {
        if filepath == outputPath {
            fmt.Fprintln(os.Stderr, "Error: the list of input files includes the output file.")
            os.Exit(1)
        }
    }

    outputFile, err := os.Create(outputPath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    for _, filepath := range inputPaths {

        if *verboseFlag {
            fmt.Println("Merging:", filepath)
        }

        inputFile, err := os.Open(filepath)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        isFirstFrame := true

        for {
            frame := mp3lib.NextFrame(inputFile)
            if frame == nil {
                break
            }

            if isFirstFrame {
                isFirstFrame = false
                if mp3lib.IsXingHeader(frame) || mp3lib.IsVbriHeader(frame) {
                    continue
                }
            }

            if firstBitRate == 0 {
                firstBitRate = frame.BitRate
            } else if frame.BitRate != firstBitRate {
                isVBR = true
            }

            _, err := outputFile.Write(frame.RawBytes)
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            totalFrames += 1
            totalBytes += uint32(len(frame.RawBytes))
        }

        inputFile.Close()
        totalFiles += 1
    }

    outputFile.Close()

    if isVBR {
        if *verboseFlag {
            fmt.Println("VBR data detected. Adding Xing header.")
        }
        addXingHeader(outputPath, totalFrames, totalBytes)
    }

    if *verboseFlag {
        fmt.Printf("%v files merged.\n", totalFiles)
    }
}

func addXingHeader(filepath string, totalFrames, totalBytes uint32) {

    outputFile, err := os.Create(filepath + ".mp3cat.tmp")
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    inputFile, err := os.Open(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    templateFrame := mp3lib.NextFrame(inputFile)
    inputFile.Seek(0, 0)

    xingHeader := mp3lib.NewXingHeader(templateFrame, totalFrames, totalBytes)

    _, err = outputFile.Write(xingHeader.RawBytes)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    _, err = io.Copy(outputFile, inputFile)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    outputFile.Close()
    inputFile.Close()

    err = os.Remove(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    err = os.Rename(filepath + ".mp3cat.tmp", filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}
<commit_msg>Bump version to 1.0.0<commit_after>/*
    Command line utility for concatenating MP3 files without re-encoding.

    Supports both constant bit rate (CBR) and variable bit rate (VBR) files.
    Strips ID3 tags and garbage data from the output.

      * Author: Darren Mulholland <dmulholland@outlook.ie>
      * License: Public Domain

*/
package main

import (
    "fmt"
    "io"
    "os"
    "flag"
    "github.com/dmulholland/mp3cat/mp3lib"
)

const version = "1.0.0"

const usage = `Usage: mp3cat [FLAGS] ARGUMENTS

Concatenates MP3 files without re-encoding. Supports both CBR and VBR files.
Strips ID3 tags and garbage data from the output.

Arguments:

  <outfile>        Output file.
  <infiles>        List of input files to concatenate.

Flags:

  -f, --force      Force overwriting of existing output files.
  -v, --verbose    Report progress.
  --help           Display this help text and exit.
  --version        Display version number and exit.`

var helpFlag = flag.Bool("help", false, "print help text and exit")
var versionFlag = flag.Bool("version", false, "print version and exit")
var debugFlag = flag.Bool("debug", false, "print debug information")
var forceFlag = flag.Bool("force", false, "force overwriting of existing output files")
var verboseFlag = flag.Bool("verbose", false, "increase verbosity")

func init() {
    flag.BoolVar(forceFlag, "f", false, "force overwriting of existing output files")
    flag.BoolVar(verboseFlag, "v", false, "increase verbosity")
}

func main() {

    flag.Usage = func() {
        fmt.Println()
        fmt.Println(usage)
    }

    flag.Parse()

    if *helpFlag {
        fmt.Println(usage)
        os.Exit(0)
    }

    if *versionFlag {
        fmt.Println(version)
        os.Exit(0)
    }

    if *debugFlag {
        mp3lib.DebugMode = true
    }

    if flag.NArg() < 2 {
        fmt.Fprintln(os.Stderr, "Error: you must supply at least two arguments.\n")
        fmt.Fprintln(os.Stderr, usage)
        os.Exit(1)
    }

    mergeFiles(flag.Arg(0), flag.Args()[1:])
}

func mergeFiles(outputPath string, inputPaths []string) {

    var totalFrames uint32
    var totalBytes uint32
    var totalFiles int
    var firstBitRate int
    var isVBR bool

    if _, err := os.Stat(outputPath); err == nil {
        if !(*forceFlag) {
            fmt.Fprintf(os.Stderr, "Error: \"%v\" already exists.\n", outputPath)
            fmt.Fprintf(os.Stderr, "Use the --force flag to overwrite it.\n")
            os.Exit(1)
        }
    }

    for _, filepath := range inputPaths {
        if filepath == outputPath {
            fmt.Fprintln(os.Stderr, "Error: the list of input files includes the output file.")
            os.Exit(1)
        }
    }

    outputFile, err := os.Create(outputPath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    for _, filepath := range inputPaths {

        if *verboseFlag {
            fmt.Println("Merging:", filepath)
        }

        inputFile, err := os.Open(filepath)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        isFirstFrame := true

        for {
            frame := mp3lib.NextFrame(inputFile)
            if frame == nil {
                break
            }

            if isFirstFrame {
                isFirstFrame = false
                if mp3lib.IsXingHeader(frame) || mp3lib.IsVbriHeader(frame) {
                    continue
                }
            }

            if firstBitRate == 0 {
                firstBitRate = frame.BitRate
            } else if frame.BitRate != firstBitRate {
                isVBR = true
            }

            _, err := outputFile.Write(frame.RawBytes)
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            totalFrames += 1
            totalBytes += uint32(len(frame.RawBytes))
        }

        inputFile.Close()
        totalFiles += 1
    }

    outputFile.Close()

    if isVBR {
        if *verboseFlag {
            fmt.Println("VBR data detected. Adding Xing header.")
        }
        addXingHeader(outputPath, totalFrames, totalBytes)
    }

    if *verboseFlag {
        fmt.Printf("%v files merged.\n", totalFiles)
    }
}

func addXingHeader(filepath string, totalFrames, totalBytes uint32) {

    outputFile, err := os.Create(filepath + ".mp3cat.tmp")
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    inputFile, err := os.Open(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    templateFrame := mp3lib.NextFrame(inputFile)
    inputFile.Seek(0, 0)

    xingHeader := mp3lib.NewXingHeader(templateFrame, totalFrames, totalBytes)

    _, err = outputFile.Write(xingHeader.RawBytes)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    _, err = io.Copy(outputFile, inputFile)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    outputFile.Close()
    inputFile.Close()

    err = os.Remove(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    err = os.Rename(filepath + ".mp3cat.tmp", filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}
<|endoftext|>


<commit_before>package mock

import (
	crand "crypto/rand"
	"fmt"

	"github.com/hashicorp/nomad/nomad/structs"
)

func GenerateUUID() string {
	buf := make([]byte, 16)
	if _, err := crand.Read(buf); err != nil {
		panic(fmt.Errorf("failed to read random bytes: %v", err))
	}

	return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
		buf[0:4],
		buf[4:6],
		buf[6:8],
		buf[8:10],
		buf[10:16])
}

func Node() *structs.Node {
	node := &structs.Node{
		ID:         GenerateUUID(),
		Datacenter: "dc1",
		Name:       "foobar",
		Attributes: map[string]string{
			"os":            "linux",
			"arch":          "x86",
			"version":       "0.1.0",
			"driver.docker": "1.0.0",
		},
		Resources: &structs.Resources{
			CPU:      4.0,
			MemoryMB: 8192,
			DiskMB:   100 * 1024,
			IOPS:     150,
			Networks: []*structs.NetworkResource{
				&structs.NetworkResource{
					Public:        true,
					CIDR:          "192.168.0.100/32",
					ReservedPorts: []int{22},
					MBits:         1000,
				},
			},
		},
		Reserved: &structs.Resources{
			CPU:      0.1,
			MemoryMB: 256,
			DiskMB:   4 * 1024,
		},
		Links: map[string]string{
			"consul": "foobar.dc1",
		},
		Meta: map[string]string{
			"pci-dss": "true",
		},
		NodeClass: "linux-medium-pci",
		Status:    structs.NodeStatusReady,
	}
	return node
}

func Job() *structs.Job {
	job := &structs.Job{
		ID:          GenerateUUID(),
		Name:        "my-job",
		Type:        structs.JobTypeService,
		Priority:    50,
		AllAtOnce:   false,
		Datacenters: []string{"dc1"},
		Constraints: []*structs.Constraint{
			&structs.Constraint{
				Hard:    true,
				LTarget: "$attr.os",
				RTarget: "linux",
				Operand: "=",
			},
		},
		TaskGroups: []*structs.TaskGroup{
			&structs.TaskGroup{
				Name:  "web",
				Count: 10,
				Tasks: []*structs.Task{
					&structs.Task{
						Name:   "web",
						Driver: "docker",
						Config: map[string]string{
							"image":   "hashicorp/web",
							"version": "v1.2.3",
						},
						Resources: &structs.Resources{
							CPU:      0.5,
							MemoryMB: 256,
						},
					},
				},
				Meta: map[string]string{
					"elb_check_type":     "http",
					"elb_check_interval": "30s",
					"elb_check_min":      "3",
				},
			},
		},
		Meta: map[string]string{
			"owner": "armon",
		},
		Status:      structs.JobStatusPending,
		CreateIndex: 42,
		ModifyIndex: 99,
	}
	return job
}

func Eval() *structs.Evaluation {
	eval := &structs.Evaluation{
		ID:       GenerateUUID(),
		Priority: 50,
		Type:     structs.JobTypeService,
		JobID:    GenerateUUID(),
		Status:   structs.EvalStatusPending,
	}
	return eval
}

func Alloc() *structs.Allocation {
	alloc := &structs.Allocation{
		ID:     GenerateUUID(),
		EvalID: GenerateUUID(),
		NodeID: "foo",
		Resources: &structs.Resources{
			CPU:      1.0,
			MemoryMB: 1024,
			DiskMB:   1024,
			IOPS:     10,
			Networks: []*structs.NetworkResource{
				&structs.NetworkResource{
					Public:        true,
					CIDR:          "192.168.0.100/32",
					ReservedPorts: []int{12345},
					MBits:         100,
				},
			},
		},
		Job:    Job(),
		Status: structs.AllocStatusPending,
	}
	alloc.JobID = alloc.Job.ID
	return alloc
}

func Plan() *structs.Plan {
	return &structs.Plan{
		Priority: 50,
	}
}

func PlanResult() *structs.PlanResult {
	return &structs.PlanResult{}
}
<commit_msg>nomad: update mock alloc status<commit_after>package mock

import (
	crand "crypto/rand"
	"fmt"

	"github.com/hashicorp/nomad/nomad/structs"
)

func GenerateUUID() string {
	buf := make([]byte, 16)
	if _, err := crand.Read(buf); err != nil {
		panic(fmt.Errorf("failed to read random bytes: %v", err))
	}

	return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
		buf[0:4],
		buf[4:6],
		buf[6:8],
		buf[8:10],
		buf[10:16])
}

func Node() *structs.Node {
	node := &structs.Node{
		ID:         GenerateUUID(),
		Datacenter: "dc1",
		Name:       "foobar",
		Attributes: map[string]string{
			"os":            "linux",
			"arch":          "x86",
			"version":       "0.1.0",
			"driver.docker": "1.0.0",
		},
		Resources: &structs.Resources{
			CPU:      4.0,
			MemoryMB: 8192,
			DiskMB:   100 * 1024,
			IOPS:     150,
			Networks: []*structs.NetworkResource{
				&structs.NetworkResource{
					Public:        true,
					CIDR:          "192.168.0.100/32",
					ReservedPorts: []int{22},
					MBits:         1000,
				},
			},
		},
		Reserved: &structs.Resources{
			CPU:      0.1,
			MemoryMB: 256,
			DiskMB:   4 * 1024,
		},
		Links: map[string]string{
			"consul": "foobar.dc1",
		},
		Meta: map[string]string{
			"pci-dss": "true",
		},
		NodeClass: "linux-medium-pci",
		Status:    structs.NodeStatusReady,
	}
	return node
}

func Job() *structs.Job {
	job := &structs.Job{
		ID:          GenerateUUID(),
		Name:        "my-job",
		Type:        structs.JobTypeService,
		Priority:    50,
		AllAtOnce:   false,
		Datacenters: []string{"dc1"},
		Constraints: []*structs.Constraint{
			&structs.Constraint{
				Hard:    true,
				LTarget: "$attr.os",
				RTarget: "linux",
				Operand: "=",
			},
		},
		TaskGroups: []*structs.TaskGroup{
			&structs.TaskGroup{
				Name:  "web",
				Count: 10,
				Tasks: []*structs.Task{
					&structs.Task{
						Name:   "web",
						Driver: "docker",
						Config: map[string]string{
							"image":   "hashicorp/web",
							"version": "v1.2.3",
						},
						Resources: &structs.Resources{
							CPU:      0.5,
							MemoryMB: 256,
						},
					},
				},
				Meta: map[string]string{
					"elb_check_type":     "http",
					"elb_check_interval": "30s",
					"elb_check_min":      "3",
				},
			},
		},
		Meta: map[string]string{
			"owner": "armon",
		},
		Status:      structs.JobStatusPending,
		CreateIndex: 42,
		ModifyIndex: 99,
	}
	return job
}

func Eval() *structs.Evaluation {
	eval := &structs.Evaluation{
		ID:       GenerateUUID(),
		Priority: 50,
		Type:     structs.JobTypeService,
		JobID:    GenerateUUID(),
		Status:   structs.EvalStatusPending,
	}
	return eval
}

func Alloc() *structs.Allocation {
	alloc := &structs.Allocation{
		ID:     GenerateUUID(),
		EvalID: GenerateUUID(),
		NodeID: "foo",
		Resources: &structs.Resources{
			CPU:      1.0,
			MemoryMB: 1024,
			DiskMB:   1024,
			IOPS:     10,
			Networks: []*structs.NetworkResource{
				&structs.NetworkResource{
					Public:        true,
					CIDR:          "192.168.0.100/32",
					ReservedPorts: []int{12345},
					MBits:         100,
				},
			},
		},
		Job:           Job(),
		DesiredStatus: structs.AllocDesiredStatusRun,
		ClientStatus:  structs.AllocClientStatusPending,
	}
	alloc.JobID = alloc.Job.ID
	return alloc
}

func Plan() *structs.Plan {
	return &structs.Plan{
		Priority: 50,
	}
}

func PlanResult() *structs.PlanResult {
	return &structs.PlanResult{}
}
<|endoftext|>


<commit_before>package oauth1

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

// Out-Of-Band mode, used for applications that do not have
// a callback URL, such as mobile phones or command-line
// utilities.
const OOB = "oob"

// Consumer represents a website or application that uses the
// OAuth 1.0a protocol to access protected resources on behalf
// of a User.
type Consumer struct {
	// A value used by the Consumer to identify itself
	// to the Service Provider.
	ConsumerKey string

	// A secret used by the Consumer to establish
	// ownership of the Consumer Key.
	ConsumerSecret string

	// An absolute URL to which the Service Provider will redirect
	// the User back when the Obtaining User Authorization step
	// is completed.
	//
	// If the Consumer is unable to receive callbacks or a callback
	// URL has been established via other means, the parameter
	// value MUST be set to oob (case sensitive), to indicate
	// an out-of-band configuration.
	CallbackURL string

	// The URL used to obtain an unauthorized
	// Request Token.
	RequestTokenURL string

	// The URL used to obtain User authorization
	// for Consumer access.
	AccessTokenURL string

	// The URL used to exchange the User-authorized
	// Request Token for an Access Token.
	AuthorizationURL string
}

func (c *Consumer) RequestToken() (*RequestToken, error) {

	// create the http request to fetch a Request Token.
	requestTokenUrl, _ := url.Parse(c.RequestTokenURL)
	req := http.Request{
		URL:        requestTokenUrl,
		Method:     "GET",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, nil, map[string]string{ "oauth_callback":c.CallbackURL })
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	requestToken, err := ParseRequestToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return requestToken, nil
}

// AuthorizeRedirect constructs the request URL that should be used
// to redirect the User to verify User identify and consent.
func (c *Consumer) AuthorizeRedirect(t *RequestToken) (string, error) {
	redirect, err := url.Parse(c.AuthorizationURL)
	if err != nil {
		return "", err
	}
	params := make(url.Values)
	params.Add("oauth_token", t.token)
	redirect.RawQuery = params.Encode()
	return redirect.String(), nil
}

func (c *Consumer) AuthorizeToken(t *RequestToken, verifier string) (*AccessToken, error) {

	// create the http request to fetch a Request Token.
	accessTokenUrl, _ := url.Parse(c.AccessTokenURL)
	req := http.Request{
		URL:        accessTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, t, map[string]string{ "oauth_verifier":verifier })
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	accessToken, err := ParseAccessToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return accessToken, nil
}

// Sign will sign an http.Request using the provided token.
func (c *Consumer) Sign(req *http.Request, token Token) error {
	return c.SignParams(req, token, nil)
}

// Sign will sign an http.Request using the provided token, and additional
// parameters.
func (c *Consumer) SignParams(req *http.Request, token Token, params map[string]string) error {

	// ensure the parameter map is not nil
	if params == nil {
		params = map[string]string{}
	}

	// ensure default parameters are set
	//params["oauth_token"]            = token.Token()
	params["oauth_consumer_key"]     = c.ConsumerKey
	params["oauth_nonce"]            = nonce()
	params["oauth_signature_method"] = "HMAC-SHA1"
	params["oauth_timestamp"]        = timestamp()
	params["oauth_version"]          = "1.0"

	// we'll need to sign any form values?
	if req.Form != nil {
		for k, _ := range req.Form {
			params[k] = req.Form.Get(k)
		}
	}

	// we'll also need to sign any URL parameter
	queryParams := req.URL.Query()
	for k, _ := range queryParams {
		params[k] = queryParams.Get(k)
	}

	var tokenSecret string
	if token != nil {
		tokenSecret = token.Secret()
		params["oauth_token"] = token.Token()
	}

	// create the oauth signature
	key := escape(c.ConsumerSecret) + "&" + escape(tokenSecret)
	base := requestString(req.Method, req.URL.String(), params)
	params["oauth_signature"] = sign(base, key)

	//HACK: we were previously including params in the Authorization
	//      header that shouldn't be. so for now, we'll filter
	//authStringParams := map[string]string{}
	//for k,v := range params {
	//	if strings.HasPrefix(k, "oauth_") {
	//		authStringParams[k]=v
	//	}
	//}

	// ensure the http.Request's Header is not nil
	if req.Header == nil {
		req.Header = http.Header{}
	}

	// add the authorization header string
	req.Header.Add("Authorization", authorizationString(params))//params))

	// ensure the appropriate content-type is set for POST,
	// assuming the field is not populated
	if req.Method == "POST" && len(req.Header.Get("Content-Type")) == 0 {
		req.Header.Set("Content-Type","application/x-www-form-urlencoded")
	}

	return nil
}

// -----------------------------------------------------------------------------
// Private Helper Functions

// Nonce generator, seeded with current time
var nonceGenerator = rand.New(rand.NewSource(time.Now().Unix()))

// Nonce generates a random string. Nonce's are uniquely generated
// for each request.
func nonce() string {
	//return strconv.FormatInt(5786940697266324430,10)//TODO
	return strconv.FormatInt(nonceGenerator.Int63(), 10)
}

// Timestamp generates a timestamp, expressed in the number of seconds
// since January 1, 1970 00:00:00 GMT.
func timestamp() string {
	//return strconv.FormatInt(1358055923,10)
	return strconv.FormatInt(time.Now().Unix(), 10)
}

// Generates an HMAC Signature for an OAuth1.0a request.
func sign(message, key string) string {
	hashfun := hmac.New(sha1.New, []byte(key))
	hashfun.Write([]byte(message))
	rawsignature := hashfun.Sum(nil)
	base64signature := make([]byte, base64.StdEncoding.EncodedLen(len(rawsignature)))
	base64.StdEncoding.Encode(base64signature, rawsignature)

	return string(base64signature)
}

// Gets the default set of OAuth1.0a headers.
func headers(consumerKey string) map[string]string {
	return map[string]string{
		"oauth_consumer_key"     : consumerKey,
		"oauth_nonce"            : nonce(),
		"oauth_signature_method" : "HMAC-SHA1",
		"oauth_timestamp"        : timestamp(),
		"oauth_version"          : "1.0",
	}
}

func requestString(method string, uri string, params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	result := method + "&" + escape(uri)

	// loop through sorted params and append to the string
	for pos, key := range keys {
		if pos == 0 {
			result += "&"
		} else {
			result += escape("&")
		}

		result += escape(fmt.Sprintf("%s=%s", key, escape(params[key])))
	}

	return result
}

func authorizationString(params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	var str string
	var cnt = 0

	// loop through sorted params and append to the string
	for _, key := range keys {

		// we previously encoded all params (url params, form data & oauth params)
		// but for the authorization string we should only encode the oauth params
		if !strings.HasPrefix(key, "oauth_") {
			continue
		}

		if cnt > 0 {
			str += ","
		}

		str += fmt.Sprintf("%s=%q", key, escape(params[key]))
		cnt++
	}

	return fmt.Sprintf("OAuth %s", str)
}

func escape(s string) string {
	t := make([]byte, 0, 3*len(s))
	for i := 0; i < len(s); i++ {
		c := s[i]
		if isEscapable(c) {
			t = append(t, '%')
			t = append(t, "0123456789ABCDEF"[c>>4])
			t = append(t, "0123456789ABCDEF"[c&15])
		} else {
			t = append(t, s[i])
		}
	}
	return string(t)
}

func isEscapable(b byte) bool {
	return !('A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' || b == '-' || b == '.' || b == '_' || b == '~')

}

<commit_msg>added "application/x-www-form-urlencoded" header to PUT methods<commit_after>package oauth1

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

// Out-Of-Band mode, used for applications that do not have
// a callback URL, such as mobile phones or command-line
// utilities.
const OOB = "oob"

// Consumer represents a website or application that uses the
// OAuth 1.0a protocol to access protected resources on behalf
// of a User.
type Consumer struct {
	// A value used by the Consumer to identify itself
	// to the Service Provider.
	ConsumerKey string

	// A secret used by the Consumer to establish
	// ownership of the Consumer Key.
	ConsumerSecret string

	// An absolute URL to which the Service Provider will redirect
	// the User back when the Obtaining User Authorization step
	// is completed.
	//
	// If the Consumer is unable to receive callbacks or a callback
	// URL has been established via other means, the parameter
	// value MUST be set to oob (case sensitive), to indicate
	// an out-of-band configuration.
	CallbackURL string

	// The URL used to obtain an unauthorized
	// Request Token.
	RequestTokenURL string

	// The URL used to obtain User authorization
	// for Consumer access.
	AccessTokenURL string

	// The URL used to exchange the User-authorized
	// Request Token for an Access Token.
	AuthorizationURL string
}

func (c *Consumer) RequestToken() (*RequestToken, error) {

	// create the http request to fetch a Request Token.
	requestTokenUrl, _ := url.Parse(c.RequestTokenURL)
	req := http.Request{
		URL:        requestTokenUrl,
		Method:     "GET",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, nil, map[string]string{ "oauth_callback":c.CallbackURL })
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	requestToken, err := ParseRequestToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return requestToken, nil
}

// AuthorizeRedirect constructs the request URL that should be used
// to redirect the User to verify User identify and consent.
func (c *Consumer) AuthorizeRedirect(t *RequestToken) (string, error) {
	redirect, err := url.Parse(c.AuthorizationURL)
	if err != nil {
		return "", err
	}
	params := make(url.Values)
	params.Add("oauth_token", t.token)
	redirect.RawQuery = params.Encode()
	return redirect.String(), nil
}

func (c *Consumer) AuthorizeToken(t *RequestToken, verifier string) (*AccessToken, error) {

	// create the http request to fetch a Request Token.
	accessTokenUrl, _ := url.Parse(c.AccessTokenURL)
	req := http.Request{
		URL:        accessTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, t, map[string]string{ "oauth_verifier":verifier })
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	accessToken, err := ParseAccessToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return accessToken, nil
}

// Sign will sign an http.Request using the provided token.
func (c *Consumer) Sign(req *http.Request, token Token) error {
	return c.SignParams(req, token, nil)
}

// Sign will sign an http.Request using the provided token, and additional
// parameters.
func (c *Consumer) SignParams(req *http.Request, token Token, params map[string]string) error {

	// ensure the parameter map is not nil
	if params == nil {
		params = map[string]string{}
	}

	// ensure default parameters are set
	//params["oauth_token"]            = token.Token()
	params["oauth_consumer_key"]     = c.ConsumerKey
	params["oauth_nonce"]            = nonce()
	params["oauth_signature_method"] = "HMAC-SHA1"
	params["oauth_timestamp"]        = timestamp()
	params["oauth_version"]          = "1.0"

	// we'll need to sign any form values?
	if req.Form != nil {
		for k, _ := range req.Form {
			params[k] = req.Form.Get(k)
		}
	}

	// we'll also need to sign any URL parameter
	queryParams := req.URL.Query()
	for k, _ := range queryParams {
		params[k] = queryParams.Get(k)
	}

	var tokenSecret string
	if token != nil {
		tokenSecret = token.Secret()
		params["oauth_token"] = token.Token()
	}

	// create the oauth signature
	key := escape(c.ConsumerSecret) + "&" + escape(tokenSecret)
	base := requestString(req.Method, req.URL.String(), params)
	params["oauth_signature"] = sign(base, key)

	//HACK: we were previously including params in the Authorization
	//      header that shouldn't be. so for now, we'll filter
	//authStringParams := map[string]string{}
	//for k,v := range params {
	//	if strings.HasPrefix(k, "oauth_") {
	//		authStringParams[k]=v
	//	}
	//}

	// ensure the http.Request's Header is not nil
	if req.Header == nil {
		req.Header = http.Header{}
	}

	// add the authorization header string
	req.Header.Add("Authorization", authorizationString(params))//params))

	// ensure the appropriate content-type is set for POST,
	// assuming the field is not populated
	if (req.Method == "POST" || req.Method == "PUT") && len(req.Header.Get("Content-Type")) == 0 {
		req.Header.Set("Content-Type","application/x-www-form-urlencoded")
	}

	return nil
}

// -----------------------------------------------------------------------------
// Private Helper Functions

// Nonce generator, seeded with current time
var nonceGenerator = rand.New(rand.NewSource(time.Now().Unix()))

// Nonce generates a random string. Nonce's are uniquely generated
// for each request.
func nonce() string {
	return strconv.FormatInt(nonceGenerator.Int63(), 10)
}

// Timestamp generates a timestamp, expressed in the number of seconds
// since January 1, 1970 00:00:00 GMT.
func timestamp() string {
	return strconv.FormatInt(time.Now().Unix(), 10)
}

// Generates an HMAC Signature for an OAuth1.0a request.
func sign(message, key string) string {
	hashfun := hmac.New(sha1.New, []byte(key))
	hashfun.Write([]byte(message))
	rawsignature := hashfun.Sum(nil)
	base64signature := make([]byte, base64.StdEncoding.EncodedLen(len(rawsignature)))
	base64.StdEncoding.Encode(base64signature, rawsignature)

	return string(base64signature)
}

// Gets the default set of OAuth1.0a headers.
func headers(consumerKey string) map[string]string {
	return map[string]string{
		"oauth_consumer_key"     : consumerKey,
		"oauth_nonce"            : nonce(),
		"oauth_signature_method" : "HMAC-SHA1",
		"oauth_timestamp"        : timestamp(),
		"oauth_version"          : "1.0",
	}
}

func requestString(method string, uri string, params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	result := method + "&" + escape(uri)

	// loop through sorted params and append to the string
	for pos, key := range keys {
		if pos == 0 {
			result += "&"
		} else {
			result += escape("&")
		}

		result += escape(fmt.Sprintf("%s=%s", key, escape(params[key])))
	}

	return result
}

func authorizationString(params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	var str string
	var cnt = 0

	// loop through sorted params and append to the string
	for _, key := range keys {

		// we previously encoded all params (url params, form data & oauth params)
		// but for the authorization string we should only encode the oauth params
		if !strings.HasPrefix(key, "oauth_") {
			continue
		}

		if cnt > 0 {
			str += ","
		}

		str += fmt.Sprintf("%s=%q", key, escape(params[key]))
		cnt++
	}

	return fmt.Sprintf("OAuth %s", str)
}

func escape(s string) string {
	t := make([]byte, 0, 3*len(s))
	for i := 0; i < len(s); i++ {
		c := s[i]
		if isEscapable(c) {
			t = append(t, '%')
			t = append(t, "0123456789ABCDEF"[c>>4])
			t = append(t, "0123456789ABCDEF"[c&15])
		} else {
			t = append(t, s[i])
		}
	}
	return string(t)
}

func isEscapable(b byte) bool {
	return !('A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' || b == '-' || b == '.' || b == '_' || b == '~')

}

<|endoftext|>


<commit_before>package openapi

import (
	"context"
	"fmt"
	"net/http"
)

type Channel struct {
	ID            *string       `json:"id,omitempty"`
	TeamID        *string       `json:"team_id,omitempty"`
	VChannelID    *string       `json:"vchannel_id,omitempty"`
	UserID        *string       `json:"uid,omitempty"`
	Name          *string       `json:"name,omitempty"`
	Type          *VChannelType `json:"type,omitempty"`
	Private       *bool         `json:"private,omitempty"`
	General       *bool         `json:"general,omitempty"`
	Topic         *string       `json:"topic,omitempty"`
	IsMember      *bool         `json:"is_member,omitempty"`
	IsActive      *bool         `json:"is_active,omitempty"`
	MemberUserIDs []string      `json:"member_uids,omitempty"`
	LatestTS      *VChannelTS   `json:"latest_ts,omitempty"`
}

type ChannelService service

type ChannelInfoOptions struct {
	ChannelID string
}

// Info implements `GET /channel.info`
func (c *ChannelService) Info(ctx context.Context, opt *ChannelInfoOptions) (*Channel, *http.Response, error) {
	endpoint := fmt.Sprintf("channel.info?channel_id=%s", opt.ChannelID)
	req, err := c.client.newRequest("GET", endpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

// List implements `GET /channel.list`
func (c *ChannelService) List(ctx context.Context) ([]*Channel, *http.Response, error) {
	req, err := c.client.newRequest("GET", "channel.list", nil)
	if err != nil {
		return nil, nil, err
	}

	var channels []*Channel
	resp, err := c.client.do(ctx, req, &channels)
	if err != nil {
		return nil, resp, err
	}
	return channels, resp, nil
}

type ChannelCreateOptions struct {
	Name    string  `json:"name"`
	Topic   *string `json:"topic,omitempty"`
	Private *bool   `json:"private,omitempty"`
}

// Create implements `POST /channel.create`
func (c *ChannelService) Create(ctx context.Context, opt *ChannelCreateOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.create", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelArchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Archive implements `POST /channel.archive`
func (c *ChannelService) Archive(ctx context.Context, opt *ChannelArchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.archive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelUnarchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Unarchive implements `POST /channel.unarchive`
func (c *ChannelService) Unarchive(ctx context.Context, opt *ChannelUnarchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.unarchive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelLeaveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Leave implements `POST /channel.leave`
func (c *ChannelService) Leave(ctx context.Context, opt *ChannelLeaveOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.leave", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelJoinOptions struct {
	ChannelID string `json:"channel_id"`
}

// Join implements `POST /channel.join`
func (c *ChannelService) Join(ctx context.Context, opt *ChannelJoinOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.join", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelInviteOptions struct {
	ChannelID    string `json:"channel_id"`
	InviteUserID string `json:"invite_uid"`
}

// Invite implements `POST /channel.invite`
func (c *ChannelService) Invite(ctx context.Context, opt *ChannelInviteOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.invite", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}
<commit_msg>feat(openapi): implement `channel.kick`<commit_after>package openapi

import (
	"context"
	"fmt"
	"net/http"
)

type Channel struct {
	ID            *string       `json:"id,omitempty"`
	TeamID        *string       `json:"team_id,omitempty"`
	VChannelID    *string       `json:"vchannel_id,omitempty"`
	UserID        *string       `json:"uid,omitempty"`
	Name          *string       `json:"name,omitempty"`
	Type          *VChannelType `json:"type,omitempty"`
	Private       *bool         `json:"private,omitempty"`
	General       *bool         `json:"general,omitempty"`
	Topic         *string       `json:"topic,omitempty"`
	IsMember      *bool         `json:"is_member,omitempty"`
	IsActive      *bool         `json:"is_active,omitempty"`
	MemberUserIDs []string      `json:"member_uids,omitempty"`
	LatestTS      *VChannelTS   `json:"latest_ts,omitempty"`
}

type ChannelService service

type ChannelInfoOptions struct {
	ChannelID string
}

// Info implements `GET /channel.info`
func (c *ChannelService) Info(ctx context.Context, opt *ChannelInfoOptions) (*Channel, *http.Response, error) {
	endpoint := fmt.Sprintf("channel.info?channel_id=%s", opt.ChannelID)
	req, err := c.client.newRequest("GET", endpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

// List implements `GET /channel.list`
func (c *ChannelService) List(ctx context.Context) ([]*Channel, *http.Response, error) {
	req, err := c.client.newRequest("GET", "channel.list", nil)
	if err != nil {
		return nil, nil, err
	}

	var channels []*Channel
	resp, err := c.client.do(ctx, req, &channels)
	if err != nil {
		return nil, resp, err
	}
	return channels, resp, nil
}

type ChannelCreateOptions struct {
	Name    string  `json:"name"`
	Topic   *string `json:"topic,omitempty"`
	Private *bool   `json:"private,omitempty"`
}

// Create implements `POST /channel.create`
func (c *ChannelService) Create(ctx context.Context, opt *ChannelCreateOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.create", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelArchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Archive implements `POST /channel.archive`
func (c *ChannelService) Archive(ctx context.Context, opt *ChannelArchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.archive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelUnarchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Unarchive implements `POST /channel.unarchive`
func (c *ChannelService) Unarchive(ctx context.Context, opt *ChannelUnarchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.unarchive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelLeaveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Leave implements `POST /channel.leave`
func (c *ChannelService) Leave(ctx context.Context, opt *ChannelLeaveOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.leave", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelJoinOptions struct {
	ChannelID string `json:"channel_id"`
}

// Join implements `POST /channel.join`
func (c *ChannelService) Join(ctx context.Context, opt *ChannelJoinOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.join", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelInviteOptions struct {
	ChannelID    string `json:"channel_id"`
	InviteUserID string `json:"invite_uid"`
}

// Invite implements `POST /channel.invite`
func (c *ChannelService) Invite(ctx context.Context, opt *ChannelInviteOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.invite", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelKickOptions struct {
	ChannelID  string `json:"channel_id"`
	KickUserID string `json:"kick_uid"`
}

// Kick implements `POST /channel.kick`
func (c *ChannelService) Kick(ctx context.Context, opt *ChannelKickOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.kickout", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}
<|endoftext|>