<commit_before>//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    decoder.go
//: details: TODO
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: 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 sflow

import (
	"encoding/binary"
	"errors"
	"io"
	"net"
)

const (
	DataFlowSample    = 1 // Packet Flow Sampling
	DataCounterSample = 2 // Counter Sampling
)

type SFDecoder struct {
	reader io.ReadSeeker
	filter []uint32 // Filter data format(s)
}

type SFDatagram struct {
	Version    uint32 // Datagram version
	IPVersion  uint32 // Data gram sFlow version
	AgentSubId uint32 // Identifies a source of sFlow data
	SequenceNo uint32 // Sequence of sFlow Datagrams
	SysUpTime  uint32 // Current time (in milliseconds since device last booted
	SamplesNo  uint32 // Number of samples

	IPAddress net.IP // Agent IP address
}

type SFSampledHeader struct {
	HeaderProtocol uint32 // (enum SFHeaderProtocol)
	FrameLength    uint32 // Original length of packet before sampling
	Stripped       uint32 // Header/trailer bytes stripped by sender
	HeaderLength   uint32 // Length of sampled header bytes to follow
	HeaderBytes    []byte // Header bytes
}

type SFSample interface{}

var (
	nonEnterpriseStandard = errors.New("the enterprise is not standard sflow data")
	dataLengthUnknown     = errors.New("the sflow data length is unknown")
	sfVersionNotSupport   = errors.New("the sflow version doesn't support")
)

func NewSFDecoder(r io.ReadSeeker, f []uint32) SFDecoder {
	return SFDecoder{
		reader: r,
		filter: f,
	}
}

func (d *SFDecoder) SFDecode() ([]interface{}, error) {
	datagram, err := d.sfHeaderDecode()
	if err != nil {
		return nil, err
	}

	for i := uint32(0); i < datagram.SamplesNo; i++ {
		sfTypeFormat, sfDataLength, err := d.getSampleInfo()
		if err != nil {
			return nil, err
		}

		if m := d.isFilterMatch(sfTypeFormat); m {
			d.reader.Seek(int64(sfDataLength), 1)
			continue
		}

		switch sfTypeFormat {
		case DataFlowSample:
			h, err := decodeFlowSample(d.reader)
			return h, err
		case DataCounterSample:
			d.reader.Seek(int64(sfDataLength), 1)
		default:
			d.reader.Seek(int64(sfDataLength), 1)

		}

	}

	return nil, nil
}

func (d *SFDecoder) sfHeaderDecode() (*SFDatagram, error) {
	var (
		datagram     = &SFDatagram{}
		ipLen    int = 4
		err      error
	)

	if err = read(d.reader, &datagram.Version); err != nil {
		return nil, err
	}

	if datagram.Version != 5 {
		return nil, sfVersionNotSupport
	}

	if err = read(d.reader, &datagram.IPVersion); err != nil {
		return nil, err
	}

	// read the agent ip address
	if datagram.IPVersion == 2 {
		ipLen = 16
	}
	buff := make([]byte, ipLen)
	if _, err = d.reader.Read(buff); err != nil {
		return nil, err
	}
	datagram.IPAddress = buff

	if err = read(d.reader, &datagram.AgentSubId); err != nil {
		return nil, err
	}
	if err = read(d.reader, &datagram.SequenceNo); err != nil {
		return nil, err
	}
	if err = read(d.reader, &datagram.SysUpTime); err != nil {
		return nil, err
	}
	if err = read(d.reader, &datagram.SamplesNo); err != nil {
		return nil, err
	}

	return datagram, nil
}

func (d *SFDecoder) getSampleInfo() (uint32, uint32, error) {
	var (
		sfType           uint32
		sfTypeFormat     uint32
		sfTypeEnterprise uint32
		sfDataLength     uint32

		err error
	)

	if err = read(d.reader, &sfType); err != nil {
		return 0, 0, err
	}

	sfTypeEnterprise = sfType >> 12 // 20 bytes enterprise
	sfTypeFormat = sfType & 0xfff   // 12 bytes format

	// supports standard sflow data
	if sfTypeEnterprise != 0 {
		d.reader.Seek(int64(sfDataLength), 1)
		return 0, 0, nonEnterpriseStandard
	}

	if err = read(d.reader, &sfDataLength); err != nil {
		return 0, 0, dataLengthUnknown
	}

	return sfTypeFormat, sfDataLength, nil
}

func (d *SFDecoder) isFilterMatch(f uint32) bool {
	for _, v := range d.filter {
		if v == f {
			return true
		}
	}
	return false
}

func read(r io.Reader, v interface{}) error {
	return binary.Read(r, binary.BigEndian, v)
}
<commit_msg>fix golint and clean up<commit_after>// Package sflow decodes sFlow packets
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    decoder.go
//: details: TODO
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: 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 sflow

import (
	"encoding/binary"
	"errors"
	"io"
	"net"
)

const (
	// DataFlowSample defines packet flow sampling
	DataFlowSample = 1

	// DataCounterSample defines counter sampling
	DataCounterSample = 2
)

// SFDecoder represents sFlow decoder
type SFDecoder struct {
	reader io.ReadSeeker
	filter []uint32 // Filter data format(s)
}

// SFDatagram represents sFlow datagram
type SFDatagram struct {
	Version    uint32 // Datagram version
	IPVersion  uint32 // Data gram sFlow version
	AgentSubID uint32 // Identifies a source of sFlow data
	SequenceNo uint32 // Sequence of sFlow Datagrams
	SysUpTime  uint32 // Current time (in milliseconds since device last booted
	SamplesNo  uint32 // Number of samples

	IPAddress net.IP // Agent IP address
}

// SFSampledHeader represents sFlow sample header
type SFSampledHeader struct {
	HeaderProtocol uint32 // (enum SFHeaderProtocol)
	FrameLength    uint32 // Original length of packet before sampling
	Stripped       uint32 // Header/trailer bytes stripped by sender
	HeaderLength   uint32 // Length of sampled header bytes to follow
	HeaderBytes    []byte // Header bytes
}

var (
	errNoneEnterpriseStandard = errors.New("the enterprise is not standard sflow data")
	errDataLengthUnknown      = errors.New("the sflow data length is unknown")
	errSFVersionNotSupport    = errors.New("the sflow version doesn't support")
)

// NewSFDecoder constructs new sflow decoder
func NewSFDecoder(r io.ReadSeeker, f []uint32) SFDecoder {
	return SFDecoder{
		reader: r,
		filter: f,
	}
}

// SFDecode decodes sFlow data
func (d *SFDecoder) SFDecode() ([]interface{}, error) {
	datagram, err := d.sfHeaderDecode()
	if err != nil {
		return nil, err
	}

	for i := uint32(0); i < datagram.SamplesNo; i++ {
		sfTypeFormat, sfDataLength, err := d.getSampleInfo()
		if err != nil {
			return nil, err
		}

		if m := d.isFilterMatch(sfTypeFormat); m {
			d.reader.Seek(int64(sfDataLength), 1)
			continue
		}

		switch sfTypeFormat {
		case DataFlowSample:
			h, err := decodeFlowSample(d.reader)
			return h, err
		case DataCounterSample:
			d.reader.Seek(int64(sfDataLength), 1)
		default:
			d.reader.Seek(int64(sfDataLength), 1)

		}

	}

	return nil, nil
}

func (d *SFDecoder) sfHeaderDecode() (*SFDatagram, error) {
	var (
		datagram = &SFDatagram{}
		ipLen    = 4
		err      error
	)

	if err = read(d.reader, &datagram.Version); err != nil {
		return nil, err
	}

	if datagram.Version != 5 {
		return nil, errSFVersionNotSupport
	}

	if err = read(d.reader, &datagram.IPVersion); err != nil {
		return nil, err
	}

	// read the agent ip address
	if datagram.IPVersion == 2 {
		ipLen = 16
	}
	buff := make([]byte, ipLen)
	if _, err = d.reader.Read(buff); err != nil {
		return nil, err
	}
	datagram.IPAddress = buff

	if err = read(d.reader, &datagram.AgentSubID); err != nil {
		return nil, err
	}
	if err = read(d.reader, &datagram.SequenceNo); err != nil {
		return nil, err
	}
	if err = read(d.reader, &datagram.SysUpTime); err != nil {
		return nil, err
	}
	if err = read(d.reader, &datagram.SamplesNo); err != nil {
		return nil, err
	}

	return datagram, nil
}

func (d *SFDecoder) getSampleInfo() (uint32, uint32, error) {
	var (
		sfType           uint32
		sfTypeFormat     uint32
		sfTypeEnterprise uint32
		sfDataLength     uint32

		err error
	)

	if err = read(d.reader, &sfType); err != nil {
		return 0, 0, err
	}

	sfTypeEnterprise = sfType >> 12 // 20 bytes enterprise
	sfTypeFormat = sfType & 0xfff   // 12 bytes format

	// supports standard sflow data
	if sfTypeEnterprise != 0 {
		d.reader.Seek(int64(sfDataLength), 1)
		return 0, 0, errNoneEnterpriseStandard
	}

	if err = read(d.reader, &sfDataLength); err != nil {
		return 0, 0, errDataLengthUnknown
	}

	return sfTypeFormat, sfDataLength, nil
}

func (d *SFDecoder) isFilterMatch(f uint32) bool {
	for _, v := range d.filter {
		if v == f {
			return true
		}
	}
	return false
}

func read(r io.Reader, v interface{}) error {
	return binary.Read(r, binary.BigEndian, v)
}
<|endoftext|>


<commit_before>package csrf

import (
	"github.com/cssivision/looli"
)

type Options struct {
}

func New(options Options) looli.HandlerFunc {
	return func(c *looli.Context) {
	}
}
<commit_msg>feat: csrf part finished<commit_after>package csrf

import (
	"github.com/cssivision/looli"
	"net/http"
)

var (
    maxAge = 12 * 3600
    cookieName = "_csrf"
)

type Options struct {
	FormKey    string
	HeaderKey  string
	Skip       func(*looli.Context) bool
	MaxAge     int
	Domain     string
	Path       string
	HttpOnly   bool
	Secure     bool
}

func Default() looli.HandlerFunc {
	return New(Options{})
}

func New(options Options) looli.HandlerFunc {
	if options.FormKey == "" {
		options.FormKey = "csrf_token"
	}

	if options.HeaderKey == "" {
		options.HeaderKey = "X-CSRF-Token"
	}

	if options.MaxAge == 0 {
		options.MaxAge = maxAge
	}

	return func(c *looli.Context) {
		if options.Skip != nil && options.Skip(c) {
			return
		}

		// Set the Vary: Cookie header to protect clients from caching the response.
		c.ResponseWriter.Header().Add("Vary", "Cookie")

		csrfToken := c.PostForm(options.FormKey)
		if csrfToken == "" {
			csrfToken = c.Header(options.HeaderKey)
		}

		if csrfToken == "" || !verify(getSecret(c), csrfToken) {
			c.AbortWithStatus(http.StatusForbidden)
			c.String("invalid csrf token")
            return
		}
	}
}

func getSecret(c *looli.Context) string {
    value, err := c.Cookie(cookieName)
    var secretCookie *http.Cookie

    if err != nil {
        secretCookie = &http.Cookie{}
        secretCookie.Name = cookieName
        secretCookie.Value = newSecret(c)
        secretCookie.MaxAge = maxAge
        value = secretCookie.Value
        c.SetCookie(secretCookie)
    }
    return value
}

func NewToken(c *looli.Context) string {
    return ""
}

func newSecret(c *looli.Context) string {
    return ""
}

func verify(secret, token string) bool {
    return true
}
<|endoftext|>


<commit_before>// +build go1.8

package simple

import "go/types"

// TODO(dh): use types.IdenticalIgnoreTags once CL 24190 has been merged
// var structsIdentical = types.IdenticalIgnoreTags
var structsIdentical = types.Identical
<commit_msg>simple: ignore struct tags in conversions for Go 1.8<commit_after>// +build go1.8

package simple

import "go/types"

var structsIdentical = types.IdenticalIgnoreTags
<|endoftext|>


<commit_before>package ctx

const (
	DefaultConfig = `
{
    zones: [
        {
            name: "test"
            zk: "10.213.42.140:12181,10.213.42.141:12181,10.213.42.142:12181"
        }
        {
            name: "sit"
            zk: "10.213.33.154:2181,10.213.42.48:2181,10.213.42.49:2181"
        }
        {
            name: "prod"
            zk: "10.209.33.69:2181,10.209.37.19:2181,10.209.37.68:2181"
        }
    ]

    zk_default_zone: "prod"
    kafka_home: "/opt/kafka_2.10-0.8.2.2"
    loglevel: "info"

    aliases: [
    	//{
    	//	cmd: "_xxx"
    	//	alias: "_yyy"
    	//}
    ]

    reverse_dns: [
        // test zk
        "z12181a.test.wdds.zk.com:10.213.42.140"
        "z12181b.test.wdds.zk.com:10.213.42.141"
        "z12181c.test.wdds.zk.com:10.213.42.142"

        // test kafka brokers
        "k10001a.test.wdds.kfk.com:10.213.57.156"
        "k10001b.test.wdds.kfk.com:10.213.42.135"

        // sit zk
        "z2181a.sit.wdds.zk.com:10.213.33.154"
        "z2181b.sit.wdds.zk.com:10.213.42.48"
        "z2181c.sit.wdds.zk.com:10.213.42.49"

        // sit kafka brokers
        "k10101a.sit.wdds.kfk.com:10.213.33.148"
        "k10101b.sit.wdds.kfk.com:10.213.33.149"
        "k10102a.sit.wdds.kfk.com:10.213.33.148"
        "k10102b.sit.wdds.kfk.com:10.213.33.149"
        "k10103a.sit.wdds.kfk.com:10.213.33.148"
        "k10103b.sit.wdds.kfk.com:10.213.33.149"
        "k10104a.sit.wdds.kfk.com:10.213.33.148"
        "k10104b.sit.wdds.kfk.com:10.213.33.149"
        "k10105a.sit.wdds.kfk.com:10.213.33.148"
        "k10105b.sit.wdds.kfk.com:10.213.33.149"
        "k10106a.sit.wdds.kfk.com:10.213.33.148"
        "k10106b.sit.wdds.kfk.com:10.213.33.149"
        "k10107a.sit.wdds.kfk.com:10.213.33.148"
        "k10107b.sit.wdds.kfk.com:10.213.33.149"
        "k10108a.sit.wdds.kfk.com:10.213.33.148"
        "k10108b.sit.wdds.kfk.com:10.213.33.149"
        "k10109a.sit.wdds.kfk.com:10.213.33.148"
        "k10109b.sit.wdds.kfk.com:10.213.33.149"
        "k10110a.sit.wdds.kfk.com:10.213.33.148"
        "k10110b.sit.wdds.kfk.com:10.213.33.149"
        "k10111a.sit.wdds.kfk.com:10.213.33.148"
        "k10111b.sit.wdds.kfk.com:10.213.33.149"
        "k10112a.sit.wdds.kfk.com:10.213.33.148"
        "k10112b.sit.wdds.kfk.com:10.213.33.149"
        "k10113a.sit.wdds.kfk.com:10.213.33.148"
        "k10113b.sit.wdds.kfk.com:10.213.33.149"
        "k10114a.sit.wdds.kfk.com:10.213.33.148"
        "k10114b.sit.wdds.kfk.com:10.213.33.149"
        "k10115a.sit.wdds.kfk.com:10.213.33.148"
        "k10115b.sit.wdds.kfk.com:10.213.33.149"
        "k10116a.sit.wdds.kfk.com:10.213.33.148"
        "k10116b.sit.wdds.kfk.com:10.213.33.149"
        "k10117c.sit.wdds.kfk.com:10.213.33.150"
        "k10117d.sit.wdds.kfk.com:10.213.33.151"
        "k10118c.sit.wdds.kfk.com:10.213.33.150"
        "k10118d.sit.wdds.kfk.com:10.213.33.151"
        "k11000a.sit.wdds.kfk.com:10.213.33.148"
        "k11000b.sit.wdds.kfk.com:10.213.33.149"
        "k11001a.sit.wdds.kfk.com:10.213.33.148"
        "k11001b.sit.wdds.kfk.com:10.213.33.149"

        // prod zk
        "zk2181a.wdds.zk.com:10.209.33.69"
        "zk2181b.wdds.zk.com:10.209.37.19"
        "zk2181c.wdds.zk.com:10.209.37.68"

        // prod kafka brokers
        "k10101a.wdds.kfk.com:10.209.37.39"
        "k10101b.wdds.kfk.com:10.209.33.20"
        "k10102a.wdds.kfk.com:10.209.37.39"
        "k10102b.wdds.kfk.com:10.209.33.20"
        "k10103a.wdds.kfk.com:10.209.37.39"
        "k10103b.wdds.kfk.com:10.209.33.20"
        "k10104a.wdds.kfk.com:10.209.37.39"
        "k10104b.wdds.kfk.com:10.209.33.20"
        "k10105a.wdds.kfk.com:10.209.37.39"
        "k10105b.wdds.kfk.com:10.209.33.20"
        "k10106a.wdds.kfk.com:10.209.37.39"
        "k10106b.wdds.kfk.com:10.209.33.20"
        "k10107a.wdds.kfk.com:10.209.37.39"
        "k10107b.wdds.kfk.com:10.209.33.20"
        "k10108a.wdds.kfk.com:10.209.37.39"
        "k10108b.wdds.kfk.com:10.209.33.20"
        "k10109a.wdds.kfk.com:10.209.37.39"
        "k10109b.wdds.kfk.com:10.209.33.20"
        "k10110a.wdds.kfk.com:10.209.37.39"
        "k10110b.wdds.kfk.com:10.209.33.20"
        "k10111a.wdds.kfk.com:10.209.37.39"
        "k10111b.wdds.kfk.com:10.209.33.20"
        "k10112a.wdds.kfk.com:10.209.37.39"
        "k10112b.wdds.kfk.com:10.209.33.20"
        "k10113a.wdds.kfk.com:10.209.37.69"
        "k10113b.wdds.kfk.com:10.209.33.40"
        "k10114a.wdds.kfk.com:10.209.37.69"
        "k10114b.wdds.kfk.com:10.209.33.40"
        "k10115a.wdds.kfk.com:10.209.37.69"
        "k10115b.wdds.kfk.com:10.209.33.40"
        "k10116a.wdds.kfk.com:10.209.37.69"
        "k10116b.wdds.kfk.com:10.209.33.40"
        "k10117a.wdds.kfk.com:10.209.37.69"
        "k10117b.wdds.kfk.com:10.209.33.40"
        "k10118a.wdds.kfk.com:10.209.37.69"
        "k10118b.wdds.kfk.com:10.209.33.40"
        "k10119a.wdds.kfk.com:10.209.37.69"
        "k10119b.wdds.kfk.com:10.209.33.40"
        "k10120a.wdds.kfk.com:10.209.37.69"
        "k10120b.wdds.kfk.com:10.209.33.40"
        "k10121a.wdds.kfk.com:10.209.37.69"
        "k10121b.wdds.kfk.com:10.209.33.40"
        "k10122a.wdds.kfk.com:10.209.37.69"
        "k10122b.wdds.kfk.com:10.209.33.40"
        "k11000a.wdds.kfk.com:10.209.37.39"
        "k11000b.wdds.kfk.com:10.209.33.20"
        "k11001a.wdds.kfk.com:10.209.37.69"
        "k11001b.wdds.kfk.com:10.209.33.40"
        "k10120a.wdds.kfk.com:10.209.10.161"
        "k10120b.wdds.kfk.com:10.209.10.141"
        "k10121a.wdds.kfk.com:10.209.10.161"
        "k10121b.wdds.kfk.com:10.209.10.141"
        "k10118a.wdds.kfk.com:10.209.11.166"
        "k10118b.wdds.kfk.com:10.209.11.195"
        "k11003a.wdds.kfk.com:10.209.18.15"
        "k11003b.wdds.kfk.com:10.209.18.16"
    ]
}
`
)
<commit_msg>new zk clusters added<commit_after>package ctx

const (
	DefaultConfig = `
{
    zones: [
        {
            name: "test"
            zk: "10.213.42.140:12181,10.213.42.141:12181,10.213.42.142:12181"
        }
        {
            name: "sit"
            zk: "10.213.33.154:2181,10.213.42.48:2181,10.213.42.49:2181"
        }
        {
            name: "prod"
            zk: "10.209.33.69:2181,10.209.37.19:2181,10.209.37.68:2181"
        }
        {
            name: "z_payment_test"
            zk: "10.213.43.69:2181,10.213.43.70:2181,10.213.43.72:2181"
        }
        {
            name: "z_payment_sit"
			zk: "10.213.57.247:2181,10.213.34.37:2181,10.213.57.245:2181"
        }
        {
            name: "z_payment_prod"
			zk: "10.213.1.225:2181,10.213.10.140:2181,10.213.18.207:2181,10.213.10.145:2181,10.213.18.215:2181"
        }
    ]

    zk_default_zone: "prod"
    kafka_home: "/opt/kafka_2.10-0.8.2.2"
    loglevel: "info"

    aliases: [
    	//{
    	//	cmd: "_xxx"
    	//	alias: "_yyy"
    	//}
    ]

    reverse_dns: [
        // test zk
        "z12181a.test.wdds.zk.com:10.213.42.140"
        "z12181b.test.wdds.zk.com:10.213.42.141"
        "z12181c.test.wdds.zk.com:10.213.42.142"

        // test kafka brokers
        "k10001a.test.wdds.kfk.com:10.213.57.156"
        "k10001b.test.wdds.kfk.com:10.213.42.135"

        // sit zk
        "z2181a.sit.wdds.zk.com:10.213.33.154"
        "z2181b.sit.wdds.zk.com:10.213.42.48"
        "z2181c.sit.wdds.zk.com:10.213.42.49"

        // sit kafka brokers
        "k10101a.sit.wdds.kfk.com:10.213.33.148"
        "k10101b.sit.wdds.kfk.com:10.213.33.149"
        "k10102a.sit.wdds.kfk.com:10.213.33.148"
        "k10102b.sit.wdds.kfk.com:10.213.33.149"
        "k10103a.sit.wdds.kfk.com:10.213.33.148"
        "k10103b.sit.wdds.kfk.com:10.213.33.149"
        "k10104a.sit.wdds.kfk.com:10.213.33.148"
        "k10104b.sit.wdds.kfk.com:10.213.33.149"
        "k10105a.sit.wdds.kfk.com:10.213.33.148"
        "k10105b.sit.wdds.kfk.com:10.213.33.149"
        "k10106a.sit.wdds.kfk.com:10.213.33.148"
        "k10106b.sit.wdds.kfk.com:10.213.33.149"
        "k10107a.sit.wdds.kfk.com:10.213.33.148"
        "k10107b.sit.wdds.kfk.com:10.213.33.149"
        "k10108a.sit.wdds.kfk.com:10.213.33.148"
        "k10108b.sit.wdds.kfk.com:10.213.33.149"
        "k10109a.sit.wdds.kfk.com:10.213.33.148"
        "k10109b.sit.wdds.kfk.com:10.213.33.149"
        "k10110a.sit.wdds.kfk.com:10.213.33.148"
        "k10110b.sit.wdds.kfk.com:10.213.33.149"
        "k10111a.sit.wdds.kfk.com:10.213.33.148"
        "k10111b.sit.wdds.kfk.com:10.213.33.149"
        "k10112a.sit.wdds.kfk.com:10.213.33.148"
        "k10112b.sit.wdds.kfk.com:10.213.33.149"
        "k10113a.sit.wdds.kfk.com:10.213.33.148"
        "k10113b.sit.wdds.kfk.com:10.213.33.149"
        "k10114a.sit.wdds.kfk.com:10.213.33.148"
        "k10114b.sit.wdds.kfk.com:10.213.33.149"
        "k10115a.sit.wdds.kfk.com:10.213.33.148"
        "k10115b.sit.wdds.kfk.com:10.213.33.149"
        "k10116a.sit.wdds.kfk.com:10.213.33.148"
        "k10116b.sit.wdds.kfk.com:10.213.33.149"
        "k10117c.sit.wdds.kfk.com:10.213.33.150"
        "k10117d.sit.wdds.kfk.com:10.213.33.151"
        "k10118c.sit.wdds.kfk.com:10.213.33.150"
        "k10118d.sit.wdds.kfk.com:10.213.33.151"
        "k11000a.sit.wdds.kfk.com:10.213.33.148"
        "k11000b.sit.wdds.kfk.com:10.213.33.149"
        "k11001a.sit.wdds.kfk.com:10.213.33.148"
        "k11001b.sit.wdds.kfk.com:10.213.33.149"

        // prod zk
        "zk2181a.wdds.zk.com:10.209.33.69"
        "zk2181b.wdds.zk.com:10.209.37.19"
        "zk2181c.wdds.zk.com:10.209.37.68"

        // prod kafka brokers
        "k10101a.wdds.kfk.com:10.209.37.39"
        "k10101b.wdds.kfk.com:10.209.33.20"
        "k10102a.wdds.kfk.com:10.209.37.39"
        "k10102b.wdds.kfk.com:10.209.33.20"
        "k10103a.wdds.kfk.com:10.209.37.39"
        "k10103b.wdds.kfk.com:10.209.33.20"
        "k10104a.wdds.kfk.com:10.209.37.39"
        "k10104b.wdds.kfk.com:10.209.33.20"
        "k10105a.wdds.kfk.com:10.209.37.39"
        "k10105b.wdds.kfk.com:10.209.33.20"
        "k10106a.wdds.kfk.com:10.209.37.39"
        "k10106b.wdds.kfk.com:10.209.33.20"
        "k10107a.wdds.kfk.com:10.209.37.39"
        "k10107b.wdds.kfk.com:10.209.33.20"
        "k10108a.wdds.kfk.com:10.209.37.39"
        "k10108b.wdds.kfk.com:10.209.33.20"
        "k10109a.wdds.kfk.com:10.209.37.39"
        "k10109b.wdds.kfk.com:10.209.33.20"
        "k10110a.wdds.kfk.com:10.209.37.39"
        "k10110b.wdds.kfk.com:10.209.33.20"
        "k10111a.wdds.kfk.com:10.209.37.39"
        "k10111b.wdds.kfk.com:10.209.33.20"
        "k10112a.wdds.kfk.com:10.209.37.39"
        "k10112b.wdds.kfk.com:10.209.33.20"
        "k10113a.wdds.kfk.com:10.209.37.69"
        "k10113b.wdds.kfk.com:10.209.33.40"
        "k10114a.wdds.kfk.com:10.209.37.69"
        "k10114b.wdds.kfk.com:10.209.33.40"
        "k10115a.wdds.kfk.com:10.209.37.69"
        "k10115b.wdds.kfk.com:10.209.33.40"
        "k10116a.wdds.kfk.com:10.209.37.69"
        "k10116b.wdds.kfk.com:10.209.33.40"
        "k10117a.wdds.kfk.com:10.209.37.69"
        "k10117b.wdds.kfk.com:10.209.33.40"
        "k10118a.wdds.kfk.com:10.209.37.69"
        "k10118b.wdds.kfk.com:10.209.33.40"
        "k10119a.wdds.kfk.com:10.209.37.69"
        "k10119b.wdds.kfk.com:10.209.33.40"
        "k10120a.wdds.kfk.com:10.209.37.69"
        "k10120b.wdds.kfk.com:10.209.33.40"
        "k10121a.wdds.kfk.com:10.209.37.69"
        "k10121b.wdds.kfk.com:10.209.33.40"
        "k10122a.wdds.kfk.com:10.209.37.69"
        "k10122b.wdds.kfk.com:10.209.33.40"
        "k11000a.wdds.kfk.com:10.209.37.39"
        "k11000b.wdds.kfk.com:10.209.33.20"
        "k11001a.wdds.kfk.com:10.209.37.69"
        "k11001b.wdds.kfk.com:10.209.33.40"
        "k10120a.wdds.kfk.com:10.209.10.161"
        "k10120b.wdds.kfk.com:10.209.10.141"
        "k10121a.wdds.kfk.com:10.209.10.161"
        "k10121b.wdds.kfk.com:10.209.10.141"
        "k10118a.wdds.kfk.com:10.209.11.166"
        "k10118b.wdds.kfk.com:10.209.11.195"
        "k11003a.wdds.kfk.com:10.209.18.15"
        "k11003b.wdds.kfk.com:10.209.18.16"
    ]
}
`
)
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.

// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

// +build linux darwin freebsd

package cups

/*
#cgo freebsd CFLAGS: -I/usr/local/include
#cgo freebsd LDFLAGS: -L/usr/local/lib
#include "cups.h"
*/
import "C"
import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"
	"unsafe"

	"github.com/avlis/cloud-print-connector/lib"
	"github.com/avlis/cloud-print-connector/log"
)

const (
	// jobURIFormat is the string format required by the CUPS API
	// to do things like query the state of a job.
	jobURIFormat = "/jobs/%d"

	// filePathMaxLength varies by operating system and file system.
	// This value should be large enough to be useful and small enough
	// to work on any platform.
	filePathMaxLength = 1024
)

// cupsCore handles CUPS API interaction and connection management.
type cupsCore struct {
	host           *C.char
	port           C.int
	encryption     C.http_encryption_t
	connectTimeout C.int
	// connectionSemaphore limits the quantity of open CUPS connections.
	connectionSemaphore *lib.Semaphore
	// connectionPool allows a connection to be reused instead of closed.
	connectionPool chan *C.http_t
	hostIsLocal    bool
}

func newCUPSCore(maxConnections uint, connectTimeout time.Duration) (*cupsCore, error) {
	host := C.cupsServer()
	port := C.ippPort()
	encryption := C.cupsEncryption()
	timeout := C.int(connectTimeout / time.Millisecond)

	var e string
	switch encryption {
	case C.HTTP_ENCRYPTION_ALWAYS:
		e = "encrypting ALWAYS"
	case C.HTTP_ENCRYPTION_IF_REQUESTED:
		e = "encrypting IF REQUESTED"
	case C.HTTP_ENCRYPTION_NEVER:
		e = "encrypting NEVER"
	case C.HTTP_ENCRYPTION_REQUIRED:
		e = "encryption REQUIRED"
	default:
		encryption = C.HTTP_ENCRYPTION_REQUIRED
		e = "encrypting REQUIRED"
	}

	var hostIsLocal bool
	if h := C.GoString(host); strings.HasPrefix(h, "/") || h == "localhost" {
		hostIsLocal = true
	}

	cs := lib.NewSemaphore(maxConnections)
	cp := make(chan *C.http_t)

	cc := &cupsCore{host, port, encryption, timeout, cs, cp, hostIsLocal}

	log.Infof("Connecting to CUPS server at %s:%d %s", C.GoString(host), int(port), e)

	// This connection isn't used, just checks that a connection is possible
	// before returning from the constructor.
	http, err := cc.connect()
	if err != nil {
		return nil, err
	}
	cc.disconnect(http)

	log.Info("Connected to CUPS server successfully")

	return cc, nil
}

// printFile prints by calling C.cupsPrintFile2().
// Returns the CUPS job ID, which is 0 (and meaningless) when err
// is not nil.
func (cc *cupsCore) printFile(user, printername, filename, title *C.char, numOptions C.int, options *C.cups_option_t) (C.int, error) {
	http, err := cc.connect()
	if err != nil {
		return 0, err
	}
	defer cc.disconnect(http)

	C.cupsSetUser(user)
	jobID := C.cupsPrintFile2(http, printername, filename, title, numOptions, options)
	if jobID == 0 {
		return 0, fmt.Errorf("Failed to call cupsPrintFile2() for file %s: %d %s",
			C.GoString(filename), int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
	}

	return jobID, nil
}

// getPrinters gets the current list and state of printers by calling
// C.doRequest (IPP_OP_CUPS_GET_PRINTERS).
//
// The caller is responsible to C.ippDelete the returned *C.ipp_t response.
func (cc *cupsCore) getPrinters(attributes **C.char, attrSize C.int) (*C.ipp_t, error) {
	// ippNewRequest() returns ipp_t pointer which does not need explicit free.
	request := C.ippNewRequest(C.IPP_OP_CUPS_GET_PRINTERS)
	C.ippAddStrings(request, C.IPP_TAG_OPERATION, C.IPP_TAG_KEYWORD, C.REQUESTED_ATTRIBUTES,
		attrSize, nil, attributes)

	response, err := cc.doRequest(request,
		[]C.ipp_status_t{C.IPP_STATUS_OK, C.IPP_STATUS_ERROR_NOT_FOUND})
	if err != nil {
		err = fmt.Errorf("Failed to call cupsDoRequest() [IPP_OP_CUPS_GET_PRINTERS]: %s", err)
		return nil, err
	}

	return response, nil
}

// getPPD gets the filename of the PPD for a printer by calling
// C.cupsGetPPD3. If the PPD hasn't changed since the time indicated
// by modtime, then the returned filename is a nil pointer.
//
// Note that modtime is a pointer whose value is changed by this
// function.
//
// The caller is responsible to C.free the returned *C.char filename
// if the returned filename is not nil.
func (cc *cupsCore) getPPD(printername *C.char, modtime *C.time_t) (*C.char, error) {
	bufsize := C.size_t(filePathMaxLength)
	buffer := (*C.char)(C.malloc(bufsize))
	if buffer == nil {
		return nil, errors.New("Failed to malloc; out of memory?")
	}
	C.memset(unsafe.Pointer(buffer), 0, bufsize)

	var http *C.http_t
	if !cc.hostIsLocal {
		// Don't need a connection or corresponding semaphore if the PPD
		// is on the local filesystem.
		// Still need OS thread lock; see else.
		var err error
		http, err = cc.connect()
		if err != nil {
			return nil, err
		}
		defer cc.disconnect(http)

	} else {
		// Lock the OS thread so that thread-local storage is available to
		// cupsLastError() and cupsLastErrorString().
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
	}

	httpStatus := C.cupsGetPPD3(http, printername, modtime, buffer, bufsize)

        switch httpStatus {
        case C.HTTP_STATUS_NOT_MODIFIED:
                // Cache hit.
                if len(C.GoString(buffer)) > 0 {
                        os.Remove(C.GoString(buffer))
                }
                C.free(unsafe.Pointer(buffer))
                return nil, nil

        case C.HTTP_STATUS_OK:
                // Cache miss.
                return buffer, nil

        case C.HTTP_STATUS_NOT_FOUND:
                // printer does not exist @ cups
                if len(C.GoString(buffer)) > 0 {
                        os.Remove(C.GoString(buffer))
                }
                C.free(unsafe.Pointer(buffer))
                return nil, fmt.Errorf("printer does not exist: %d", httpStatus)

        default:
                //ignore all other errors, may be temporary
                if len(C.GoString(buffer)) > 0 {
                        os.Remove(C.GoString(buffer))
                }
                C.free(unsafe.Pointer(buffer))
                return nil,nil
        }
}

// getJobAttributes gets the requested attributes for a job by calling
// C.doRequest (IPP_OP_GET_JOB_ATTRIBUTES).
//
// The caller is responsible to C.ippDelete the returned *C.ipp_t response.
func (cc *cupsCore) getJobAttributes(jobID C.int, attributes **C.char) (*C.ipp_t, error) {
	uri, err := createJobURI(jobID)
	if err != nil {
		return nil, err
	}
	defer C.free(unsafe.Pointer(uri))

	// ippNewRequest() returns ipp_t pointer does not need explicit free.
	request := C.ippNewRequest(C.IPP_OP_GET_JOB_ATTRIBUTES)

	C.ippAddString(request, C.IPP_TAG_OPERATION, C.IPP_TAG_URI, C.JOB_URI_ATTRIBUTE, nil, uri)
	C.ippAddStrings(request, C.IPP_TAG_OPERATION, C.IPP_TAG_KEYWORD, C.REQUESTED_ATTRIBUTES,
		C.int(0), nil, attributes)

	response, err := cc.doRequest(request, []C.ipp_status_t{C.IPP_STATUS_OK})
	if err != nil {
		err = fmt.Errorf("Failed to call cupsDoRequest() [IPP_OP_GET_JOB_ATTRIBUTES]: %s", err)
		return nil, err
	}

	return response, nil
}

// createJobURI creates a uri string for the job-uri attribute, used to get the
// state of a CUPS job.
func createJobURI(jobID C.int) (*C.char, error) {
	length := C.size_t(urlMaxLength)
	uri := (*C.char)(C.malloc(length))
	if uri == nil {
		return nil, errors.New("Failed to malloc; out of memory?")
	}

	resource := C.CString(fmt.Sprintf(jobURIFormat, uint32(jobID)))
	defer C.free(unsafe.Pointer(resource))
	C.httpAssembleURI(C.HTTP_URI_CODING_ALL,
		uri, C.int(length), C.IPP, nil, C.cupsServer(), C.ippPort(), resource)

	return uri, nil
}

// doRequest calls cupsDoRequest().
func (cc *cupsCore) doRequest(request *C.ipp_t, acceptableStatusCodes []C.ipp_status_t) (*C.ipp_t, error) {
	http, err := cc.connect()
	if err != nil {
		return nil, err
	}
	defer cc.disconnect(http)

	if C.ippValidateAttributes(request) != 1 {
		return nil, fmt.Errorf("Bad IPP request: %s", C.GoString(C.cupsLastErrorString()))
	}

	response := C.cupsDoRequest(http, request, C.POST_RESOURCE)
	if response == nil {
		return nil, fmt.Errorf("cupsDoRequest failed: %d %s", int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
	}
	statusCode := C.getIPPRequestStatusCode(response)
	for _, sc := range acceptableStatusCodes {
		if statusCode == sc {
			return response, nil
		}
	}

	return nil, fmt.Errorf("IPP status code %d", int(statusCode))
}

// connect calls C.httpConnect2 to create a new, open connection to
// the CUPS server specified by environment variables, client.conf, etc.
//
// connect also acquires the connection semaphore and locks the OS
// thread to allow the CUPS API to use thread-local storage cleanly.
//
// The caller is responsible to close the connection when finished
// using cupsCore.disconnect.
func (cc *cupsCore) connect() (*C.http_t, error) {
	cc.connectionSemaphore.Acquire()

	// Lock the OS thread so that thread-local storage is available to
	// cupsLastError() and cupsLastErrorString().
	runtime.LockOSThread()

	var http *C.http_t

	select {
	case h := <-cc.connectionPool:
		// Reuse another connection.
		http = h
	default:
		// No connection available for reuse; create a new one.
		http = C.httpConnect2(cc.host, cc.port, nil, C.AF_UNSPEC, cc.encryption, 1, cc.connectTimeout, nil)
		if http == nil {
			defer cc.disconnect(http)
			return nil, fmt.Errorf("Failed to connect to CUPS server %s:%d because %d %s",
				C.GoString(cc.host), int(cc.port), int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
		}
	}

	return http, nil
}

// disconnect calls C.httpClose to close an open CUPS connection, then
// unlocks the OS thread and the connection semaphore.
//
// The http argument may be nil; the OS thread and semaphore are still
// treated the same as described above.
func (cc *cupsCore) disconnect(http *C.http_t) {
	go func() {
		select {
		case cc.connectionPool <- http:
			// Hand this connection to the next guy who needs it.
		case <-time.After(time.Second):
			// Don't wait very long; stale connections are no fun.
			C.httpClose(http)
		}
	}()
	runtime.UnlockOSThread()
	cc.connectionSemaphore.Release()
}

func (cc *cupsCore) connQtyOpen() uint {
	return cc.connectionSemaphore.Count()
}

func (cc *cupsCore) connQtyMax() uint {
	return cc.connectionSemaphore.Size()
}
<commit_msg>remove 404 handling, causing issues as well<commit_after>// Copyright 2015 Google Inc. All rights reserved.

// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

// +build linux darwin freebsd

package cups

/*
#cgo freebsd CFLAGS: -I/usr/local/include
#cgo freebsd LDFLAGS: -L/usr/local/lib
#include "cups.h"
*/
import "C"
import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"
	"unsafe"

	"github.com/avlis/cloud-print-connector/lib"
	"github.com/avlis/cloud-print-connector/log"
)

const (
	// jobURIFormat is the string format required by the CUPS API
	// to do things like query the state of a job.
	jobURIFormat = "/jobs/%d"

	// filePathMaxLength varies by operating system and file system.
	// This value should be large enough to be useful and small enough
	// to work on any platform.
	filePathMaxLength = 1024
)

// cupsCore handles CUPS API interaction and connection management.
type cupsCore struct {
	host           *C.char
	port           C.int
	encryption     C.http_encryption_t
	connectTimeout C.int
	// connectionSemaphore limits the quantity of open CUPS connections.
	connectionSemaphore *lib.Semaphore
	// connectionPool allows a connection to be reused instead of closed.
	connectionPool chan *C.http_t
	hostIsLocal    bool
}

func newCUPSCore(maxConnections uint, connectTimeout time.Duration) (*cupsCore, error) {
	host := C.cupsServer()
	port := C.ippPort()
	encryption := C.cupsEncryption()
	timeout := C.int(connectTimeout / time.Millisecond)

	var e string
	switch encryption {
	case C.HTTP_ENCRYPTION_ALWAYS:
		e = "encrypting ALWAYS"
	case C.HTTP_ENCRYPTION_IF_REQUESTED:
		e = "encrypting IF REQUESTED"
	case C.HTTP_ENCRYPTION_NEVER:
		e = "encrypting NEVER"
	case C.HTTP_ENCRYPTION_REQUIRED:
		e = "encryption REQUIRED"
	default:
		encryption = C.HTTP_ENCRYPTION_REQUIRED
		e = "encrypting REQUIRED"
	}

	var hostIsLocal bool
	if h := C.GoString(host); strings.HasPrefix(h, "/") || h == "localhost" {
		hostIsLocal = true
	}

	cs := lib.NewSemaphore(maxConnections)
	cp := make(chan *C.http_t)

	cc := &cupsCore{host, port, encryption, timeout, cs, cp, hostIsLocal}

	log.Infof("Connecting to CUPS server at %s:%d %s", C.GoString(host), int(port), e)

	// This connection isn't used, just checks that a connection is possible
	// before returning from the constructor.
	http, err := cc.connect()
	if err != nil {
		return nil, err
	}
	cc.disconnect(http)

	log.Info("Connected to CUPS server successfully")

	return cc, nil
}

// printFile prints by calling C.cupsPrintFile2().
// Returns the CUPS job ID, which is 0 (and meaningless) when err
// is not nil.
func (cc *cupsCore) printFile(user, printername, filename, title *C.char, numOptions C.int, options *C.cups_option_t) (C.int, error) {
	http, err := cc.connect()
	if err != nil {
		return 0, err
	}
	defer cc.disconnect(http)

	C.cupsSetUser(user)
	jobID := C.cupsPrintFile2(http, printername, filename, title, numOptions, options)
	if jobID == 0 {
		return 0, fmt.Errorf("Failed to call cupsPrintFile2() for file %s: %d %s",
			C.GoString(filename), int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
	}

	return jobID, nil
}

// getPrinters gets the current list and state of printers by calling
// C.doRequest (IPP_OP_CUPS_GET_PRINTERS).
//
// The caller is responsible to C.ippDelete the returned *C.ipp_t response.
func (cc *cupsCore) getPrinters(attributes **C.char, attrSize C.int) (*C.ipp_t, error) {
	// ippNewRequest() returns ipp_t pointer which does not need explicit free.
	request := C.ippNewRequest(C.IPP_OP_CUPS_GET_PRINTERS)
	C.ippAddStrings(request, C.IPP_TAG_OPERATION, C.IPP_TAG_KEYWORD, C.REQUESTED_ATTRIBUTES,
		attrSize, nil, attributes)

	response, err := cc.doRequest(request,
		[]C.ipp_status_t{C.IPP_STATUS_OK, C.IPP_STATUS_ERROR_NOT_FOUND})
	if err != nil {
		err = fmt.Errorf("Failed to call cupsDoRequest() [IPP_OP_CUPS_GET_PRINTERS]: %s", err)
		return nil, err
	}

	return response, nil
}

// getPPD gets the filename of the PPD for a printer by calling
// C.cupsGetPPD3. If the PPD hasn't changed since the time indicated
// by modtime, then the returned filename is a nil pointer.
//
// Note that modtime is a pointer whose value is changed by this
// function.
//
// The caller is responsible to C.free the returned *C.char filename
// if the returned filename is not nil.
func (cc *cupsCore) getPPD(printername *C.char, modtime *C.time_t) (*C.char, error) {
	bufsize := C.size_t(filePathMaxLength)
	buffer := (*C.char)(C.malloc(bufsize))
	if buffer == nil {
		return nil, errors.New("Failed to malloc; out of memory?")
	}
	C.memset(unsafe.Pointer(buffer), 0, bufsize)

	var http *C.http_t
	if !cc.hostIsLocal {
		// Don't need a connection or corresponding semaphore if the PPD
		// is on the local filesystem.
		// Still need OS thread lock; see else.
		var err error
		http, err = cc.connect()
		if err != nil {
			return nil, err
		}
		defer cc.disconnect(http)

	} else {
		// Lock the OS thread so that thread-local storage is available to
		// cupsLastError() and cupsLastErrorString().
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
	}

	httpStatus := C.cupsGetPPD3(http, printername, modtime, buffer, bufsize)

        switch httpStatus {
        case C.HTTP_STATUS_NOT_MODIFIED:
                // Cache hit.
                if len(C.GoString(buffer)) > 0 {
                        os.Remove(C.GoString(buffer))
                }
                C.free(unsafe.Pointer(buffer))
                return nil, nil

        case C.HTTP_STATUS_OK:
                // Cache miss.
                return buffer, nil

        default:
                //ignore all other errors, may be temporary
                if len(C.GoString(buffer)) > 0 {
                        os.Remove(C.GoString(buffer))
                }
                C.free(unsafe.Pointer(buffer))
                return nil,nil
        }
}

// getJobAttributes gets the requested attributes for a job by calling
// C.doRequest (IPP_OP_GET_JOB_ATTRIBUTES).
//
// The caller is responsible to C.ippDelete the returned *C.ipp_t response.
func (cc *cupsCore) getJobAttributes(jobID C.int, attributes **C.char) (*C.ipp_t, error) {
	uri, err := createJobURI(jobID)
	if err != nil {
		return nil, err
	}
	defer C.free(unsafe.Pointer(uri))

	// ippNewRequest() returns ipp_t pointer does not need explicit free.
	request := C.ippNewRequest(C.IPP_OP_GET_JOB_ATTRIBUTES)

	C.ippAddString(request, C.IPP_TAG_OPERATION, C.IPP_TAG_URI, C.JOB_URI_ATTRIBUTE, nil, uri)
	C.ippAddStrings(request, C.IPP_TAG_OPERATION, C.IPP_TAG_KEYWORD, C.REQUESTED_ATTRIBUTES,
		C.int(0), nil, attributes)

	response, err := cc.doRequest(request, []C.ipp_status_t{C.IPP_STATUS_OK})
	if err != nil {
		err = fmt.Errorf("Failed to call cupsDoRequest() [IPP_OP_GET_JOB_ATTRIBUTES]: %s", err)
		return nil, err
	}

	return response, nil
}

// createJobURI creates a uri string for the job-uri attribute, used to get the
// state of a CUPS job.
func createJobURI(jobID C.int) (*C.char, error) {
	length := C.size_t(urlMaxLength)
	uri := (*C.char)(C.malloc(length))
	if uri == nil {
		return nil, errors.New("Failed to malloc; out of memory?")
	}

	resource := C.CString(fmt.Sprintf(jobURIFormat, uint32(jobID)))
	defer C.free(unsafe.Pointer(resource))
	C.httpAssembleURI(C.HTTP_URI_CODING_ALL,
		uri, C.int(length), C.IPP, nil, C.cupsServer(), C.ippPort(), resource)

	return uri, nil
}

// doRequest calls cupsDoRequest().
func (cc *cupsCore) doRequest(request *C.ipp_t, acceptableStatusCodes []C.ipp_status_t) (*C.ipp_t, error) {
	http, err := cc.connect()
	if err != nil {
		return nil, err
	}
	defer cc.disconnect(http)

	if C.ippValidateAttributes(request) != 1 {
		return nil, fmt.Errorf("Bad IPP request: %s", C.GoString(C.cupsLastErrorString()))
	}

	response := C.cupsDoRequest(http, request, C.POST_RESOURCE)
	if response == nil {
		return nil, fmt.Errorf("cupsDoRequest failed: %d %s", int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
	}
	statusCode := C.getIPPRequestStatusCode(response)
	for _, sc := range acceptableStatusCodes {
		if statusCode == sc {
			return response, nil
		}
	}

	return nil, fmt.Errorf("IPP status code %d", int(statusCode))
}

// connect calls C.httpConnect2 to create a new, open connection to
// the CUPS server specified by environment variables, client.conf, etc.
//
// connect also acquires the connection semaphore and locks the OS
// thread to allow the CUPS API to use thread-local storage cleanly.
//
// The caller is responsible to close the connection when finished
// using cupsCore.disconnect.
func (cc *cupsCore) connect() (*C.http_t, error) {
	cc.connectionSemaphore.Acquire()

	// Lock the OS thread so that thread-local storage is available to
	// cupsLastError() and cupsLastErrorString().
	runtime.LockOSThread()

	var http *C.http_t

	select {
	case h := <-cc.connectionPool:
		// Reuse another connection.
		http = h
	default:
		// No connection available for reuse; create a new one.
		http = C.httpConnect2(cc.host, cc.port, nil, C.AF_UNSPEC, cc.encryption, 1, cc.connectTimeout, nil)
		if http == nil {
			defer cc.disconnect(http)
			return nil, fmt.Errorf("Failed to connect to CUPS server %s:%d because %d %s",
				C.GoString(cc.host), int(cc.port), int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
		}
	}

	return http, nil
}

// disconnect calls C.httpClose to close an open CUPS connection, then
// unlocks the OS thread and the connection semaphore.
//
// The http argument may be nil; the OS thread and semaphore are still
// treated the same as described above.
func (cc *cupsCore) disconnect(http *C.http_t) {
	go func() {
		select {
		case cc.connectionPool <- http:
			// Hand this connection to the next guy who needs it.
		case <-time.After(time.Second):
			// Don't wait very long; stale connections are no fun.
			C.httpClose(http)
		}
	}()
	runtime.UnlockOSThread()
	cc.connectionSemaphore.Release()
}

func (cc *cupsCore) connQtyOpen() uint {
	return cc.connectionSemaphore.Count()
}

func (cc *cupsCore) connQtyMax() uint {
	return cc.connectionSemaphore.Size()
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 inspectors

import (
	"flag"
	"os"
	"os/exec"
	"strings"
	"time"

	log "github.com/cihub/seelog"
	"github.com/mitchellh/cli"

	inspector "github.com/osrg/namazu/nmz/inspector/proc"
)

type procFlags struct {
	commonFlags
	RootPID       int
	WatchInterval time.Duration
	Cmd           string
	Stdout        string
	Stderr        string
}

var (
	procFlagset = flag.NewFlagSet("proc", flag.ExitOnError)
	_procFlags  = procFlags{}
)

func init() {
	initCommon(procFlagset, &_procFlags.commonFlags, "_namazu_proc_inspector")
	procFlagset.IntVar(&_procFlags.RootPID, "pid", -1, "PID for the target process tree")
	procFlagset.DurationVar(&_procFlags.WatchInterval, "watch-interval", 1*time.Second, "Watching interval")
	procFlagset.StringVar(&_procFlags.Cmd, "cmd", "", "Command for target process")
	procFlagset.StringVar(&_procFlags.Stdout, "stdout", "", "Stdout for target process (used if -cmd option is given)")
	procFlagset.StringVar(&_procFlags.Stderr, "stderr", "", "Stderr for target process (used if -cmd option is given)")
}

type procCmd struct {
}

func ProcCommandFactory() (cli.Command, error) {
	return procCmd{}, nil
}

func (cmd procCmd) Help() string {
	return "Please run `nmz --help inspectors` instead"
}

func (cmd procCmd) Synopsis() string {
	return "Start process inspector"
}

func (cmd procCmd) Run(args []string) int {
	if err := procFlagset.Parse(args); err != nil {
		log.Critical(err)
		return 1
	}

	pid := _procFlags.RootPID
	endCh := make(chan struct{})

	if pid <= 0 {
		if _procFlags.Cmd != "" {
			args := strings.Split(_procFlags.Cmd, " ")
			cmd := exec.Command(args[0], args[1:]...)

			if _procFlags.Stdout == "" {
				cmd.Stdout = os.Stdout
			} else {
				f, err := os.OpenFile(_procFlags.Stdout, os.O_WRONLY|os.O_CREATE, 0622)
				if err != nil {
					log.Critical("failed to open a file %s for stdout: %s", _procFlags.Stdout, err)
					return 1
				}
				cmd.Stdout = f
			}

			if _procFlags.Stderr == "" {
				cmd.Stderr = os.Stderr
			} else {
				f, err := os.OpenFile(_procFlags.Stderr, os.O_WRONLY|os.O_CREATE, 0622)
				if err != nil {
					log.Critical("failed to open a file %s for stderr: %s", _procFlags.Stderr, err)
					return 1
				}
				cmd.Stderr = f
			}

			err := cmd.Start()
			if err != nil {
				log.Critical("failed to cmd.Start: %s", err)
				return 1
			}

			pid = cmd.Process.Pid

			go func() {
				err := cmd.Wait()
				if err != nil {
					log.Critical("failed to cmd.Wait: %s", err)
				}
				endCh <- struct{}{}
			}()
		} else {
			log.Critical("pid and command line are not set (or set to non-positive value)")
			return 1
		}
	} else if _procFlags.Cmd != "" {
		log.Critical("you cannot set both pid and command line")
		return 1
	}

	autopilot, err := conditionalStartAutopilotOrchestrator(_procFlags.commonFlags)
	if err != nil {
		log.Critical(err)
		return 1
	}
	log.Infof("Autopilot-mode: %t", autopilot)

	procInspector := &inspector.ProcInspector{
		OrchestratorURL: _procFlags.OrchestratorURL,
		EntityID:        _procFlags.EntityID,
		RootPID:         pid,
		WatchInterval:   _procFlags.WatchInterval,
	}

	if err := procInspector.Serve(endCh); err != nil {
		panic(log.Critical(err))
	}

	// NOTREACHED
	return 0
}
<commit_msg>cli: use given stdout as stderr by default (#155)<commit_after>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 inspectors

import (
	"flag"
	"os"
	"os/exec"
	"strings"
	"time"

	log "github.com/cihub/seelog"
	"github.com/mitchellh/cli"

	inspector "github.com/osrg/namazu/nmz/inspector/proc"
)

type procFlags struct {
	commonFlags
	RootPID       int
	WatchInterval time.Duration
	Cmd           string
	Stdout        string
	Stderr        string
}

var (
	procFlagset = flag.NewFlagSet("proc", flag.ExitOnError)
	_procFlags  = procFlags{}
)

func init() {
	initCommon(procFlagset, &_procFlags.commonFlags, "_namazu_proc_inspector")
	procFlagset.IntVar(&_procFlags.RootPID, "pid", -1, "PID for the target process tree")
	procFlagset.DurationVar(&_procFlags.WatchInterval, "watch-interval", 1*time.Second, "Watching interval")
	procFlagset.StringVar(&_procFlags.Cmd, "cmd", "", "Command for target process")
	procFlagset.StringVar(&_procFlags.Stdout, "stdout", "", "Stdout for target process (used if -cmd option is given)")
	procFlagset.StringVar(&_procFlags.Stderr, "stderr", "", "Stderr for target process (used if -cmd option is given)")
}

type procCmd struct {
}

func ProcCommandFactory() (cli.Command, error) {
	return procCmd{}, nil
}

func (cmd procCmd) Help() string {
	return "Please run `nmz --help inspectors` instead"
}

func (cmd procCmd) Synopsis() string {
	return "Start process inspector"
}

func (cmd procCmd) Run(args []string) int {
	if err := procFlagset.Parse(args); err != nil {
		log.Critical(err)
		return 1
	}

	pid := _procFlags.RootPID
	endCh := make(chan struct{})

	if pid <= 0 {
		if _procFlags.Cmd != "" {
			args := strings.Split(_procFlags.Cmd, " ")
			cmd := exec.Command(args[0], args[1:]...)

			if _procFlags.Stdout == "" {
				cmd.Stdout = os.Stdout
			} else {
				f, err := os.OpenFile(_procFlags.Stdout, os.O_WRONLY|os.O_CREATE, 0622)
				if err != nil {
					log.Critical("failed to open a file %s for stdout: %s", _procFlags.Stdout, err)
					return 1
				}
				cmd.Stdout = f

				if _procFlags.Stderr == "" {
					cmd.Stderr = f
				}
			}

			if _procFlags.Stderr == "" {
				if cmd.Stderr == nil {
					cmd.Stderr = os.Stderr
				}
			} else {
				f, err := os.OpenFile(_procFlags.Stderr, os.O_WRONLY|os.O_CREATE, 0622)
				if err != nil {
					log.Critical("failed to open a file %s for stderr: %s", _procFlags.Stderr, err)
					return 1
				}
				cmd.Stderr = f
			}

			err := cmd.Start()
			if err != nil {
				log.Critical("failed to cmd.Start: %s", err)
				return 1
			}

			pid = cmd.Process.Pid

			go func() {
				err := cmd.Wait()
				if err != nil {
					log.Critical("failed to cmd.Wait: %s", err)
				}
				endCh <- struct{}{}
			}()
		} else {
			log.Critical("pid and command line are not set (or set to non-positive value)")
			return 1
		}
	} else if _procFlags.Cmd != "" {
		log.Critical("you cannot set both pid and command line")
		return 1
	}

	autopilot, err := conditionalStartAutopilotOrchestrator(_procFlags.commonFlags)
	if err != nil {
		log.Critical(err)
		return 1
	}
	log.Infof("Autopilot-mode: %t", autopilot)

	procInspector := &inspector.ProcInspector{
		OrchestratorURL: _procFlags.OrchestratorURL,
		EntityID:        _procFlags.EntityID,
		RootPID:         pid,
		WatchInterval:   _procFlags.WatchInterval,
	}

	if err := procInspector.Serve(endCh); err != nil {
		panic(log.Critical(err))
	}

	// NOTREACHED
	return 0
}
<|endoftext|>


<commit_before>package skiplist

import (
	"fmt"
	"math/rand"
	"strings"
	"testing"
)

//
// Utility functions
//

func less(a, b interface{}) bool {
	return a.(int) < b.(int)
}

func shuffleRange(min, max int) []int {
	a := make ([]int, max - min + 1)
	for i := range(a) {
		a[i] = min+i
	}
	for i := range(a) {
		other := rand.Intn(max-min+1)
		a[i], a[other] = a[other], a[i]
	}
	return a
}

func skiplist(min, max int) *Skiplist {
	s := New(less, nil)
	for _, v := range shuffleRange(min,max) {
		s.Insert (v, 2*v)
	}
	return s
}

//
// Benchmarks, examples, and Tests
//

func TestSkiplist(t *testing.T) {
	s := skiplist(1, 20)
	i := 1
	for e := s.Front(); e != nil; e = e.Next() {
		if e.Key().(int) != i || e.Value.(int) != 2*i {
			t.Fail()
		}
		i++
	}
}

func TestElement_Key(t *testing.T) {
	e := skiplist(1,3).Front()
	for i := 1; i<=3; i++ {
		if e == nil || e.Key().(int) != i {
			t.Fail()
		}
		e = e.Next()
	}
}

func ExampleElement_Next() {
	s := New(less, nil).Insert(0, 0).Insert(1, 2).Insert(2, 4).Insert(3, 6)
	for e := s.Front(); e != nil; e = e.Next() {
		fmt.Print(e, " ")
	}
	// Output: 0:0 1:2 2:4 3:6
}

func TestElement_String(t *testing.T) {
	if fmt.Sprint(skiplist(1,2).Front()) != "1:2" {
		t.Fail()
	}
}

func TestNew(t *testing.T) {
	// Verify the injected random number generator is used.
	s := New(less, nil)
	s1 := New(less, rand.New(rand.NewSource(1)))
	s42 := New(less, rand.New(rand.NewSource(42)))
	for i:=0; i<32; i++ {
		s.Insert(i,i)
		s1.Insert(i,i)
		s42.Insert(i,i)
	}
	v := s.Visualization()
	v1 := s1.Visualization()
	v42 := s42.Visualization()
	if v == v1 {
		t.Error("Seed did not change behaviour")
	} else if v != v42 {
		t.Error("Default seed is not 42.")
	}
}

func TestSkiplist_Front(t *testing.T) {
	s := skiplist (1,3)
	if s.Front().Key().(int) != 1 {
		t.Fail()
	}
}

func TestSkiplist_Insert(t *testing.T) {
	if skiplist(1, 10).String() != "{1:2 2:4 3:6 4:8 5:10 6:12 7:14 8:16 9:18 10:20}" {
		t.Fail()
	}
}

func BenchmarkSkiplist_Insert(b *testing.B) {
	s := New(less, nil)
	for i:=0; i<b.N; i++ {
		s.Insert(i,i)
	}
}

func TestSkiplist_Remove(t *testing.T) {
	s := skiplist(0,10)
	if s.Remove(-1) != nil || s.Remove(11) != nil {
		t.Error("Removing nonexistant key should fail.")
	}
	for i:= range shuffleRange(0,10) {
		e := s.Remove(i)
		if e == nil {
			t.Error("nil")
		}
		if e.Key().(int) != i {
			t.Error("bad key")
		}
		if e.Value.(int) != 2*i {
			t.Error("bad value")
		}
	}
	if s.Len() != 0 {
		t.Error("nonzero len")
	}
}

func TestSkiplist_RemoveN(t *testing.T) {
	s := skiplist(0,10)
	keys := shuffleRange(0,10)
	cnt := 11
	for _,key := range(keys) {
		found, pos := s.Find(key)
		t.Logf("Removing key=%v at pos=%v", key, pos)
		t.Log(key, found, pos)
		t.Log("\n" + s.Visualization())
		e := s.RemoveN(pos)
		if e == nil {
			t.Error("nil returned")
		} else if found != e {
			t.Error("Wrong removed")
		} else if e.Key().(int) != key {
			t.Error("bad Key()")
		} else if e.Value.(int) != 2*key {
			t.Error("bad Value")
		}
		cnt--
		l := s.Len()
		if l != cnt {
			t.Error ("bad Len()=", l, "!=", cnt)
		}
	}
}

func TestSkiplist_Find(t *testing.T) {
	s := skiplist(0, 9)
	for i := s.Len()-1; i>=0; i-- {
		e, pos := s.Find(i)
		if e == nil {
			t.Error("nil")
		} else if e != s.FindN(pos) {
			t.Error("bad pos")
		} else if e.Key().(int) != i {
			t.Error("bad Key")
		} else if e.Value.(int) != 2*i {
			t.Error ("bad Value")
		}
	}
}

func TestSkiplist_Len(t *testing.T) {
	s := skiplist(0, 4)
	if s.Len() != 5 {
		t.Fail()
	}
}

func TestSkiplist_FindN(t *testing.T) {
	s := skiplist(0, 9)
	for i := s.Len()-1; i>=0; i-- {
		e := s.FindN(i)
		if e == nil {
			t.Error("nil")
		} else if e.Key().(int) != i {
			t.Error("bad Key")
		} else if e.Value.(int) != 2*i {
			t.Error ("bad Value")
		}
	}
}

func ExampleSkiplist_String() {
	skip := New(less, nil).Insert(1, 10).Insert(2, 20).Insert(3, 30)
	fmt.Println(skip)
	// Output: {1:10 2:20 3:30}
}

func ExampleVisualization() {
	s := New(less, nil)
	for i := 0; i < 64; i++ {
		s.Insert(i, i)
	}
	fmt.Println(s.Visualization())
	// Output:
	// L6 ---------------------------------------------------------------->
	// L5 ---------------------------------------------------->----------->
	// L4 -------------------------->------------------------->----------->
	// L3 -------------->----------->---->---->---------->---->->--------->
	// L2 --->--->--->-->----->->--->>->->->-->-->----->->---->->--------->
	// L1 --->--->--->>->>>>-->>>>-->>->->>>>->>>>>>--->>>--->>->>>--->-->>
	// L0 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	//    0000000000000000111111111111111122222222222222223333333333333333
	//    0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
}

func arrow(cnt int) (s string) {
	switch {
	case cnt > 1:
		return strings.Repeat("-", cnt-1) + ">"
	case cnt == 1:
		return ">"
	}
	return "X"
}

func (l *Skiplist) Visualization() (s string) {
	for level := len(l.links) - 1; level >= 0; level-- {
		s += fmt.Sprintf("L%d ", level)
		w := l.links[level].width
		s += arrow(w)
		for n := l.links[level].to; n != nil; n = n.links[level].to {
			w = n.links[level].width
			s += arrow(w)
		}
		s += "\n"
	}
	s += "   "
	for n := l.links[0].to; n != nil; n = n.links[0].to {
		s += fmt.Sprintf("%x", n.key.(int)>>4&0xf)
	}
	s += "\n   "
	for n := l.links[0].to; n != nil; n = n.links[0].to {
		s += fmt.Sprintf("%x", n.key.(int)&0xf)
	}
	return string(s)
}
<commit_msg>Add BenchmarkSkiplist_Remove (2684 ns/op)<commit_after>package skiplist

import (
	"fmt"
	"math/rand"
	"strings"
	"testing"
)

//
// Utility functions
//

func less(a, b interface{}) bool {
	return a.(int) < b.(int)
}

func shuffleRange(min, max int) []int {
	a := make ([]int, max - min + 1)
	for i := range(a) {
		a[i] = min+i
	}
	for i := range(a) {
		other := rand.Intn(max-min+1)
		a[i], a[other] = a[other], a[i]
	}
	return a
}

func skiplist(min, max int) *Skiplist {
	s := New(less, nil)
	for _, v := range shuffleRange(min,max) {
		s.Insert (v, 2*v)
	}
	return s
}

//
// Benchmarks, examples, and Tests
//

func TestSkiplist(t *testing.T) {
	s := skiplist(1, 20)
	i := 1
	for e := s.Front(); e != nil; e = e.Next() {
		if e.Key().(int) != i || e.Value.(int) != 2*i {
			t.Fail()
		}
		i++
	}
}

func TestElement_Key(t *testing.T) {
	e := skiplist(1,3).Front()
	for i := 1; i<=3; i++ {
		if e == nil || e.Key().(int) != i {
			t.Fail()
		}
		e = e.Next()
	}
}

func ExampleElement_Next() {
	s := New(less, nil).Insert(0, 0).Insert(1, 2).Insert(2, 4).Insert(3, 6)
	for e := s.Front(); e != nil; e = e.Next() {
		fmt.Print(e, " ")
	}
	// Output: 0:0 1:2 2:4 3:6
}

func TestElement_String(t *testing.T) {
	if fmt.Sprint(skiplist(1,2).Front()) != "1:2" {
		t.Fail()
	}
}

func TestNew(t *testing.T) {
	// Verify the injected random number generator is used.
	s := New(less, nil)
	s1 := New(less, rand.New(rand.NewSource(1)))
	s42 := New(less, rand.New(rand.NewSource(42)))
	for i:=0; i<32; i++ {
		s.Insert(i,i)
		s1.Insert(i,i)
		s42.Insert(i,i)
	}
	v := s.Visualization()
	v1 := s1.Visualization()
	v42 := s42.Visualization()
	if v == v1 {
		t.Error("Seed did not change behaviour")
	} else if v != v42 {
		t.Error("Default seed is not 42.")
	}
}

func TestSkiplist_Front(t *testing.T) {
	s := skiplist (1,3)
	if s.Front().Key().(int) != 1 {
		t.Fail()
	}
}

func TestSkiplist_Insert(t *testing.T) {
	if skiplist(1, 10).String() != "{1:2 2:4 3:6 4:8 5:10 6:12 7:14 8:16 9:18 10:20}" {
		t.Fail()
	}
}

func BenchmarkSkiplist_Insert(b *testing.B) {
	b.StopTimer()
	s := New(less, nil)
	b.StartTimer()
	for i:=0; i<b.N; i++ {
		s.Insert(i,i)
	}
}

func BenchmarkSkiplist_Remove(b *testing.B) {
	b.StopTimer()
	s := skiplist(0, b.N-1)
	a := shuffleRange (0, b.N-1)
	b.StartTimer()
	for _, key := range a {
		s.Remove(key)
	}
}

func TestSkiplist_Remove(t *testing.T) {
	s := skiplist(0,10)
	if s.Remove(-1) != nil || s.Remove(11) != nil {
		t.Error("Removing nonexistant key should fail.")
	}
	for i:= range shuffleRange(0,10) {
		e := s.Remove(i)
		if e == nil {
			t.Error("nil")
		}
		if e.Key().(int) != i {
			t.Error("bad key")
		}
		if e.Value.(int) != 2*i {
			t.Error("bad value")
		}
	}
	if s.Len() != 0 {
		t.Error("nonzero len")
	}
}

func TestSkiplist_RemoveN(t *testing.T) {
	s := skiplist(0,10)
	keys := shuffleRange(0,10)
	cnt := 11
	for _,key := range(keys) {
		found, pos := s.Find(key)
		t.Logf("Removing key=%v at pos=%v", key, pos)
		t.Log(key, found, pos)
		t.Log("\n" + s.Visualization())
		e := s.RemoveN(pos)
		if e == nil {
			t.Error("nil returned")
		} else if found != e {
			t.Error("Wrong removed")
		} else if e.Key().(int) != key {
			t.Error("bad Key()")
		} else if e.Value.(int) != 2*key {
			t.Error("bad Value")
		}
		cnt--
		l := s.Len()
		if l != cnt {
			t.Error ("bad Len()=", l, "!=", cnt)
		}
	}
}

func TestSkiplist_Find(t *testing.T) {
	s := skiplist(0, 9)
	for i := s.Len()-1; i>=0; i-- {
		e, pos := s.Find(i)
		if e == nil {
			t.Error("nil")
		} else if e != s.FindN(pos) {
			t.Error("bad pos")
		} else if e.Key().(int) != i {
			t.Error("bad Key")
		} else if e.Value.(int) != 2*i {
			t.Error ("bad Value")
		}
	}
}

func TestSkiplist_Len(t *testing.T) {
	s := skiplist(0, 4)
	if s.Len() != 5 {
		t.Fail()
	}
}

func TestSkiplist_FindN(t *testing.T) {
	s := skiplist(0, 9)
	for i := s.Len()-1; i>=0; i-- {
		e := s.FindN(i)
		if e == nil {
			t.Error("nil")
		} else if e.Key().(int) != i {
			t.Error("bad Key")
		} else if e.Value.(int) != 2*i {
			t.Error ("bad Value")
		}
	}
}

func ExampleSkiplist_String() {
	skip := New(less, nil).Insert(1, 10).Insert(2, 20).Insert(3, 30)
	fmt.Println(skip)
	// Output: {1:10 2:20 3:30}
}

func ExampleVisualization() {
	s := New(less, nil)
	for i := 0; i < 64; i++ {
		s.Insert(i, i)
	}
	fmt.Println(s.Visualization())
	// Output:
	// L6 ---------------------------------------------------------------->
	// L5 ---------------------------------------------------->----------->
	// L4 -------------------------->------------------------->----------->
	// L3 -------------->----------->---->---->---------->---->->--------->
	// L2 --->--->--->-->----->->--->>->->->-->-->----->->---->->--------->
	// L1 --->--->--->>->>>>-->>>>-->>->->>>>->>>>>>--->>>--->>->>>--->-->>
	// L0 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	//    0000000000000000111111111111111122222222222222223333333333333333
	//    0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
}

func arrow(cnt int) (s string) {
	switch {
	case cnt > 1:
		return strings.Repeat("-", cnt-1) + ">"
	case cnt == 1:
		return ">"
	}
	return "X"
}

func (l *Skiplist) Visualization() (s string) {
	for level := len(l.links) - 1; level >= 0; level-- {
		s += fmt.Sprintf("L%d ", level)
		w := l.links[level].width
		s += arrow(w)
		for n := l.links[level].to; n != nil; n = n.links[level].to {
			w = n.links[level].width
			s += arrow(w)
		}
		s += "\n"
	}
	s += "   "
	for n := l.links[0].to; n != nil; n = n.links[0].to {
		s += fmt.Sprintf("%x", n.key.(int)>>4&0xf)
	}
	s += "\n   "
	for n := l.links[0].to; n != nil; n = n.links[0].to {
		s += fmt.Sprintf("%x", n.key.(int)&0xf)
	}
	return string(s)
}
<|endoftext|>


<commit_before>package slackapi

import (
	"encoding/json"
	"testing"
)

func CheckResponse(t *testing.T, x interface{}, y string) {
	out, err := json.Marshal(x)
	if err != nil {
		t.Fatal("json fromat;", err)
	}
	if string(out) != y {
		t.Fatalf("invalid json response;\n- %s\n+ %s\n", y, out)
	}
}

func TestAPITest(t *testing.T) {
	s := New()
	x := s.APITest()
	y := `{"ok":true}`
	CheckResponse(t, x, y)
}
<commit_msg>Remove api.test unit test due to API uncertanties<commit_after>package slackapi

import (
	"encoding/json"
	"testing"
)

func CheckResponse(t *testing.T, x interface{}, y string) {
	out, err := json.Marshal(x)
	if err != nil {
		t.Fatal("json fromat;", err)
	}
	if string(out) != y {
		t.Fatalf("invalid json response;\n- %s\n+ %s\n", y, out)
	}
}
<|endoftext|>


<commit_before>package slices

import "reflect"

func FilterInPlace(sl interface{}, f func(interface{}) bool) {
	v := reflect.ValueOf(sl).Elem()
	j := 0
	for i := 0; i < v.Len(); i++ {
		e := v.Index(i)
		if f(e.Interface()) {
			v.Index(j).Set(e)
			j++
		}
	}
	v.SetLen(j)
}
<commit_msg>slices.FilterInPlace: Take a typed function and a pointer to the value<commit_after>package slices

import "reflect"

func FilterInPlace(sl interface{}, f interface{}) {
	v := reflect.ValueOf(sl).Elem()
	j := 0
	for i := 0; i < v.Len(); i++ {
		e := v.Index(i)
		if reflect.ValueOf(f).Call([]reflect.Value{e.Addr()})[0].Bool() {
			v.Index(j).Set(e)
			j++
		}
	}
	v.SetLen(j)
}
<|endoftext|>


<commit_before>package xd

import (
	"fmt"
	"io"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"time"
	"xd/lib/config"
	"xd/lib/log"
	"xd/lib/rpc"
	"xd/lib/util"
	"xd/lib/version"
)

type httpRPC struct {
	w http.ResponseWriter
	r *http.Request
}

// Run runs XD main function
func Run() {

	var closers []io.Closer
	v := version.Version()
	conf := new(config.Config)
	fname := "torrents.ini"
	if len(os.Args) > 1 {
		fname = os.Args[1]
	}
	if fname == "-h" || fname == "--help" {
		fmt.Fprintf(os.Stdout, "usage: %s [config.ini]\n", os.Args[0])
		return
	}

	log.Infof("starting %s", v)
	var err error
	if !util.CheckFile(fname) {
		conf.Load(fname)
		err = conf.Save(fname)
		if err != nil {
			log.Errorf("failed to save initial config: %s", err)
			return
		}
		log.Infof("auto-generated new config at %s", fname)
	}
	err = conf.Load(fname)
	if err != nil {
		log.Errorf("failed to config %s", err)
		return
	}
	log.Infof("loaded config %s", fname)
	log.SetLevel(conf.Log.Level)

	if conf.Log.Pprof {
		go func() {
			pprofaddr := "127.0.0.1:6060"
			log.Infof("spawning pprof at %s", pprofaddr)
			log.Warnf("pprof exited: %s", http.ListenAndServe(pprofaddr, nil))
		}()
	}

	st := conf.Storage.CreateStorage()
	sw := conf.Bittorrent.CreateSwarm(st)
	closers = append(closers, sw, st)

	ts, err := st.OpenAllTorrents()
	if err != nil {
		log.Errorf("error opening all torrents: %s", err)
		return
	}
	for _, t := range ts {
		err = sw.AddTorrent(t, false)
		if err != nil {
			log.Errorf("error adding torrent: %s", err)
			return
		}
	}

	// torrent auto adder
	go func() {
		for sw.Running() {
			nt := st.PollNewTorrents()
			for _, t := range nt {
				sw.AddTorrent(t, true)
			}
			time.Sleep(time.Second)
		}
	}()

	// start rpc server
	if conf.RPC.Enabled {
		log.Infof("RPC enabled")
		srv := rpc.NewServer(sw)
		go func() {
			log.Errorf("rpc died: %s", http.ListenAndServe(conf.RPC.Bind, srv))
		}()

	}

	net := conf.I2P.CreateSession()
	// network mainloop
	go func() {
		for sw.Running() {
			log.Info("opening i2p session")
			err := net.Open()
			if err == nil {
				log.Infof("i2p session made, we are %s", net.B32Addr())
				err = sw.Run(net)
				if err != nil {
					log.Errorf("lost i2p session: %s", err)
				}
			} else {
				log.Errorf("failed to create i2p session: %s", err)
				time.Sleep(time.Second)
			}
		}
	}()
	closers = append(closers, net)
	sigchnl := make(chan os.Signal)
	signal.Notify(sigchnl, os.Interrupt)
	for {
		sig := <-sigchnl
		if sig == os.Interrupt {
			log.Info("Interrupted")
			for idx := range closers {
				closers[idx].Close()
			}
			return
		} else {
			log.Warnf("got wierd signal wtf: %s", sig)
			continue
		}
	}
}
<commit_msg>initialize storage backend<commit_after>package xd

import (
	"fmt"
	"io"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"time"
	"xd/lib/config"
	"xd/lib/log"
	"xd/lib/rpc"
	"xd/lib/util"
	"xd/lib/version"
)

type httpRPC struct {
	w http.ResponseWriter
	r *http.Request
}

// Run runs XD main function
func Run() {

	var closers []io.Closer
	v := version.Version()
	conf := new(config.Config)
	fname := "torrents.ini"
	if len(os.Args) > 1 {
		fname = os.Args[1]
	}
	if fname == "-h" || fname == "--help" {
		fmt.Fprintf(os.Stdout, "usage: %s [config.ini]\n", os.Args[0])
		return
	}

	log.Infof("starting %s", v)
	var err error
	if !util.CheckFile(fname) {
		conf.Load(fname)
		err = conf.Save(fname)
		if err != nil {
			log.Errorf("failed to save initial config: %s", err)
			return
		}
		log.Infof("auto-generated new config at %s", fname)
	}
	err = conf.Load(fname)
	if err != nil {
		log.Errorf("failed to config %s", err)
		return
	}
	log.Infof("loaded config %s", fname)
	log.SetLevel(conf.Log.Level)

	if conf.Log.Pprof {
		go func() {
			pprofaddr := "127.0.0.1:6060"
			log.Infof("spawning pprof at %s", pprofaddr)
			log.Warnf("pprof exited: %s", http.ListenAndServe(pprofaddr, nil))
		}()
	}

	st := conf.Storage.CreateStorage()
	err = st.Init()
	if err != nil {
		log.Errorf("error initializing storage: %s", err)
		return
	}
	sw := conf.Bittorrent.CreateSwarm(st)
	closers = append(closers, sw, st)

	ts, err := st.OpenAllTorrents()
	if err != nil {
		log.Errorf("error opening all torrents: %s", err)
		return
	}
	for _, t := range ts {
		err = sw.AddTorrent(t, false)
		if err != nil {
			log.Errorf("error adding torrent: %s", err)
			return
		}
	}

	// torrent auto adder
	go func() {
		for sw.Running() {
			nt := st.PollNewTorrents()
			for _, t := range nt {
				sw.AddTorrent(t, true)
			}
			time.Sleep(time.Second)
		}
	}()

	// start rpc server
	if conf.RPC.Enabled {
		log.Infof("RPC enabled")
		srv := rpc.NewServer(sw)
		go func() {
			log.Errorf("rpc died: %s", http.ListenAndServe(conf.RPC.Bind, srv))
		}()

	}

	net := conf.I2P.CreateSession()
	// network mainloop
	go func() {
		for sw.Running() {
			log.Info("opening i2p session")
			err := net.Open()
			if err == nil {
				log.Infof("i2p session made, we are %s", net.B32Addr())
				err = sw.Run(net)
				if err != nil {
					log.Errorf("lost i2p session: %s", err)
				}
			} else {
				log.Errorf("failed to create i2p session: %s", err)
				time.Sleep(time.Second)
			}
		}
	}()
	closers = append(closers, net)
	sigchnl := make(chan os.Signal)
	signal.Notify(sigchnl, os.Interrupt)
	for {
		sig := <-sigchnl
		if sig == os.Interrupt {
			log.Info("Interrupted")
			for idx := range closers {
				closers[idx].Close()
			}
			return
		} else {
			log.Warnf("got wierd signal wtf: %s", sig)
			continue
		}
	}
}
<|endoftext|>


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

//+build linux

package main

// this implements /init of stage1/nspawn+systemd

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"syscall"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"

	"github.com/coreos/rkt/common"
	"github.com/coreos/rkt/networking"
	"github.com/coreos/rkt/pkg/sys"
)

const (
	// Path to systemd-nspawn binary within the stage1 rootfs
	nspawnBin = "/usr/bin/systemd-nspawn"
	// Path to the interpreter within the stage1 rootfs
	interpBin = "/usr/lib/ld-linux-x86-64.so.2"
	// Path to the localtime file/symlink in host
	localtimePath = "/etc/localtime"
)

// mirrorLocalZoneInfo tries to reproduce the /etc/localtime target in stage1/ to satisfy systemd-nspawn
func mirrorLocalZoneInfo(root string) {
	zif, err := os.Readlink(localtimePath)
	if err != nil {
		return
	}

	// On some systems /etc/localtime is a relative symlink, make it absolute
	if !filepath.IsAbs(zif) {
		zif = filepath.Join(filepath.Dir(localtimePath), zif)
		zif = filepath.Clean(zif)
	}

	src, err := os.Open(zif)
	if err != nil {
		return
	}
	defer src.Close()

	destp := filepath.Join(common.Stage1RootfsPath(root), zif)

	if err = os.MkdirAll(filepath.Dir(destp), 0755); err != nil {
		return
	}

	dest, err := os.OpenFile(destp, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return
	}
	defer dest.Close()

	_, _ = io.Copy(dest, src)
}

var (
	debug       bool
	privNet     bool
	interactive bool
)

func init() {
	flag.BoolVar(&debug, "debug", false, "Run in debug mode")
	flag.BoolVar(&privNet, "private-net", false, "Setup private network")
	flag.BoolVar(&interactive, "interactive", false, "The pod is interactive")

	// this ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

// getArgsEnv returns the nspawn args and env according to the usr used
func getArgsEnv(p *Pod, debug bool) ([]string, []string, error) {
	args := []string{}
	env := os.Environ()

	flavor, err := os.Readlink(filepath.Join(common.Stage1RootfsPath(p.Root), "flavor"))
	if err != nil {
		return nil, nil, fmt.Errorf("unable to determine stage1 flavor: %v", err)
	}

	switch flavor {
	case "coreos":
		// when running the coreos-derived stage1 with unpatched systemd-nspawn we need some ld-linux hackery
		args = append(args, filepath.Join(common.Stage1RootfsPath(p.Root), interpBin))
		args = append(args, filepath.Join(common.Stage1RootfsPath(p.Root), nspawnBin))
		args = append(args, "--boot")              // Launch systemd in the pod
		args = append(args, "--register", "false") // We cannot assume the host system is running systemd
		// TODO(vc): we should leave registration enabled if systemd is running on the host,
		// but it needs to be sufficiently new systemd or registration will fail.

		env = append(env, "LD_PRELOAD="+filepath.Join(common.Stage1RootfsPath(p.Root), "fakesdboot.so"))
		env = append(env, "LD_LIBRARY_PATH="+filepath.Join(common.Stage1RootfsPath(p.Root), "usr/lib"))

	case "src":
		args = append(args, filepath.Join(common.Stage1RootfsPath(p.Root), nspawnBin))
		args = append(args, "--boot") // Launch systemd in the pod
		out, err := os.Getwd()
		if err != nil {
			return nil, nil, err
		}
		lfd, err := common.GetRktLockFD()
		if err != nil {
			return nil, nil, err
		}
		args = append(args, fmt.Sprintf("--pid-file=%v", filepath.Join(out, "pid")))
		args = append(args, fmt.Sprintf("--keep-fd=%v", lfd))
	default:
		return nil, nil, fmt.Errorf("unrecognized stage1 flavor: %q", flavor)
	}

	if !debug {
		args = append(args, "--quiet") // silence most nspawn output (log_warning is currently not covered by this)
	}

	nsargs, err := p.PodToNspawnArgs()
	if err != nil {
		return nil, nil, fmt.Errorf("Failed to generate nspawn args: %v", err)
	}
	args = append(args, nsargs...)

	// Arguments to systemd
	args = append(args, "--")
	args = append(args, "--default-standard-output=tty") // redirect all service logs straight to tty
	if !debug {
		args = append(args, "--log-target=null") // silence systemd output inside pod
		args = append(args, "--show-status=0")   // silence systemd initialization status output
	}

	return args, env, nil
}

func withClearedCloExec(lfd int, f func() error) error {
	err := sys.CloseOnExec(lfd, false)
	if err != nil {
		return err
	}
	defer sys.CloseOnExec(lfd, true)

	return f()
}

func forwardedPorts(pod *Pod) ([]networking.ForwardedPort, error) {
	fps := []networking.ForwardedPort{}

	for _, ep := range pod.Manifest.Ports {
		n := ""
		fp := networking.ForwardedPort{}

		for an, a := range pod.Apps {
			for _, p := range a.App.Ports {
				if p.Name == ep.Name {
					if n == "" {
						fp.Protocol = p.Protocol
						fp.HostPort = ep.HostPort
						fp.PodPort = p.Port
						n = an
					} else {
						return nil, fmt.Errorf("Ambiguous exposed port in PodManifest: %q and %q both define port %q", n, an, p.Name)
					}
				}
			}
		}

		if n == "" {
			return nil, fmt.Errorf("Port name %q is not defined by any apps", ep.Name)
		}

		fps = append(fps, fp)
	}

	// TODO(eyakubovich): validate that there're no conflicts

	return fps, nil
}

func stage1() int {
	uuid, err := types.NewUUID(flag.Arg(0))
	if err != nil {
		fmt.Fprintln(os.Stderr, "UUID is missing or malformed")
		return 1
	}

	root := "."
	p, err := LoadPod(root, uuid)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load pod: %v\n", err)
		return 1
	}

	// set close-on-exec flag on RKT_LOCK_FD so it gets correctly closed when invoking
	// network plugins
	lfd, err := common.GetRktLockFD()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get rkt lock fd: %v\n", err)
		return 1
	}

	if err := sys.CloseOnExec(lfd, true); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to set FD_CLOEXEC on rkt lock: %v\n", err)
		return 1
	}

	mirrorLocalZoneInfo(p.Root)

	if privNet {
		fps, err := forwardedPorts(p)
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			return 6
		}

		n, err := networking.Setup(root, p.UUID, fps)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to setup network: %v\n", err)
			return 6
		}
		defer n.Teardown()

		if err = n.Save(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to save networking state %v\n", err)
			return 6
		}

		p.MetadataServiceURL = common.MetadataServicePublicURL(n.GetDefaultHostIP())

		if err = registerPod(p, n.GetDefaultIP()); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to register pod: %v\n", err)
			return 6
		}
		defer unregisterPod(p)
	}

	if err = p.PodToSystemd(interactive); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to configure systemd: %v\n", err)
		return 2
	}

	args, env, err := getArgsEnv(p, debug)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get execution parameters: %v\n", err)
		return 3
	}

	var execFn func() error

	if privNet {
		cmd := exec.Cmd{
			Path:   args[0],
			Args:   args,
			Stdin:  os.Stdin,
			Stdout: os.Stdout,
			Stderr: os.Stderr,
			Env:    env,
		}
		execFn = cmd.Run
	} else {
		execFn = func() error {
			return syscall.Exec(args[0], args, env)
		}
	}

	err = withClearedCloExec(lfd, execFn)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to execute nspawn: %v\n", err)
		return 5
	}

	return 0
}

func main() {
	flag.Parse()

	if !debug {
		log.SetOutput(ioutil.Discard)
	}

	// move code into stage1() helper so defered fns get run
	os.Exit(stage1())
}
<commit_msg>stage1: systemd: register only if systemd on the host supports it<commit_after>// Copyright 2014 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//+build linux

package main

// this implements /init of stage1/nspawn+systemd

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"syscall"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/godbus/dbus"
	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/godbus/dbus/introspect"

	"github.com/coreos/rkt/common"
	"github.com/coreos/rkt/networking"
	"github.com/coreos/rkt/pkg/sys"
)

const (
	// Path to systemd-nspawn binary within the stage1 rootfs
	nspawnBin = "/usr/bin/systemd-nspawn"
	// Path to the interpreter within the stage1 rootfs
	interpBin = "/usr/lib/ld-linux-x86-64.so.2"
	// Path to the localtime file/symlink in host
	localtimePath = "/etc/localtime"
)

// mirrorLocalZoneInfo tries to reproduce the /etc/localtime target in stage1/ to satisfy systemd-nspawn
func mirrorLocalZoneInfo(root string) {
	zif, err := os.Readlink(localtimePath)
	if err != nil {
		return
	}

	// On some systems /etc/localtime is a relative symlink, make it absolute
	if !filepath.IsAbs(zif) {
		zif = filepath.Join(filepath.Dir(localtimePath), zif)
		zif = filepath.Clean(zif)
	}

	src, err := os.Open(zif)
	if err != nil {
		return
	}
	defer src.Close()

	destp := filepath.Join(common.Stage1RootfsPath(root), zif)

	if err = os.MkdirAll(filepath.Dir(destp), 0755); err != nil {
		return
	}

	dest, err := os.OpenFile(destp, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return
	}
	defer dest.Close()

	_, _ = io.Copy(dest, src)
}

var (
	debug       bool
	privNet     bool
	interactive bool
)

func init() {
	flag.BoolVar(&debug, "debug", false, "Run in debug mode")
	flag.BoolVar(&privNet, "private-net", false, "Setup private network")
	flag.BoolVar(&interactive, "interactive", false, "The pod is interactive")

	// this ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

// machinedRegister checks if nspawn should register the pod to machined
func machinedRegister() bool {
	// machined has a D-Bus interface following versioning guidelines, see:
	// http://www.freedesktop.org/wiki/Software/systemd/machined/
	// Therefore we can just check if the D-Bus method we need exists and we
	// don't need to check the signature.
	var found int

	conn, err := dbus.SystemBus()
	if err != nil {
		return false
	}
	node, err := introspect.Call(conn.Object("org.freedesktop.machine1", "/org/freedesktop/machine1"))
	if err != nil {
		return false
	}
	for _, iface := range node.Interfaces {
		if iface.Name != "org.freedesktop.machine1.Manager" {
			continue
		}
		// machined v215 supports methods "RegisterMachine" and "CreateMachine" called by nspawn v215.
		// machined v216+ (since commit 5aa4bb) additionally supports methods "CreateMachineWithNetwork"
		// and "RegisterMachineWithNetwork", called by nspawn v216+.
		// TODO(alban): write checks for both versions in order to register on machined v215?
		for _, method := range iface.Methods {
			if method.Name == "CreateMachineWithNetwork" || method.Name == "RegisterMachineWithNetwork" {
				found++
			}
		}
		break
	}
	return found == 2
}

// getArgsEnv returns the nspawn args and env according to the usr used
func getArgsEnv(p *Pod, debug bool) ([]string, []string, error) {
	args := []string{}
	env := os.Environ()

	flavor, err := os.Readlink(filepath.Join(common.Stage1RootfsPath(p.Root), "flavor"))
	if err != nil {
		return nil, nil, fmt.Errorf("unable to determine stage1 flavor: %v", err)
	}

	switch flavor {
	case "coreos":
		// when running the coreos-derived stage1 with unpatched systemd-nspawn we need some ld-linux hackery
		args = append(args, filepath.Join(common.Stage1RootfsPath(p.Root), interpBin))
		args = append(args, filepath.Join(common.Stage1RootfsPath(p.Root), nspawnBin))
		args = append(args, "--boot") // Launch systemd in the pod

		// Note: the coreos flavor uses systemd-nspawn v215 but machinedRegister()
		// checks for the nspawn registration method used since v216. So we will
		// not register when the host has systemd v215.
		if machinedRegister() {
			args = append(args, fmt.Sprintf("--register=true"))
		} else {
			args = append(args, fmt.Sprintf("--register=false"))
		}

		env = append(env, "LD_PRELOAD="+filepath.Join(common.Stage1RootfsPath(p.Root), "fakesdboot.so"))
		env = append(env, "LD_LIBRARY_PATH="+filepath.Join(common.Stage1RootfsPath(p.Root), "usr/lib"))

	case "src":
		args = append(args, filepath.Join(common.Stage1RootfsPath(p.Root), nspawnBin))
		args = append(args, "--boot") // Launch systemd in the pod
		out, err := os.Getwd()
		if err != nil {
			return nil, nil, err
		}
		lfd, err := common.GetRktLockFD()
		if err != nil {
			return nil, nil, err
		}
		args = append(args, fmt.Sprintf("--pid-file=%v", filepath.Join(out, "pid")))
		args = append(args, fmt.Sprintf("--keep-fd=%v", lfd))
		if machinedRegister() {
			args = append(args, fmt.Sprintf("--register=true"))
		} else {
			args = append(args, fmt.Sprintf("--register=false"))
		}
	default:
		return nil, nil, fmt.Errorf("unrecognized stage1 flavor: %q", flavor)
	}

	if !debug {
		args = append(args, "--quiet") // silence most nspawn output (log_warning is currently not covered by this)
	}

	nsargs, err := p.PodToNspawnArgs()
	if err != nil {
		return nil, nil, fmt.Errorf("Failed to generate nspawn args: %v", err)
	}
	args = append(args, nsargs...)

	// Arguments to systemd
	args = append(args, "--")
	args = append(args, "--default-standard-output=tty") // redirect all service logs straight to tty
	if !debug {
		args = append(args, "--log-target=null") // silence systemd output inside pod
		args = append(args, "--show-status=0")   // silence systemd initialization status output
	}

	return args, env, nil
}

func withClearedCloExec(lfd int, f func() error) error {
	err := sys.CloseOnExec(lfd, false)
	if err != nil {
		return err
	}
	defer sys.CloseOnExec(lfd, true)

	return f()
}

func forwardedPorts(pod *Pod) ([]networking.ForwardedPort, error) {
	fps := []networking.ForwardedPort{}

	for _, ep := range pod.Manifest.Ports {
		n := ""
		fp := networking.ForwardedPort{}

		for an, a := range pod.Apps {
			for _, p := range a.App.Ports {
				if p.Name == ep.Name {
					if n == "" {
						fp.Protocol = p.Protocol
						fp.HostPort = ep.HostPort
						fp.PodPort = p.Port
						n = an
					} else {
						return nil, fmt.Errorf("Ambiguous exposed port in PodManifest: %q and %q both define port %q", n, an, p.Name)
					}
				}
			}
		}

		if n == "" {
			return nil, fmt.Errorf("Port name %q is not defined by any apps", ep.Name)
		}

		fps = append(fps, fp)
	}

	// TODO(eyakubovich): validate that there're no conflicts

	return fps, nil
}

func stage1() int {
	uuid, err := types.NewUUID(flag.Arg(0))
	if err != nil {
		fmt.Fprintln(os.Stderr, "UUID is missing or malformed")
		return 1
	}

	root := "."
	p, err := LoadPod(root, uuid)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load pod: %v\n", err)
		return 1
	}

	// set close-on-exec flag on RKT_LOCK_FD so it gets correctly closed when invoking
	// network plugins
	lfd, err := common.GetRktLockFD()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get rkt lock fd: %v\n", err)
		return 1
	}

	if err := sys.CloseOnExec(lfd, true); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to set FD_CLOEXEC on rkt lock: %v\n", err)
		return 1
	}

	mirrorLocalZoneInfo(p.Root)

	if privNet {
		fps, err := forwardedPorts(p)
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			return 6
		}

		n, err := networking.Setup(root, p.UUID, fps)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to setup network: %v\n", err)
			return 6
		}
		defer n.Teardown()

		if err = n.Save(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to save networking state %v\n", err)
			return 6
		}

		p.MetadataServiceURL = common.MetadataServicePublicURL(n.GetDefaultHostIP())

		if err = registerPod(p, n.GetDefaultIP()); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to register pod: %v\n", err)
			return 6
		}
		defer unregisterPod(p)
	}

	if err = p.PodToSystemd(interactive); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to configure systemd: %v\n", err)
		return 2
	}

	args, env, err := getArgsEnv(p, debug)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get execution parameters: %v\n", err)
		return 3
	}

	var execFn func() error

	if privNet {
		cmd := exec.Cmd{
			Path:   args[0],
			Args:   args,
			Stdin:  os.Stdin,
			Stdout: os.Stdout,
			Stderr: os.Stderr,
			Env:    env,
		}
		execFn = cmd.Run
	} else {
		execFn = func() error {
			return syscall.Exec(args[0], args, env)
		}
	}

	err = withClearedCloExec(lfd, execFn)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to execute nspawn: %v\n", err)
		return 5
	}

	return 0
}

func main() {
	flag.Parse()

	if !debug {
		log.SetOutput(ioutil.Discard)
	}

	// move code into stage1() helper so defered fns get run
	os.Exit(stage1())
}
<|endoftext|>


<commit_before>// +build linux

package store

import (
	"runtime"
	"testing"
)

func StoreLinux__cadir(t *testing.T) {
	// just grab the linuxStore and make sure it has a cadir member
	s := platform()
	if s.ca == nil || s.ca.empty() {
		t.Error("no cadir found on platform: %s", runtime.GOOS)
	}
}
<commit_msg>store/linux: fix from go vet<commit_after>// +build linux

package store

import (
	"runtime"
	"testing"
)

func StoreLinux__cadir(t *testing.T) {
	// just grab the linuxStore and make sure it has a cadir member
	s := platform()
	if s.ca == nil || s.ca.empty() {
		t.Errorf("no cadir found on platform: %s", runtime.GOOS)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package freebsd

import (
	"github.com/google/syzkaller/prog"
)

func initTarget(target *prog.Target) {
	arch := &arch{
		mmapSyscall:   target.SyscallMap["mmap"],
		PROT_READ:     target.ConstMap["PROT_READ"],
		PROT_WRITE:    target.ConstMap["PROT_WRITE"],
		MAP_ANONYMOUS: target.ConstMap["MAP_ANONYMOUS"],
		MAP_PRIVATE:   target.ConstMap["MAP_PRIVATE"],
		MAP_FIXED:     target.ConstMap["MAP_FIXED"],
		S_IFREG:       target.ConstMap["S_IFREG"],
		S_IFCHR:       target.ConstMap["S_IFCHR"],
		S_IFBLK:       target.ConstMap["S_IFBLK"],
		S_IFIFO:       target.ConstMap["S_IFIFO"],
		S_IFSOCK:      target.ConstMap["S_IFSOCK"],
	}

	target.PageSize = pageSize
	target.DataOffset = dataOffset
	target.MmapSyscall = arch.mmapSyscall
	target.MakeMmap = arch.makeMmap
	target.AnalyzeMmap = arch.analyzeMmap
	target.SanitizeCall = arch.sanitizeCall
}

const (
	pageSize   = 4 << 10
	dataOffset = 512 << 20
	invalidFD  = ^uint64(0)
)

type arch struct {
	mmapSyscall         *prog.Syscall
	clockGettimeSyscall *prog.Syscall

	PROT_READ     uint64
	PROT_WRITE    uint64
	MAP_ANONYMOUS uint64
	MAP_PRIVATE   uint64
	MAP_FIXED     uint64
	S_IFREG       uint64
	S_IFCHR       uint64
	S_IFBLK       uint64
	S_IFIFO       uint64
	S_IFSOCK      uint64
}

// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range.
func (arch *arch) makeMmap(start, npages uint64) *prog.Call {
	meta := arch.mmapSyscall
	return &prog.Call{
		Meta: meta,
		Args: []prog.Arg{
			prog.MakePointerArg(meta.Args[0], start, 0, npages, nil),
			prog.MakeConstArg(meta.Args[1], npages*pageSize),
			prog.MakeConstArg(meta.Args[2], arch.PROT_READ|arch.PROT_WRITE),
			prog.MakeConstArg(meta.Args[3], arch.MAP_ANONYMOUS|arch.MAP_PRIVATE|arch.MAP_FIXED),
			prog.MakeResultArg(meta.Args[4], nil, invalidFD),
			prog.MakeConstArg(meta.Args[5], 0),
		},
		Ret: prog.MakeReturnArg(meta.Ret),
	}
}

func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
	switch c.Meta.Name {
	case "mmap":
		// Filter out only very wrong arguments.
		npages = c.Args[1].(*prog.ConstArg).Val / pageSize
		if npages == 0 {
			return
		}
		flags := c.Args[3].(*prog.ConstArg).Val
		fd := c.Args[4].(*prog.ResultArg).Val
		if flags&arch.MAP_ANONYMOUS == 0 && fd == invalidFD {
			return
		}
		start = c.Args[0].(*prog.PointerArg).PageIndex
		mapped = true
		return
	case "munmap":
		start = c.Args[0].(*prog.PointerArg).PageIndex
		npages = c.Args[1].(*prog.ConstArg).Val / pageSize
		mapped = false
		return
	default:
		return
	}
}

func (arch *arch) sanitizeCall(c *prog.Call) {
	switch c.Meta.CallName {
	case "mmap":
		// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
		c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
	case "mknod", "mknodat":
		pos := 1
		if c.Meta.CallName == "mknodat" {
			pos = 2
		}
		mode := c.Args[pos].(*prog.ConstArg)
		dev := c.Args[pos+1].(*prog.ConstArg)
		// Char and block devices read/write io ports, kernel memory and do other nasty things.
		// TODO: not required if executor drops privileges.
		switch mode.Val & (arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK) {
		case arch.S_IFREG, arch.S_IFIFO, arch.S_IFSOCK:
		case arch.S_IFBLK:
			// TODO(dvyukov): mknod dev argument is uint32,
			// but prog arguments contain not-truncated uint64 values,
			// so we can mistakenly assume that this is not loop, when it actually is.
			// This is not very harmful, but need to verify other arguments in this function.
			if dev.Val>>8 == 7 {
				break // loop
			}
			mode.Val &^= arch.S_IFBLK
			mode.Val |= arch.S_IFREG
		case arch.S_IFCHR:
			mode.Val &^= arch.S_IFCHR
			mode.Val |= arch.S_IFREG
		}
	case "exit":
		code := c.Args[0].(*prog.ConstArg)
		// These codes are reserved by executor.
		if code.Val%128 == 67 || code.Val%128 == 68 {
			code.Val = 1
		}
	}
}
<commit_msg>sys/freebsd: fix const name<commit_after>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package freebsd

import (
	"github.com/google/syzkaller/prog"
)

func initTarget(target *prog.Target) {
	arch := &arch{
		mmapSyscall: target.SyscallMap["mmap"],
		PROT_READ:   target.ConstMap["PROT_READ"],
		PROT_WRITE:  target.ConstMap["PROT_WRITE"],
		MAP_ANON:    target.ConstMap["MAP_ANON"],
		MAP_PRIVATE: target.ConstMap["MAP_PRIVATE"],
		MAP_FIXED:   target.ConstMap["MAP_FIXED"],
		S_IFREG:     target.ConstMap["S_IFREG"],
		S_IFCHR:     target.ConstMap["S_IFCHR"],
		S_IFBLK:     target.ConstMap["S_IFBLK"],
		S_IFIFO:     target.ConstMap["S_IFIFO"],
		S_IFSOCK:    target.ConstMap["S_IFSOCK"],
	}

	target.PageSize = pageSize
	target.DataOffset = dataOffset
	target.MmapSyscall = arch.mmapSyscall
	target.MakeMmap = arch.makeMmap
	target.AnalyzeMmap = arch.analyzeMmap
	target.SanitizeCall = arch.sanitizeCall
}

const (
	pageSize   = 4 << 10
	dataOffset = 512 << 20
	invalidFD  = ^uint64(0)
)

type arch struct {
	mmapSyscall         *prog.Syscall
	clockGettimeSyscall *prog.Syscall

	PROT_READ   uint64
	PROT_WRITE  uint64
	MAP_ANON    uint64
	MAP_PRIVATE uint64
	MAP_FIXED   uint64
	S_IFREG     uint64
	S_IFCHR     uint64
	S_IFBLK     uint64
	S_IFIFO     uint64
	S_IFSOCK    uint64
}

// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range.
func (arch *arch) makeMmap(start, npages uint64) *prog.Call {
	meta := arch.mmapSyscall
	return &prog.Call{
		Meta: meta,
		Args: []prog.Arg{
			prog.MakePointerArg(meta.Args[0], start, 0, npages, nil),
			prog.MakeConstArg(meta.Args[1], npages*pageSize),
			prog.MakeConstArg(meta.Args[2], arch.PROT_READ|arch.PROT_WRITE),
			prog.MakeConstArg(meta.Args[3], arch.MAP_ANON|arch.MAP_PRIVATE|arch.MAP_FIXED),
			prog.MakeResultArg(meta.Args[4], nil, invalidFD),
			prog.MakeConstArg(meta.Args[5], 0),
		},
		Ret: prog.MakeReturnArg(meta.Ret),
	}
}

func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
	switch c.Meta.Name {
	case "mmap":
		// Filter out only very wrong arguments.
		npages = c.Args[1].(*prog.ConstArg).Val / pageSize
		if npages == 0 {
			return
		}
		flags := c.Args[3].(*prog.ConstArg).Val
		fd := c.Args[4].(*prog.ResultArg).Val
		if flags&arch.MAP_ANON == 0 && fd == invalidFD {
			return
		}
		start = c.Args[0].(*prog.PointerArg).PageIndex
		mapped = true
		return
	case "munmap":
		start = c.Args[0].(*prog.PointerArg).PageIndex
		npages = c.Args[1].(*prog.ConstArg).Val / pageSize
		mapped = false
		return
	default:
		return
	}
}

func (arch *arch) sanitizeCall(c *prog.Call) {
	switch c.Meta.CallName {
	case "mmap":
		// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
		c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
	case "mknod", "mknodat":
		pos := 1
		if c.Meta.CallName == "mknodat" {
			pos = 2
		}
		mode := c.Args[pos].(*prog.ConstArg)
		dev := c.Args[pos+1].(*prog.ConstArg)
		// Char and block devices read/write io ports, kernel memory and do other nasty things.
		// TODO: not required if executor drops privileges.
		switch mode.Val & (arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK) {
		case arch.S_IFREG, arch.S_IFIFO, arch.S_IFSOCK:
		case arch.S_IFBLK:
			// TODO(dvyukov): mknod dev argument is uint32,
			// but prog arguments contain not-truncated uint64 values,
			// so we can mistakenly assume that this is not loop, when it actually is.
			// This is not very harmful, but need to verify other arguments in this function.
			if dev.Val>>8 == 7 {
				break // loop
			}
			mode.Val &^= arch.S_IFBLK
			mode.Val |= arch.S_IFREG
		case arch.S_IFCHR:
			mode.Val &^= arch.S_IFCHR
			mode.Val |= arch.S_IFREG
		}
	case "exit":
		code := c.Args[0].(*prog.ConstArg)
		// These codes are reserved by executor.
		if code.Val%128 == 67 || code.Val%128 == 68 {
			code.Val = 1
		}
	}
}
<|endoftext|>