<commit_before>// td4 ride format parser

package main

import (
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"math"
)

func hasLoop(n int) bool {
	return n>>7 == 1
}

// Set the loop bit.
func marshalLoop(hasLoop bool, n int) {
	if hasLoop {
		n |= (1 << 7)
	} else {
		n &= ^(1 << 7)
	}
}

type ControlFlags struct {
	UseMaximumTime             bool
	UseMinimumTime             bool
	SyncWithAdjacentStation    bool
	LeaveIfAnotherTrainArrives bool
	WaitForLoad                bool
	Load                       LoadType
}

func parseControlFlags(n int) *ControlFlags {
	return &ControlFlags{
		UseMaximumTime:             n>>7 == 1,
		UseMinimumTime:             n>>6 == 1,
		SyncWithAdjacentStation:    n>>5 == 1,
		LeaveIfAnotherTrainArrives: n>>4 == 1,
		WaitForLoad:                n>>3 == 1,
		Load:                       LoadType(n & 7),
	}
}

type RideType int
type VehicleType int
type LoadType int
type OperatingMode int
type SegmentType int

const (
	WOODEN_RIDE    RideType = iota
	STAND_UP_STEEL          = iota
	SUSPENDED               = iota
)

const (
	STEEL              VehicleType = iota
	STEEL_BACKWARDS                = iota
	WOODEN_VEHICLE                 = iota
	INVERTED                       = iota
	SUSPENDED_SWINGING             = iota
	LADYBIRD                       = iota
	STAND_UP                       = iota
)

const (
	MODE_NORMAL                  OperatingMode = 0x00
	MODE_CONTINUOUS_CIRCUIT                    = 0x01
	MODE_REVERSE_INCLINE_SHUTTLE               = 0x02
	MODE_POWERED_LAUNCH                        = 0x03
	MODE_SHUTTLE                               = 0x04
	MODE_BOAT_HIRE                             = 0x05
	MODE_UPWARD_LAUNCH                         = 0x06
	MODE_ROTATING_LIFT                         = 0x07
	MODE_STATION_TO_STATION                    = 0x08
)

const (
	LOAD_ONE_QUARTER    = 0
	LOAD_HALF           = 1
	LOAD_THREE_QUARTERS = 2
	LOAD_FULL           = 3
	LOAD_ANY            = 4
)

const (
	IDX_RIDE_TYPE      = 0
	IDX_VEHICLE_TYPE   = 1
	IDX_HAS_LOOP       = 2
	IDX_OPERATING_MODE = 0x06
	IDX_CONTROL_FLAG   = 0x23
	IDX_NUM_TRAINS     = 0x24
	IDX_CARS_PER_TRAIN = 0x25
	IDX_MIN_WAIT_TIME  = 0x26
	IDX_MAX_WAIT_TIME  = 0x27
	IDX_TRACK_DATA     = 0xc4
)

type Ride struct {
	RideType      RideType
	VehicleType   VehicleType
	HasLoop       bool
	OperatingMode OperatingMode
	ControlFlags  *ControlFlags
	NumTrains     int
	CarsPerTrain  int
	MinWaitTime   int
	MaxWaitTime   int
	TrackData     TrackData
}

type StationType int

const (
	STATION_ONE   StationType = 0
	STATION_TWO               = 1
	STATION_THREE             = 2
	STATION_FOUR              = 3
)

// computes sines in degrees
func sindeg(deg DirectionDelta) int {
	for ; deg >= 360; deg -= 360 {
	}
	if deg%180 == 0 {
		return 0
	} else if deg == 90 {
		return 1
	} else if deg == 270 {
		return -1
	} else {
		return int(math.Sin(float64(deg) * math.Pi / 180))
	}
}

// computes sines in degrees
func cosdeg(deg DirectionDelta) int {
	for ; deg >= 360; deg -= 360 {
	}
	if deg == 0 {
		return 1
	} else if deg == 90 || deg == 270 {
		return 0
	} else if deg == 180 {
		return -1
	} else {
		return int(math.Sin(float64(deg) * math.Pi / 180))
	}
}

//func Decrypt() {

// Take a compressed byte stream representing a ride and turn it into a Ride
// struct. Returns an error if the byte array is too short.
func Unmarshal(buf []byte, r Ride) error {
	if len(buf) < IDX_TRACK_DATA {
		return errors.New("buffer too short to be a ride")
	}
	r.RideType = RideType(buf[IDX_RIDE_TYPE])
	r.VehicleType = VehicleType(buf[IDX_VEHICLE_TYPE])
	r.HasLoop = hasLoop(int(buf[IDX_HAS_LOOP]))
	r.OperatingMode = OperatingMode(buf[IDX_OPERATING_MODE])
	r.ControlFlags = parseControlFlags(int(buf[IDX_CONTROL_FLAG]))
	r.NumTrains = int(buf[IDX_NUM_TRAINS])
	r.CarsPerTrain = int(buf[IDX_CARS_PER_TRAIN])
	r.MinWaitTime = int(buf[IDX_MIN_WAIT_TIME])
	r.MaxWaitTime = int(buf[IDX_MAX_WAIT_TIME])
	r.TrackData = parseTrackData(buf[IDX_TRACK_DATA:])
	return nil
}

func Marshal(r *Ride) ([]byte, error) {
	// at a minimum, rides have this much data
	bits := make([]byte, 0xc4)

	// This is a little bit tricky, and requires implementing the format
	// described in the tycoon technical depot, available here:
	// https://github.com/UnknownShadow200/RCTTechDepot-Archive/blob/master/td4.html
	bits[IDX_RIDE_TYPE] = byte(r.RideType)
	bits[IDX_VEHICLE_TYPE] = byte(r.VehicleType)
	//bits[IDX_HAS_LOOP] = byte(r.HasLoop)

	return bits, nil
}

var EndOfRide = errors.New("End of ride")

// Parse the serialized data into a TrackElement struct
// When the end of ride is encountered a EndOfRide error is returned
func parseElement(rawElement []byte) (te TrackElement, e error) {
	if len(rawElement) != 2 {
		return TrackElement{}, errors.New("invalid length for element input")
	}
	te.Segment = &TrackSegment{
		Type: SegmentType(rawElement[0]),
	}
	if te.Segment.Type == ELEM_END_OF_RIDE {
		return TrackElement{}, EndOfRide
	}
	q := int(rawElement[1])
	te.ChainLift = q>>7 == 1
	te.InvertedTrack = q>>6 == 1
	te.Station = q>>3 == 1
	te.StationNumber = q & 3

	te.BoostMagnitude = float32(q&15) * 7.6
	te.Rotation = (q&15)*45 - 180
	return
}

func parseTrackData(trackData []byte) TrackData {
	td := new(TrackData)
	for i := 0; i < len(trackData); i += 2 {
		elem, err := parseElement(trackData[i : i+2])
		if err != nil {
			if err == EndOfRide {
				break
			}
			panic(err)
		}
		td.Elements = append(td.Elements, elem)
	}

	// XXX where is this data actually stored?
	td.Clearance = 2
	td.ClearanceDirection = CLEARANCE_ABOVE
	return *td
}

// Advance all of the values by one track segment.
func advanceTrack(ts *TrackSegment, ΔE int, ΔForward int, ΔSideways int,
	direction DirectionDelta) (int, int, int, DirectionDelta) {
	ΔE += ts.ElevationGain

	ΔForward += cosdeg(direction) * ts.ForwardDelta
	ΔForward += sindeg(direction) * ts.SidewaysDelta

	ΔSideways += sindeg(direction) * ts.ForwardDelta
	ΔSideways += cosdeg(direction) * ts.SidewaysDelta

	direction += ts.DirectionDelta
	for ; direction >= 360; direction -= 360 {
	}

	return ΔE, ΔForward, ΔSideways, direction
}

// Test whether the ride's track forms a continuous circuit. Does not test
// whether the ride collides with itself.
func IsCircuit(t *TrackData) bool {
	// X and Y don't really make sense as variable names, easier to think about
	// relative changes
	eΔ, forwardΔ, sidewaysΔ := 0, 0, 0
	direction := DIRECTION_STRAIGHT
	if len(t.Elements) == 0 {
		return false
	}
	for i := range t.Elements {
		ts := t.Elements[i].Segment
		eΔ, forwardΔ, sidewaysΔ, direction = advanceTrack(
			ts, eΔ, forwardΔ, sidewaysΔ, direction)
	}
	return forwardΔ == 0 && sidewaysΔ == 0 && eΔ == 0
}

// Detect whether the track collides with itself.
func HasCollision(t *TrackData) bool {
	matrix := make([][][]bool, 100)
	for i := range matrix {
		matrix[i] = make([][]bool, 100)
		for j := range matrix[i] {
			matrix[i][j] = make([]bool, 100)
		}
	}
	eΔ, forwardΔ, sidewaysΔ := 0, 0, 0
	direction := DIRECTION_STRAIGHT
	for i := range t.Elements {
		ts := t.Elements[i].Segment
		eΔ, forwardΔ, sidewaysΔ, direction = advanceTrack(
			ts, eΔ, forwardΔ, sidewaysΔ, direction)
		// if there already exists a piece there, we can't build.
		if matrix[forwardΔ][sidewaysΔ][eΔ] {
			return true
		}
		matrix[forwardΔ][sidewaysΔ][eΔ] = true
	}
	return false
}

func main() {
	fmt.Println(readRaptor())
}

func readRaptor() *Ride {
	bits, err := ioutil.ReadFile("rides/raptor.td4")
	if err != nil {
		panic(err)
	}
	z, err := NewReader(buf)
	if err != nil {
		return err
	}
	var bitbuffer bytes.Buffer
	bitbuffer.ReadFrom(z)
	r := new(Ride)
	for i := 0; i < 500; i++ {
		// encode the value of i as hex
		ds := hex.EncodeToString([]byte{byte(i)})
		bitValueInHex := hex.EncodeToString([]byte{bits[i]})
		fmt.Printf("%s: %s\n", ds, bitValueInHex)
	}
	decrypted := bitbuffer.Bytes()

	Unmarshal(bitbuffer.Bytes(), *r)
	return r
}
<commit_msg>use unmarshal properly<commit_after>// td4 ride format parser

package main

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"math"
)

func hasLoop(n int) bool {
	return n>>7 == 1
}

// Set the loop bit.
func marshalLoop(hasLoop bool, n int) {
	if hasLoop {
		n |= (1 << 7)
	} else {
		n &= ^(1 << 7)
	}
}

type ControlFlags struct {
	UseMaximumTime             bool
	UseMinimumTime             bool
	SyncWithAdjacentStation    bool
	LeaveIfAnotherTrainArrives bool
	WaitForLoad                bool
	Load                       LoadType
}

func parseControlFlags(n int) *ControlFlags {
	return &ControlFlags{
		UseMaximumTime:             n>>7 == 1,
		UseMinimumTime:             n>>6 == 1,
		SyncWithAdjacentStation:    n>>5 == 1,
		LeaveIfAnotherTrainArrives: n>>4 == 1,
		WaitForLoad:                n>>3 == 1,
		Load:                       LoadType(n & 7),
	}
}

type RideType int
type VehicleType int
type LoadType int
type OperatingMode int
type SegmentType int

const (
	WOODEN_RIDE    RideType = iota
	STAND_UP_STEEL          = iota
	SUSPENDED               = iota
)

const (
	STEEL              VehicleType = iota
	STEEL_BACKWARDS                = iota
	WOODEN_VEHICLE                 = iota
	INVERTED                       = iota
	SUSPENDED_SWINGING             = iota
	LADYBIRD                       = iota
	STAND_UP                       = iota
)

const (
	MODE_NORMAL                  OperatingMode = 0x00
	MODE_CONTINUOUS_CIRCUIT                    = 0x01
	MODE_REVERSE_INCLINE_SHUTTLE               = 0x02
	MODE_POWERED_LAUNCH                        = 0x03
	MODE_SHUTTLE                               = 0x04
	MODE_BOAT_HIRE                             = 0x05
	MODE_UPWARD_LAUNCH                         = 0x06
	MODE_ROTATING_LIFT                         = 0x07
	MODE_STATION_TO_STATION                    = 0x08
)

const (
	LOAD_ONE_QUARTER    = 0
	LOAD_HALF           = 1
	LOAD_THREE_QUARTERS = 2
	LOAD_FULL           = 3
	LOAD_ANY            = 4
)

const (
	IDX_RIDE_TYPE      = 0
	IDX_VEHICLE_TYPE   = 1
	IDX_HAS_LOOP       = 2
	IDX_OPERATING_MODE = 0x06
	IDX_CONTROL_FLAG   = 0x23
	IDX_NUM_TRAINS     = 0x24
	IDX_CARS_PER_TRAIN = 0x25
	IDX_MIN_WAIT_TIME  = 0x26
	IDX_MAX_WAIT_TIME  = 0x27
	IDX_TRACK_DATA     = 0xc4
)

type Ride struct {
	RideType      RideType
	VehicleType   VehicleType
	HasLoop       bool
	OperatingMode OperatingMode
	ControlFlags  *ControlFlags
	NumTrains     int
	CarsPerTrain  int
	MinWaitTime   int
	MaxWaitTime   int
	TrackData     TrackData
}

type StationType int

const (
	STATION_ONE   StationType = 0
	STATION_TWO               = 1
	STATION_THREE             = 2
	STATION_FOUR              = 3
)

// computes sines in degrees
func sindeg(deg DirectionDelta) int {
	for ; deg >= 360; deg -= 360 {
	}
	if deg%180 == 0 {
		return 0
	} else if deg == 90 {
		return 1
	} else if deg == 270 {
		return -1
	} else {
		return int(math.Sin(float64(deg) * math.Pi / 180))
	}
}

// computes sines in degrees
func cosdeg(deg DirectionDelta) int {
	for ; deg >= 360; deg -= 360 {
	}
	if deg == 0 {
		return 1
	} else if deg == 90 || deg == 270 {
		return 0
	} else if deg == 180 {
		return -1
	} else {
		return int(math.Sin(float64(deg) * math.Pi / 180))
	}
}

//func Decrypt() {

// Take a compressed byte stream representing a ride and turn it into a Ride
// struct. Returns an error if the byte array is too short.
func Unmarshal(buf []byte, r *Ride) error {
	if len(buf) < IDX_TRACK_DATA {
		return errors.New("buffer too short to be a ride")
	}
	r.RideType = RideType(buf[IDX_RIDE_TYPE])
	r.VehicleType = VehicleType(buf[IDX_VEHICLE_TYPE])
	r.HasLoop = hasLoop(int(buf[IDX_HAS_LOOP]))
	r.OperatingMode = OperatingMode(buf[IDX_OPERATING_MODE])
	r.ControlFlags = parseControlFlags(int(buf[IDX_CONTROL_FLAG]))
	r.NumTrains = int(buf[IDX_NUM_TRAINS])
	r.CarsPerTrain = int(buf[IDX_CARS_PER_TRAIN])
	r.MinWaitTime = int(buf[IDX_MIN_WAIT_TIME])
	r.MaxWaitTime = int(buf[IDX_MAX_WAIT_TIME])
	r.TrackData = parseTrackData(buf[IDX_TRACK_DATA:])

	fmt.Println(r.VehicleType)
	return nil
}

func Marshal(r *Ride) ([]byte, error) {
	// at a minimum, rides have this much data
	bits := make([]byte, 0xc4)

	// This is a little bit tricky, and requires implementing the format
	// described in the tycoon technical depot, available here:
	// https://github.com/UnknownShadow200/RCTTechDepot-Archive/blob/master/td4.html
	bits[IDX_RIDE_TYPE] = byte(r.RideType)
	bits[IDX_VEHICLE_TYPE] = byte(r.VehicleType)
	//bits[IDX_HAS_LOOP] = byte(r.HasLoop)

	return bits, nil
}

var EndOfRide = errors.New("End of ride")

// Parse the serialized data into a TrackElement struct
// When the end of ride is encountered a EndOfRide error is returned
func parseElement(rawElement []byte) (te TrackElement, e error) {
	if len(rawElement) != 2 {
		return TrackElement{}, errors.New("invalid length for element input")
	}
	te.Segment = &TrackSegment{
		Type: SegmentType(rawElement[0]),
	}
	if te.Segment.Type == ELEM_END_OF_RIDE {
		return TrackElement{}, EndOfRide
	}
	q := int(rawElement[1])
	te.ChainLift = q>>7 == 1
	te.InvertedTrack = q>>6 == 1
	te.Station = q>>3 == 1
	te.StationNumber = q & 3

	te.BoostMagnitude = float32(q&15) * 7.6
	te.Rotation = (q&15)*45 - 180
	return
}

func parseTrackData(trackData []byte) TrackData {
	td := new(TrackData)
	for i := 0; i < len(trackData); i += 2 {
		elem, err := parseElement(trackData[i : i+2])
		if err != nil {
			if err == EndOfRide {
				break
			}
			panic(err)
		}
		td.Elements = append(td.Elements, elem)
	}

	// XXX where is this data actually stored?
	td.Clearance = 2
	td.ClearanceDirection = CLEARANCE_ABOVE
	return *td
}

// Advance all of the values by one track segment.
func advanceTrack(ts *TrackSegment, ΔE int, ΔForward int, ΔSideways int,
	direction DirectionDelta) (int, int, int, DirectionDelta) {
	ΔE += ts.ElevationGain

	ΔForward += cosdeg(direction) * ts.ForwardDelta
	ΔForward += sindeg(direction) * ts.SidewaysDelta

	ΔSideways += sindeg(direction) * ts.ForwardDelta
	ΔSideways += cosdeg(direction) * ts.SidewaysDelta

	direction += ts.DirectionDelta
	for ; direction >= 360; direction -= 360 {
	}

	return ΔE, ΔForward, ΔSideways, direction
}

// Test whether the ride's track forms a continuous circuit. Does not test
// whether the ride collides with itself.
func IsCircuit(t *TrackData) bool {
	// X and Y don't really make sense as variable names, easier to think about
	// relative changes
	eΔ, forwardΔ, sidewaysΔ := 0, 0, 0
	direction := DIRECTION_STRAIGHT
	if len(t.Elements) == 0 {
		return false
	}
	for i := range t.Elements {
		ts := t.Elements[i].Segment
		eΔ, forwardΔ, sidewaysΔ, direction = advanceTrack(
			ts, eΔ, forwardΔ, sidewaysΔ, direction)
	}
	return forwardΔ == 0 && sidewaysΔ == 0 && eΔ == 0
}

// Detect whether the track collides with itself.
func HasCollision(t *TrackData) bool {
	matrix := make([][][]bool, 100)
	for i := range matrix {
		matrix[i] = make([][]bool, 100)
		for j := range matrix[i] {
			matrix[i][j] = make([]bool, 100)
		}
	}
	eΔ, forwardΔ, sidewaysΔ := 0, 0, 0
	direction := DIRECTION_STRAIGHT
	for i := range t.Elements {
		ts := t.Elements[i].Segment
		eΔ, forwardΔ, sidewaysΔ, direction = advanceTrack(
			ts, eΔ, forwardΔ, sidewaysΔ, direction)
		// if there already exists a piece there, we can't build.
		if matrix[forwardΔ][sidewaysΔ][eΔ] {
			return true
		}
		matrix[forwardΔ][sidewaysΔ][eΔ] = true
	}
	return false
}

func main() {
	fmt.Println(readRaptor())
}

func readRaptor() Ride {
	encodedBits, err := ioutil.ReadFile("rides/raptor.td4")
	if err != nil {
		panic(err)
	}
	z := NewReader(bytes.NewReader(encodedBits))
	if err != nil {
		panic(err)
	}
	var bitbuffer bytes.Buffer
	bitbuffer.ReadFrom(z)
	decrypted := bitbuffer.Bytes()
	for i := 0; i < 500; i++ {
		// encode the value of i as hex
		ds := hex.EncodeToString([]byte{byte(i)})
		bitValueInHex := hex.EncodeToString([]byte{decrypted[i]})
		fmt.Printf("%s: %s\n", ds, bitValueInHex)
	}

	// r is a pointer
	r := new(Ride)
	Unmarshal(decrypted, r)
	fmt.Println(r.VehicleType)
	return *r
}
<|endoftext|>


<commit_before>package ezserver

import (
	"crypto/tls"
	"crypto/x509"

	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
)

// KeyCert represents a TLS key/centificate pair.
type KeyCert struct {
	Key         string `json:"key"`
	Certificate string `json:"certificate"`
}

// TLSConfig represents the TLS configuration for an HTTPS server.
type TLSConfig struct {
	Named   map[string]KeyCert `json:"named"`
	RootCAs []string           `json:"root_ca"`
	Default KeyCert            `json:"default"`

	ACMEDirectoryURL string   `json:"acme_dir_url"`
	ACMEHosts        []string `json:"acme_hosts"`
	ACMECacheDir     string   `json:"acme_cache_dir"`
}

// Clone produces a deep copy of a TLSConfig object.
func (c *TLSConfig) Clone() *TLSConfig {
	named := map[string]KeyCert{}
	for key, val := range c.Named {
		named[key] = val
	}

	roots := append([]string{}, c.RootCAs...)
	acmeHosts := append([]string{}, c.ACMEHosts...)

	return &TLSConfig{named, roots, c.Default, c.ACMEDirectoryURL, acmeHosts, c.ACMECacheDir}
}

// ToConfig turns a TLSConfig into a tls.Config.
func (c *TLSConfig) ToConfig() (*tls.Config, *autocert.Manager, error) {
	var err error
	res := &tls.Config{}

	res.NextProtos = []string{"http/1.1", "h2"}

	res.Certificates = make([]tls.Certificate, 1)
	res.Certificates[0], err = tls.X509KeyPair([]byte(c.Default.Certificate),
		[]byte(c.Default.Key))
	if err != nil {
		return nil, nil, err
	}

	res.NameToCertificate = map[string]*tls.Certificate{}
	for name, pair := range c.Named {
		loaded, err := tls.X509KeyPair([]byte(pair.Certificate),
			[]byte(pair.Key))
		if err != nil {
			return nil, nil, err
		}
		idx := len(res.Certificates)
		res.Certificates = append(res.Certificates, loaded)
		res.NameToCertificate[name] = &res.Certificates[idx]
	}

	if len(c.RootCAs) > 0 {
		pool := x509.NewCertPool()
		for _, pemData := range c.RootCAs {
			if !pool.AppendCertsFromPEM([]byte(pemData)) {
				return nil, nil, ErrInvalidRootCA
			}
		}
		res.RootCAs = pool
	}

	var manager *autocert.Manager
	if len(c.ACMEHosts) > 0 {
		manager = &autocert.Manager{
			Prompt:     autocert.AcceptTOS,
			HostPolicy: autocert.HostWhitelist(c.ACMEHosts...),
		}
		if c.ACMEDirectoryURL != "" {
			manager.Client = &acme.Client{DirectoryURL: c.ACMEDirectoryURL}
		}
		if c.ACMECacheDir != "" {
			manager.Cache = autocert.DirCache(c.ACMECacheDir)
		}
		res.GetCertificate = manager.GetCertificate
	}

	return res, manager, nil
}
<commit_msg>support ALPN<commit_after>package ezserver

import (
	"crypto/tls"
	"crypto/x509"

	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
)

// KeyCert represents a TLS key/centificate pair.
type KeyCert struct {
	Key         string `json:"key"`
	Certificate string `json:"certificate"`
}

// TLSConfig represents the TLS configuration for an HTTPS server.
type TLSConfig struct {
	Named   map[string]KeyCert `json:"named"`
	RootCAs []string           `json:"root_ca"`
	Default KeyCert            `json:"default"`

	ACMEDirectoryURL string   `json:"acme_dir_url"`
	ACMEHosts        []string `json:"acme_hosts"`
	ACMECacheDir     string   `json:"acme_cache_dir"`
}

// Clone produces a deep copy of a TLSConfig object.
func (c *TLSConfig) Clone() *TLSConfig {
	named := map[string]KeyCert{}
	for key, val := range c.Named {
		named[key] = val
	}

	roots := append([]string{}, c.RootCAs...)
	acmeHosts := append([]string{}, c.ACMEHosts...)

	return &TLSConfig{named, roots, c.Default, c.ACMEDirectoryURL, acmeHosts, c.ACMECacheDir}
}

// ToConfig turns a TLSConfig into a tls.Config.
func (c *TLSConfig) ToConfig() (*tls.Config, *autocert.Manager, error) {
	var err error
	res := &tls.Config{}

	res.NextProtos = []string{"http/1.1", "h2", acme.ALPNProto}

	res.Certificates = make([]tls.Certificate, 1)
	res.Certificates[0], err = tls.X509KeyPair([]byte(c.Default.Certificate),
		[]byte(c.Default.Key))
	if err != nil {
		return nil, nil, err
	}

	res.NameToCertificate = map[string]*tls.Certificate{}
	for name, pair := range c.Named {
		loaded, err := tls.X509KeyPair([]byte(pair.Certificate),
			[]byte(pair.Key))
		if err != nil {
			return nil, nil, err
		}
		idx := len(res.Certificates)
		res.Certificates = append(res.Certificates, loaded)
		res.NameToCertificate[name] = &res.Certificates[idx]
	}

	if len(c.RootCAs) > 0 {
		pool := x509.NewCertPool()
		for _, pemData := range c.RootCAs {
			if !pool.AppendCertsFromPEM([]byte(pemData)) {
				return nil, nil, ErrInvalidRootCA
			}
		}
		res.RootCAs = pool
	}

	var manager *autocert.Manager
	if len(c.ACMEHosts) > 0 {
		manager = &autocert.Manager{
			Prompt:     autocert.AcceptTOS,
			HostPolicy: autocert.HostWhitelist(c.ACMEHosts...),
		}
		if c.ACMEDirectoryURL != "" {
			manager.Client = &acme.Client{DirectoryURL: c.ACMEDirectoryURL}
		}
		if c.ACMECacheDir != "" {
			manager.Cache = autocert.DirCache(c.ACMECacheDir)
		}
		res.GetCertificate = manager.GetCertificate
	}

	return res, manager, nil
}
<|endoftext|>


<commit_before>// Type-Length-Value splitting and parsing for proxy protocol V2
// See spec https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt sections 2.2 to 2.7 and

package proxyproto

import (
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

const (
	// Section 2.2
	PP2_TYPE_ALPN           PP2Type = 0x01
	PP2_TYPE_AUTHORITY      PP2Type = 0x02
	PP2_TYPE_CRC32C         PP2Type = 0x03
	PP2_TYPE_NOOP           PP2Type = 0x04
	PP2_TYPE_SSL            PP2Type = 0x20
	PP2_SUBTYPE_SSL_VERSION PP2Type = 0x21
	PP2_SUBTYPE_SSL_CN      PP2Type = 0x22
	PP2_SUBTYPE_SSL_CIPHER  PP2Type = 0x23
	PP2_SUBTYPE_SSL_SIG_ALG PP2Type = 0x24
	PP2_SUBTYPE_SSL_KEY_ALG PP2Type = 0x25
	PP2_TYPE_NETNS          PP2Type = 0x30

	// Section 2.2.7, reserved types
	PP2_TYPE_MIN_CUSTOM     PP2Type = 0xE0
	PP2_TYPE_MAX_CUSTOM     PP2Type = 0xEF
	PP2_TYPE_MIN_EXPERIMENT PP2Type = 0xF0
	PP2_TYPE_MAX_EXPERIMENT PP2Type = 0xF7
	PP2_TYPE_MIN_FUTURE     PP2Type = 0xF8
	PP2_TYPE_MAX_FUTURE     PP2Type = 0xFF
)

var (
	ErrTruncatedTLV    = errors.New("proxyproto: truncated TLV")
	ErrMalformedTLV    = errors.New("proxyproto: malformed TLV Value")
	ErrIncompatibleTLV = errors.New("proxyproto: incompatible TLV type")
)

// PP2Type is the proxy protocol v2 type
type PP2Type byte

// TLV is a uninterpreted Type-Length-Value for V2 protocol, see section 2.2
type TLV struct {
	Type  PP2Type
	Value []byte
}

// SplitTLVs splits the Type-Length-Value vector, returns the vector or an error.
func SplitTLVs(raw []byte) ([]TLV, error) {
	var tlvs []TLV
	for i := 0; i < len(raw); {
		tlv := TLV{
			Type: PP2Type(raw[i]),
		}
		if len(raw)-i <= 3 {
			return nil, ErrTruncatedTLV
		}
		tlvLen := int(binary.BigEndian.Uint16(raw[i+1 : i+3])) // Max length = 65K
		i += 3
		if i+tlvLen > len(raw) {
			return nil, ErrTruncatedTLV
		}
		// Ignore no-op padding
		if tlv.Type != PP2_TYPE_NOOP {
			tlv.Value = make([]byte, tlvLen)
			copy(tlv.Value, raw[i:i+tlvLen])
		}
		i += tlvLen
		tlvs = append(tlvs, tlv)
	}
	return tlvs, nil
}

// JoinTLVs joins multiple Type-Length-Value records.
func JoinTLVs(tlvs []TLV) ([]byte, error) {
	var raw []byte
	for _, tlv := range tlvs {
		if len(tlv.Value) > math.MaxUint16 {
			return nil, fmt.Errorf("proxyproto: cannot format TLV %v with length %d", tlv.Type, len(tlv.Value))
		}
		var length [2]byte
		binary.BigEndian.PutUint16(length[:], uint16(len(tlv.Value)))
		raw = append(raw, byte(tlv.Type))
		raw = append(raw, length[:]...)
		raw = append(raw, tlv.Value...)
	}
	return raw, nil
}

// Registered is true if the type is registered in the spec, see section 2.2
func (p PP2Type) Registered() bool {
	switch p {
	case PP2_TYPE_ALPN,
		PP2_TYPE_AUTHORITY,
		PP2_TYPE_CRC32C,
		PP2_TYPE_NOOP,
		PP2_TYPE_SSL,
		PP2_SUBTYPE_SSL_VERSION,
		PP2_SUBTYPE_SSL_CN,
		PP2_SUBTYPE_SSL_CIPHER,
		PP2_SUBTYPE_SSL_SIG_ALG,
		PP2_SUBTYPE_SSL_KEY_ALG,
		PP2_TYPE_NETNS:
		return true
	}
	return false
}

// App is true if the type is reserved for application specific data, see section 2.2.7
func (p PP2Type) App() bool {
	return p >= PP2_TYPE_MIN_CUSTOM && p <= PP2_TYPE_MAX_CUSTOM
}

// Experiment is true if the type is reserved for temporary experimental use by application developers, see section 2.2.7
func (p PP2Type) Experiment() bool {
	return p >= PP2_TYPE_MIN_EXPERIMENT && p <= PP2_TYPE_MAX_EXPERIMENT
}

// Future is true is the type is reserved for future use, see section 2.2.7
func (p PP2Type) Future() bool {
	return p >= PP2_TYPE_MIN_FUTURE
}

// Spec is true if the type is covered by the spec, see section 2.2 and 2.2.7
func (p PP2Type) Spec() bool {
	return p.Registered() || p.App() || p.Experiment() || p.Future()
}
<commit_msg>Fixed incorrect truncated tlv error that prevents reading empty (0 byte) TLVs<commit_after>// Type-Length-Value splitting and parsing for proxy protocol V2
// See spec https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt sections 2.2 to 2.7 and

package proxyproto

import (
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

const (
	// Section 2.2
	PP2_TYPE_ALPN           PP2Type = 0x01
	PP2_TYPE_AUTHORITY      PP2Type = 0x02
	PP2_TYPE_CRC32C         PP2Type = 0x03
	PP2_TYPE_NOOP           PP2Type = 0x04
	PP2_TYPE_SSL            PP2Type = 0x20
	PP2_SUBTYPE_SSL_VERSION PP2Type = 0x21
	PP2_SUBTYPE_SSL_CN      PP2Type = 0x22
	PP2_SUBTYPE_SSL_CIPHER  PP2Type = 0x23
	PP2_SUBTYPE_SSL_SIG_ALG PP2Type = 0x24
	PP2_SUBTYPE_SSL_KEY_ALG PP2Type = 0x25
	PP2_TYPE_NETNS          PP2Type = 0x30

	// Section 2.2.7, reserved types
	PP2_TYPE_MIN_CUSTOM     PP2Type = 0xE0
	PP2_TYPE_MAX_CUSTOM     PP2Type = 0xEF
	PP2_TYPE_MIN_EXPERIMENT PP2Type = 0xF0
	PP2_TYPE_MAX_EXPERIMENT PP2Type = 0xF7
	PP2_TYPE_MIN_FUTURE     PP2Type = 0xF8
	PP2_TYPE_MAX_FUTURE     PP2Type = 0xFF
)

var (
	ErrTruncatedTLV    = errors.New("proxyproto: truncated TLV")
	ErrMalformedTLV    = errors.New("proxyproto: malformed TLV Value")
	ErrIncompatibleTLV = errors.New("proxyproto: incompatible TLV type")
)

// PP2Type is the proxy protocol v2 type
type PP2Type byte

// TLV is a uninterpreted Type-Length-Value for V2 protocol, see section 2.2
type TLV struct {
	Type  PP2Type
	Value []byte
}

// SplitTLVs splits the Type-Length-Value vector, returns the vector or an error.
func SplitTLVs(raw []byte) ([]TLV, error) {
	var tlvs []TLV
	for i := 0; i < len(raw); {
		tlv := TLV{
			Type: PP2Type(raw[i]),
		}
		if len(raw)-i <= 2 {
			return nil, ErrTruncatedTLV
		}
		tlvLen := int(binary.BigEndian.Uint16(raw[i+1 : i+3])) // Max length = 65K
		i += 3
		if i+tlvLen > len(raw) {
			return nil, ErrTruncatedTLV
		}
		// Ignore no-op padding
		if tlv.Type != PP2_TYPE_NOOP {
			tlv.Value = make([]byte, tlvLen)
			copy(tlv.Value, raw[i:i+tlvLen])
		}
		i += tlvLen
		tlvs = append(tlvs, tlv)
	}
	return tlvs, nil
}

// JoinTLVs joins multiple Type-Length-Value records.
func JoinTLVs(tlvs []TLV) ([]byte, error) {
	var raw []byte
	for _, tlv := range tlvs {
		if len(tlv.Value) > math.MaxUint16 {
			return nil, fmt.Errorf("proxyproto: cannot format TLV %v with length %d", tlv.Type, len(tlv.Value))
		}
		var length [2]byte
		binary.BigEndian.PutUint16(length[:], uint16(len(tlv.Value)))
		raw = append(raw, byte(tlv.Type))
		raw = append(raw, length[:]...)
		raw = append(raw, tlv.Value...)
	}
	return raw, nil
}

// Registered is true if the type is registered in the spec, see section 2.2
func (p PP2Type) Registered() bool {
	switch p {
	case PP2_TYPE_ALPN,
		PP2_TYPE_AUTHORITY,
		PP2_TYPE_CRC32C,
		PP2_TYPE_NOOP,
		PP2_TYPE_SSL,
		PP2_SUBTYPE_SSL_VERSION,
		PP2_SUBTYPE_SSL_CN,
		PP2_SUBTYPE_SSL_CIPHER,
		PP2_SUBTYPE_SSL_SIG_ALG,
		PP2_SUBTYPE_SSL_KEY_ALG,
		PP2_TYPE_NETNS:
		return true
	}
	return false
}

// App is true if the type is reserved for application specific data, see section 2.2.7
func (p PP2Type) App() bool {
	return p >= PP2_TYPE_MIN_CUSTOM && p <= PP2_TYPE_MAX_CUSTOM
}

// Experiment is true if the type is reserved for temporary experimental use by application developers, see section 2.2.7
func (p PP2Type) Experiment() bool {
	return p >= PP2_TYPE_MIN_EXPERIMENT && p <= PP2_TYPE_MAX_EXPERIMENT
}

// Future is true is the type is reserved for future use, see section 2.2.7
func (p PP2Type) Future() bool {
	return p >= PP2_TYPE_MIN_FUTURE
}

// Spec is true if the type is covered by the spec, see section 2.2 and 2.2.7
func (p PP2Type) Spec() bool {
	return p.Registered() || p.App() || p.Experiment() || p.Future()
}
<|endoftext|>


<commit_before>package ts3

import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"net"
	"strings"
	"sync"
	"time"
)

const (
	DefaultPort    = "10011"
	VerificationID = "TS3"
)

var (
	// ts3.Dial max timeout
	DialTimeout    = 1 * time.Second
	CommandTimeout = 500 * time.Millisecond
)

type notification func(string, string)

type Conn struct {
	conn          net.Conn
	rbuf          *bufio.Reader
	wbuf          *bufio.Writer
	cResult       chan string
	cNotification chan string
	cError        chan ErrorMsg
	notifyCb      notification
	cmdSync       *sync.WaitGroup
	cmdLast       time.Time
	cmdTimeout    time.Duration
}

type ErrorMsg struct {
	Id  int
	Msg string
}

// Dial connects to a local/remote TS3 server. A default port is appended to
// `addr` if user doesn't provide one.
func Dial(addr string, whitelisted bool) (*Conn, error) {
	var (
		err  error
		line string
	)

	// Append DefaultPort if user didn't specify one
	if !strings.Contains(addr, ":") {
		addr += ":" + DefaultPort
	}

	// Try to establish connection
	conn, err := net.DialTimeout("tcp", addr, DialTimeout)
	if err != nil {
		return nil, err
	}

	// Create buffers
	rbuf := bufio.NewReader(conn)
	wbuf := bufio.NewWriter(conn)

	timeout := time.Duration(350 * time.Millisecond)
	if whitelisted {
		timeout = time.Duration(0 * time.Millisecond)
	}

	// Allocate connection object
	ts3conn := &Conn{
		conn:          conn,
		rbuf:          rbuf,
		wbuf:          wbuf,
		cResult:       make(chan string),
		cNotification: make(chan string),
		cError:        make(chan ErrorMsg),
		notifyCb:      nil,
		cmdSync:       new(sync.WaitGroup),
		cmdLast:       time.Now(),
		cmdTimeout:    timeout,
	}

	// Read VerificationID
	line, err = rbuf.ReadString('\n')

	// Then check if it's a TS3 server
	if !strings.Contains(line, VerificationID) {
		return nil, errors.New("Invalid VerificationID")
	}

	// Read welcome message
	line, err = rbuf.ReadString('\n')

	// Sync socket incoming data, to ts3conn
	go ts3conn.sync()

	return ts3conn, nil
}

// Close closes underlying TCP Conn to local/remote server.
func (this *Conn) Close() error {
	return this.conn.Close()
}

// Cmd sends a request to a server and waits for its response.
func (this *Conn) Cmd(cmd string) (string, ErrorMsg) {
	//Make sure only 1 command runs at a time per connection
	this.cmdSync.Wait()
	this.cmdSync.Add(1)

	//Make sure we timeout nicely per command to avoid spamming
	diff := time.Since(this.cmdLast)
	if diff < this.cmdTimeout {
		<-time.After(this.cmdTimeout - diff)
	}

	var (
		result string   //Holds end result
		temp   string   //Holds temp result
		err    ErrorMsg //Holds error message
	)

	// Write the cmd to the socket, ending with a \n
	this.send(cmd + "\n")

	// Block on a channel that will recieve the socket READ that is NOT a notification or error
	// Block on a channel that will recieve the socket READ that is NOT a notification or result
	done := false
	for !done {
		select {
		case temp = <-this.cResult:
			result += temp
			continue
		case err = <-this.cError:
			done = true
		case <-time.After(CommandTimeout):
			//TODO Is there a better way to handle this?
			err.Id = 1
			err.Msg = "timeout"
			done = true
		}
	}

	this.cmdLast = time.Now()
	this.cmdSync.Done()
	return result, err
}

func (this *Conn) NotifyFunc(cb notification) {
	this.notifyCb = cb
}

func (this *Conn) send(p string) (int, error) {
	b := []byte(p)
	// Double IAC chars
	bytes.Replace(b, []byte{0xff}, []byte{0xff, 0xff}, -1)
	return this.conn.Write(b)
}

func (this *Conn) handleResponse(data string) {
	// Has to be done by line!
	// Sadly its possible, when spammed, to have an error and notification to stick together, and more
	// Should be a better way to solve this overall, but teamspeak is a bitch and doesnt have a standard way to end a reply

	lines := strings.Split(data, "\n")
	var result string

	for _, line := range lines {
		switch {
		case strings.HasPrefix(line, "error"):
			this.cError <- parseError(line)
		case strings.HasPrefix(line, "notify"):
			if this.notifyCb != nil {
				split := strings.SplitN(line, " ", 2)
				go this.notifyCb(split[0], split[1])
			}
		default:
			result += line
		}
	}

	if result != "" {
		this.cResult <- result
	}
}

// Write writes the contents of p into the buffer. It returns the number of bytes written.
func (this *Conn) Write(p []byte) (int, error) {
	s := string(p)
	s = strings.Replace(s, "\r", "", -1)

	this.handleResponse(s)
	return len(s), nil
}

// cp copies from an io.Reader to an io.Writer
func (this *Conn) sync() {
	for {
		io.Copy(this, this.conn)
	}
}
<commit_msg>Changed default waiting time to 350 ms<commit_after>package ts3

import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"net"
	"strings"
	"sync"
	"time"
)

const (
	DefaultPort    = "10011"
	VerificationID = "TS3"
)

var (
	// ts3.Dial max timeout
	DialTimeout    = 1 * time.Second
	CommandTimeout = 350 * time.Millisecond
)

type notification func(string, string)

type Conn struct {
	conn          net.Conn
	rbuf          *bufio.Reader
	wbuf          *bufio.Writer
	cResult       chan string
	cNotification chan string
	cError        chan ErrorMsg
	notifyCb      notification
	cmdSync       *sync.WaitGroup
	cmdLast       time.Time
	cmdTimeout    time.Duration
}

type ErrorMsg struct {
	Id  int
	Msg string
}

// Dial connects to a local/remote TS3 server. A default port is appended to
// `addr` if user doesn't provide one.
func Dial(addr string, whitelisted bool) (*Conn, error) {
	var (
		err  error
		line string
	)

	// Append DefaultPort if user didn't specify one
	if !strings.Contains(addr, ":") {
		addr += ":" + DefaultPort
	}

	// Try to establish connection
	conn, err := net.DialTimeout("tcp", addr, DialTimeout)
	if err != nil {
		return nil, err
	}

	// Create buffers
	rbuf := bufio.NewReader(conn)
	wbuf := bufio.NewWriter(conn)

	timeout := time.Duration(350 * time.Millisecond)
	if whitelisted {
		timeout = time.Duration(0 * time.Millisecond)
	}

	// Allocate connection object
	ts3conn := &Conn{
		conn:          conn,
		rbuf:          rbuf,
		wbuf:          wbuf,
		cResult:       make(chan string),
		cNotification: make(chan string),
		cError:        make(chan ErrorMsg),
		notifyCb:      nil,
		cmdSync:       new(sync.WaitGroup),
		cmdLast:       time.Now(),
		cmdTimeout:    timeout,
	}

	// Read VerificationID
	line, err = rbuf.ReadString('\n')

	// Then check if it's a TS3 server
	if !strings.Contains(line, VerificationID) {
		return nil, errors.New("Invalid VerificationID")
	}

	// Read welcome message
	line, err = rbuf.ReadString('\n')

	// Sync socket incoming data, to ts3conn
	go ts3conn.sync()

	return ts3conn, nil
}

// Close closes underlying TCP Conn to local/remote server.
func (this *Conn) Close() error {
	return this.conn.Close()
}

// Cmd sends a request to a server and waits for its response.
func (this *Conn) Cmd(cmd string) (string, ErrorMsg) {
	//Make sure only 1 command runs at a time per connection
	this.cmdSync.Wait()
	this.cmdSync.Add(1)

	//Make sure we timeout nicely per command to avoid spamming
	diff := time.Since(this.cmdLast)
	if diff < this.cmdTimeout {
		<-time.After(this.cmdTimeout - diff)
	}

	var (
		result string   //Holds end result
		temp   string   //Holds temp result
		err    ErrorMsg //Holds error message
	)

	// Write the cmd to the socket, ending with a \n
	this.send(cmd + "\n")

	// Block on a channel that will recieve the socket READ that is NOT a notification or error
	// Block on a channel that will recieve the socket READ that is NOT a notification or result
	done := false
	for !done {
		select {
		case temp = <-this.cResult:
			result += temp
			continue
		case err = <-this.cError:
			done = true
		case <-time.After(CommandTimeout):
			//TODO Is there a better way to handle this?
			err.Id = 1
			err.Msg = "timeout"
			done = true
		}
	}

	this.cmdLast = time.Now()
	this.cmdSync.Done()
	return result, err
}

func (this *Conn) NotifyFunc(cb notification) {
	this.notifyCb = cb
}

func (this *Conn) send(p string) (int, error) {
	b := []byte(p)
	// Double IAC chars
	bytes.Replace(b, []byte{0xff}, []byte{0xff, 0xff}, -1)
	return this.conn.Write(b)
}

func (this *Conn) handleResponse(data string) {
	// Has to be done by line!
	// Sadly its possible, when spammed, to have an error and notification to stick together, and more
	// Should be a better way to solve this overall, but teamspeak is a bitch and doesnt have a standard way to end a reply

	lines := strings.Split(data, "\n")
	var result string

	for _, line := range lines {
		switch {
		case strings.HasPrefix(line, "error"):
			this.cError <- parseError(line)
		case strings.HasPrefix(line, "notify"):
			if this.notifyCb != nil {
				split := strings.SplitN(line, " ", 2)
				go this.notifyCb(split[0], split[1])
			}
		default:
			result += line
		}
	}

	if result != "" {
		this.cResult <- result
	}
}

// Write writes the contents of p into the buffer. It returns the number of bytes written.
func (this *Conn) Write(p []byte) (int, error) {
	s := string(p)
	s = strings.Replace(s, "\r", "", -1)

	this.handleResponse(s)
	return len(s), nil
}

// cp copies from an io.Reader to an io.Writer
func (this *Conn) sync() {
	for {
		io.Copy(this, this.conn)
	}
}
<|endoftext|>


<commit_before>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"fmt"
	"math"
	"unsafe"
)

// BUG(bmatsuo):
// MDB_INTEGERKEY and MDB_INTEGERDUP aren't usable. I'm not sure they would be
// faster with the cgo bridge.  They need to be tested and benchmarked.
const (
	// Flags for Txn.OpenDBI.
	ReverseKey = C.MDB_REVERSEKEY // Use reverse string keys.
	DupSort    = C.MDB_DUPSORT    // Use sorted duplicates.
	DupFixed   = C.MDB_DUPFIXED   // Duplicate items have a fixed size (DupSort).
	ReverseDup = C.MDB_REVERSEDUP // Reverse duplicate values (DupSort).
	Create     = C.MDB_CREATE     // Create DB if not already existing.
)

// Txn is a database transaction in an environment.
//
// WARNING: A writable Txn is not threadsafe and may only be used in the
// goroutine that created it.
//
// See MDB_txn.
type Txn struct {
	env     *Env
	_txn    *C.MDB_txn
	managed bool
}

// beginTxn does not lock the OS thread which is a prerequisite for creating a
// write transaction.
func beginTxn(env *Env, parent *Txn, flags uint) (*Txn, error) {
	var _txn *C.MDB_txn
	var ptxn *C.MDB_txn
	if parent == nil {
		ptxn = nil
	} else {
		ptxn = parent._txn
	}
	ret := C.mdb_txn_begin(env._env, ptxn, C.uint(flags), &_txn)
	if ret != success {
		return nil, errno(ret)
	}
	txn := &Txn{
		env:  env,
		_txn: _txn,
	}
	return txn, nil
}

// Commit commits all operations of the transaction to the database.  A Txn
// cannot be used again after Commit is called.
//
// See mdb_txn_commit.
func (txn *Txn) Commit() error {
	if txn.managed {
		panic("managed transaction cannot be comitted directly")
	}
	return txn.commit()
}

func (txn *Txn) commit() error {
	ret := C.mdb_txn_commit(txn._txn)
	// The transaction handle is freed if there was no error
	if ret == success {
		txn._txn = nil
	}
	return errno(ret)
}

// Abort discards pending writes in the transaction.  A Txn cannot be used
// again after Abort is called.
//
// See mdb_txn_abort.
func (txn *Txn) Abort() {
	if txn.managed {
		panic("managed transaction cannot be aborted directly")
	}

	txn.abort()
}

func (txn *Txn) abort() {
	if txn._txn == nil {
		return
	}
	C.mdb_txn_abort(txn._txn)
	// The transaction handle is always freed.
	txn._txn = nil
}

// Reset aborts the transaction clears internal state so the transaction may be
// reused by calling Renew.  Reset panics if the transaction is managed by
// Update, View, etc.
//
// See mdb_txn_reset.
func (txn *Txn) Reset() {
	if txn.managed {
		panic("managed transaction cannot be reset directly")
	}
	txn.reset()
}

func (txn *Txn) reset() {
	C.mdb_txn_reset(txn._txn)
}

// Renew reuses a transaction that was previously reset.
//
// See mdb_txn_renew.
func (txn *Txn) Renew() error {
	if txn.managed {
		panic("managed transaction cannot be renewed directly")
	}
	return txn.renew()
}

func (txn *Txn) renew() error {
	ret := C.mdb_txn_renew(txn._txn)
	return errno(ret)
}

// OpenDBI opens a database in the environment.  An error is returned if name is empty.
//
// BUG:
// DBI(math.NaN()) is returned on error which seems really wrong.
//
// See mdb_dbi_open.
func (txn *Txn) OpenDBI(name string, flags uint) (DBI, error) {
	if name == "" {
		return 0, fmt.Errorf("database name cannot be empty")
	}

	cname := C.CString(name)
	dbi, err := txn.openDBI(cname, flags)
	C.free(unsafe.Pointer(cname))
	return dbi, err
}

// CreateDBI is a shorthand for OpenDBI that passed the flag lmdb.Create.
func (txn *Txn) CreateDBI(name string) (DBI, error) {
	return txn.OpenDBI(name, Create)
}

// OpenRoot opens the root database.  Applications should not write to the root
// database if also using named databases as LMDB stores metadata in the root
// database.
func (txn *Txn) OpenRoot(flags uint) (DBI, error) {
	return txn.openDBI(nil, flags)
}

func (txn *Txn) openDBI(cname *C.char, flags uint) (DBI, error) {
	var dbi C.MDB_dbi
	ret := C.mdb_dbi_open(txn._txn, cname, C.uint(flags), &dbi)
	if ret != success {
		return DBI(math.NaN()), errno(ret)
	}
	return DBI(dbi), nil
}

// Stat returns statistics for database handle dbi.
//
// See mdb_stat.
func (txn *Txn) Stat(dbi DBI) (*Stat, error) {
	var _stat C.MDB_stat
	ret := C.mdb_stat(txn._txn, C.MDB_dbi(dbi), &_stat)
	if ret != success {
		return nil, errno(ret)
	}
	stat := Stat{PSize: uint(_stat.ms_psize),
		Depth:         uint(_stat.ms_depth),
		BranchPages:   uint64(_stat.ms_branch_pages),
		LeafPages:     uint64(_stat.ms_leaf_pages),
		OverflowPages: uint64(_stat.ms_overflow_pages),
		Entries:       uint64(_stat.ms_entries)}
	return &stat, nil
}

// Drop empties the database if del is false.  Drop deletes and closes the
// database if del is true.
//
// See mdb_drop.
func (txn *Txn) Drop(dbi DBI, del bool) error {
	ret := C.mdb_drop(txn._txn, C.MDB_dbi(dbi), cbool(del))
	return errno(ret)
}

// Sub executes fn in a subtransaction.  Sub commits the subtransaction iff no
// error is returned and otherwise aborts it.  Sub returns any error it
// encounters.
//
// Any call to Abort, Commit, Renew, or Reset on a Txn created by Sub will
// panic.
func (txn *Txn) Sub(fn TxnOp) error {
	// As of 0.9.14 Readonly is the only Txn flag and readonly subtransactions
	// don't make sense.
	return txn.subFlag(0, fn)
}

func (txn *Txn) subFlag(flags uint, fn TxnOp) error {
	sub, err := beginTxn(txn.env, txn, flags)
	if err != nil {
		return err
	}
	sub.managed = true
	defer func() {
		if e := recover(); e != nil {
			sub.abort()
			panic(e)
		}
	}()
	err = fn(sub)
	if err != nil {
		sub.abort()
		return err
	}
	return sub.commit()
}

// Get retrieves items from database dbi.  The slice returned by Get references
// a readonly section of memory and attempts to mutate region the memory will
// result in a runtime panic.
//
// See mdb_get.
func (txn *Txn) Get(dbi DBI, key []byte) ([]byte, error) {
	val, err := txn.getVal(dbi, key)
	if err != nil {
		return nil, err
	}
	return val.Bytes(), nil
}

// getVal retrieves items from database dbi as a mdbVal.
//
// See mdb_get.
func (txn *Txn) getVal(dbi DBI, key []byte) (*mdbVal, error) {
	ckey := wrapVal(key)
	var cval mdbVal
	ret := C.mdb_get(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(&cval))
	err := errno(ret)
	if err != nil {
		return nil, err
	}
	return &cval, nil
}

// Put stores an item in database dbi.
//
// See mdb_put.
func (txn *Txn) Put(dbi DBI, key []byte, val []byte, flags uint) error {
	ckey := wrapVal(key)
	cval := wrapVal(val)
	ret := C.mdb_put(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(cval), C.uint(flags))
	return errno(ret)
}

// PutReserve returns a []byte of length n that can be written to, potentially
// avoiding a memcopy.  The returned byte slice is only valid in txn's thread,
// before it has terminated.
func (txn *Txn) PutReserve(dbi DBI, key []byte, n int, flags uint) ([]byte, error) {
	ckey := wrapVal(key)
	cval := &mdbVal{mv_size: C.size_t(n)}
	ret := C.mdb_put(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(cval), C.uint(flags|C.MDB_RESERVE))
	err := errno(ret)
	if err != nil {
		return nil, err
	}
	return cval.Bytes(), nil
}

// Del deletes items from database dbi.
//
// See mdb_del.
func (txn *Txn) Del(dbi DBI, key, val []byte) error {
	ckey := wrapVal(key)
	if val == nil {
		ret := C.mdb_del(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), nil)
		return errno(ret)
	}
	cval := wrapVal(val)
	ret := C.mdb_del(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(cval))
	return errno(ret)
}

// OpenCursor allocates and initializes a Cursor to database dbi.
//
// See mdb_cursor_open.
func (txn *Txn) OpenCursor(dbi DBI) (*Cursor, error) {
	return openCursor(txn, dbi)
}

// TxnOp is an operation applied to a transaction.  The Txn passed to a TxnOp
// is managed and the operation must not call Commit, Abort, Renew, or Reset on
// it.
//
// IMPORTANT:
// TxnOps that write to the database (those passed to Update or BeginUpdate)
// must not use the Txn in another goroutine (passing it directory otherwise
// through closure). Doing so has undefined results.
type TxnOp func(txn *Txn) error
<commit_msg>godoc: remove old comment<commit_after>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"fmt"
	"math"
	"unsafe"
)

// BUG(bmatsuo):
// MDB_INTEGERKEY and MDB_INTEGERDUP aren't usable. I'm not sure they would be
// faster with the cgo bridge.  They need to be tested and benchmarked.
const (
	// Flags for Txn.OpenDBI.
	ReverseKey = C.MDB_REVERSEKEY // Use reverse string keys.
	DupSort    = C.MDB_DUPSORT    // Use sorted duplicates.
	DupFixed   = C.MDB_DUPFIXED   // Duplicate items have a fixed size (DupSort).
	ReverseDup = C.MDB_REVERSEDUP // Reverse duplicate values (DupSort).
	Create     = C.MDB_CREATE     // Create DB if not already existing.
)

// Txn is a database transaction in an environment.
//
// WARNING: A writable Txn is not threadsafe and may only be used in the
// goroutine that created it.
//
// See MDB_txn.
type Txn struct {
	env     *Env
	_txn    *C.MDB_txn
	managed bool
}

// beginTxn does not lock the OS thread which is a prerequisite for creating a
// write transaction.
func beginTxn(env *Env, parent *Txn, flags uint) (*Txn, error) {
	var _txn *C.MDB_txn
	var ptxn *C.MDB_txn
	if parent == nil {
		ptxn = nil
	} else {
		ptxn = parent._txn
	}
	ret := C.mdb_txn_begin(env._env, ptxn, C.uint(flags), &_txn)
	if ret != success {
		return nil, errno(ret)
	}
	txn := &Txn{
		env:  env,
		_txn: _txn,
	}
	return txn, nil
}

// Commit commits all operations of the transaction to the database.  A Txn
// cannot be used again after Commit is called.
//
// See mdb_txn_commit.
func (txn *Txn) Commit() error {
	if txn.managed {
		panic("managed transaction cannot be comitted directly")
	}
	return txn.commit()
}

func (txn *Txn) commit() error {
	ret := C.mdb_txn_commit(txn._txn)
	// The transaction handle is freed if there was no error
	if ret == success {
		txn._txn = nil
	}
	return errno(ret)
}

// Abort discards pending writes in the transaction.  A Txn cannot be used
// again after Abort is called.
//
// See mdb_txn_abort.
func (txn *Txn) Abort() {
	if txn.managed {
		panic("managed transaction cannot be aborted directly")
	}

	txn.abort()
}

func (txn *Txn) abort() {
	if txn._txn == nil {
		return
	}
	C.mdb_txn_abort(txn._txn)
	// The transaction handle is always freed.
	txn._txn = nil
}

// Reset aborts the transaction clears internal state so the transaction may be
// reused by calling Renew.  Reset panics if the transaction is managed by
// Update, View, etc.
//
// See mdb_txn_reset.
func (txn *Txn) Reset() {
	if txn.managed {
		panic("managed transaction cannot be reset directly")
	}
	txn.reset()
}

func (txn *Txn) reset() {
	C.mdb_txn_reset(txn._txn)
}

// Renew reuses a transaction that was previously reset.
//
// See mdb_txn_renew.
func (txn *Txn) Renew() error {
	if txn.managed {
		panic("managed transaction cannot be renewed directly")
	}
	return txn.renew()
}

func (txn *Txn) renew() error {
	ret := C.mdb_txn_renew(txn._txn)
	return errno(ret)
}

// OpenDBI opens a database in the environment.  An error is returned if name is empty.
//
// See mdb_dbi_open.
func (txn *Txn) OpenDBI(name string, flags uint) (DBI, error) {
	if name == "" {
		return 0, fmt.Errorf("database name cannot be empty")
	}

	cname := C.CString(name)
	dbi, err := txn.openDBI(cname, flags)
	C.free(unsafe.Pointer(cname))
	return dbi, err
}

// CreateDBI is a shorthand for OpenDBI that passed the flag lmdb.Create.
func (txn *Txn) CreateDBI(name string) (DBI, error) {
	return txn.OpenDBI(name, Create)
}

// OpenRoot opens the root database.  Applications should not write to the root
// database if also using named databases as LMDB stores metadata in the root
// database.
func (txn *Txn) OpenRoot(flags uint) (DBI, error) {
	return txn.openDBI(nil, flags)
}

func (txn *Txn) openDBI(cname *C.char, flags uint) (DBI, error) {
	var dbi C.MDB_dbi
	ret := C.mdb_dbi_open(txn._txn, cname, C.uint(flags), &dbi)
	if ret != success {
		return DBI(math.NaN()), errno(ret)
	}
	return DBI(dbi), nil
}

// Stat returns statistics for database handle dbi.
//
// See mdb_stat.
func (txn *Txn) Stat(dbi DBI) (*Stat, error) {
	var _stat C.MDB_stat
	ret := C.mdb_stat(txn._txn, C.MDB_dbi(dbi), &_stat)
	if ret != success {
		return nil, errno(ret)
	}
	stat := Stat{PSize: uint(_stat.ms_psize),
		Depth:         uint(_stat.ms_depth),
		BranchPages:   uint64(_stat.ms_branch_pages),
		LeafPages:     uint64(_stat.ms_leaf_pages),
		OverflowPages: uint64(_stat.ms_overflow_pages),
		Entries:       uint64(_stat.ms_entries)}
	return &stat, nil
}

// Drop empties the database if del is false.  Drop deletes and closes the
// database if del is true.
//
// See mdb_drop.
func (txn *Txn) Drop(dbi DBI, del bool) error {
	ret := C.mdb_drop(txn._txn, C.MDB_dbi(dbi), cbool(del))
	return errno(ret)
}

// Sub executes fn in a subtransaction.  Sub commits the subtransaction iff no
// error is returned and otherwise aborts it.  Sub returns any error it
// encounters.
//
// Any call to Abort, Commit, Renew, or Reset on a Txn created by Sub will
// panic.
func (txn *Txn) Sub(fn TxnOp) error {
	// As of 0.9.14 Readonly is the only Txn flag and readonly subtransactions
	// don't make sense.
	return txn.subFlag(0, fn)
}

func (txn *Txn) subFlag(flags uint, fn TxnOp) error {
	sub, err := beginTxn(txn.env, txn, flags)
	if err != nil {
		return err
	}
	sub.managed = true
	defer func() {
		if e := recover(); e != nil {
			sub.abort()
			panic(e)
		}
	}()
	err = fn(sub)
	if err != nil {
		sub.abort()
		return err
	}
	return sub.commit()
}

// Get retrieves items from database dbi.  The slice returned by Get references
// a readonly section of memory and attempts to mutate region the memory will
// result in a runtime panic.
//
// See mdb_get.
func (txn *Txn) Get(dbi DBI, key []byte) ([]byte, error) {
	val, err := txn.getVal(dbi, key)
	if err != nil {
		return nil, err
	}
	return val.Bytes(), nil
}

// getVal retrieves items from database dbi as a mdbVal.
//
// See mdb_get.
func (txn *Txn) getVal(dbi DBI, key []byte) (*mdbVal, error) {
	ckey := wrapVal(key)
	var cval mdbVal
	ret := C.mdb_get(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(&cval))
	err := errno(ret)
	if err != nil {
		return nil, err
	}
	return &cval, nil
}

// Put stores an item in database dbi.
//
// See mdb_put.
func (txn *Txn) Put(dbi DBI, key []byte, val []byte, flags uint) error {
	ckey := wrapVal(key)
	cval := wrapVal(val)
	ret := C.mdb_put(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(cval), C.uint(flags))
	return errno(ret)
}

// PutReserve returns a []byte of length n that can be written to, potentially
// avoiding a memcopy.  The returned byte slice is only valid in txn's thread,
// before it has terminated.
func (txn *Txn) PutReserve(dbi DBI, key []byte, n int, flags uint) ([]byte, error) {
	ckey := wrapVal(key)
	cval := &mdbVal{mv_size: C.size_t(n)}
	ret := C.mdb_put(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(cval), C.uint(flags|C.MDB_RESERVE))
	err := errno(ret)
	if err != nil {
		return nil, err
	}
	return cval.Bytes(), nil
}

// Del deletes items from database dbi.
//
// See mdb_del.
func (txn *Txn) Del(dbi DBI, key, val []byte) error {
	ckey := wrapVal(key)
	if val == nil {
		ret := C.mdb_del(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), nil)
		return errno(ret)
	}
	cval := wrapVal(val)
	ret := C.mdb_del(txn._txn, C.MDB_dbi(dbi), (*C.MDB_val)(ckey), (*C.MDB_val)(cval))
	return errno(ret)
}

// OpenCursor allocates and initializes a Cursor to database dbi.
//
// See mdb_cursor_open.
func (txn *Txn) OpenCursor(dbi DBI) (*Cursor, error) {
	return openCursor(txn, dbi)
}

// TxnOp is an operation applied to a transaction.  The Txn passed to a TxnOp
// is managed and the operation must not call Commit, Abort, Renew, or Reset on
// it.
//
// IMPORTANT:
// TxnOps that write to the database (those passed to Update or BeginUpdate)
// must not use the Txn in another goroutine (passing it directory otherwise
// through closure). Doing so has undefined results.
type TxnOp func(txn *Txn) error
<|endoftext|>


<commit_before>package toolbox

import (
	"strings"
	"net/url"
)

//ExtractURIParameters parses URIs to extract {<param>} defined in templateURI from requestURI, it returns extracted parameters and flag if requestURI matched templateURI
func ExtractURIParameters(templateURI, requestURI string) (map[string]string, bool) {
	var expectingValue, expectingName bool
	var name, value string
	var uriParameters = make(map[string]string)
	maxLength := len(templateURI) + len(requestURI)
	var requestURIIndex, templateURIIndex int

	questionMarkPosition := strings.Index(requestURI, "?")
	if questionMarkPosition != -1 {
		requestURI = string(requestURI[:questionMarkPosition])
	}

	for k := 0; k < maxLength; k++ {
		var requestChar, routingChar string

		if requestURIIndex < len(requestURI) {
			requestChar = requestURI[requestURIIndex: requestURIIndex+1]
		}

		if templateURIIndex < len(templateURI) {
			routingChar = templateURI[templateURIIndex: templateURIIndex+1]
		}
		if (!expectingValue && !expectingName) && requestChar == routingChar && routingChar != "" {
			requestURIIndex++
			templateURIIndex++
			continue
		}

		if routingChar == "}" {
			expectingName = false
			templateURIIndex++
		}

		if expectingValue && requestChar == "/" {
			expectingValue = false
		}

		if expectingName && templateURIIndex < len(templateURI) {
			name += routingChar
			templateURIIndex++
		}

		if routingChar == "{" {
			expectingValue = true
			expectingName = true
			templateURIIndex++

		}

		if expectingValue && requestURIIndex < len(requestURI) {
			value += requestChar
			requestURIIndex++
		}

		if !expectingValue && !expectingName && len(name) > 0 {
			uriParameters[name] = value
			name = ""
			value = ""
		}

	}

	if len(name) > 0 && len(value) > 0 {
		uriParameters[name] = value
	}
	matched := requestURIIndex == len(requestURI) && templateURIIndex == len(templateURI)
	return uriParameters, matched
}

func URLPathJoin(baseURL, path string) string {
	if strings.HasSuffix(baseURL, "/") {
		return baseURL + path
	}
	if ! strings.HasPrefix(path, "/") {
		path = "/" + path
	}

	return baseURL + path
}

//URLBase returns base URL
func URLBase(URL string) string {
	parsedURL, err := url.Parse(URL)
	if err != nil || parsedURL.Path == "" {
		return URL
	}
	pathPosition := strings.Index(URL, parsedURL.Path)
	if pathPosition == -1 {
		return URL
	}
	return string(URL[:pathPosition])
}
<commit_msg>added URL split, patched URLBase<commit_after>package toolbox

import (
	"fmt"
	"net/url"
	"strings"
)

//ExtractURIParameters parses URIs to extract {<param>} defined in templateURI from requestURI, it returns extracted parameters and flag if requestURI matched templateURI
func ExtractURIParameters(templateURI, requestURI string) (map[string]string, bool) {
	var expectingValue, expectingName bool
	var name, value string
	var uriParameters = make(map[string]string)
	maxLength := len(templateURI) + len(requestURI)
	var requestURIIndex, templateURIIndex int

	questionMarkPosition := strings.Index(requestURI, "?")
	if questionMarkPosition != -1 {
		requestURI = string(requestURI[:questionMarkPosition])
	}

	for k := 0; k < maxLength; k++ {
		var requestChar, routingChar string

		if requestURIIndex < len(requestURI) {
			requestChar = requestURI[requestURIIndex : requestURIIndex+1]
		}

		if templateURIIndex < len(templateURI) {
			routingChar = templateURI[templateURIIndex : templateURIIndex+1]
		}
		if (!expectingValue && !expectingName) && requestChar == routingChar && routingChar != "" {
			requestURIIndex++
			templateURIIndex++
			continue
		}

		if routingChar == "}" {
			expectingName = false
			templateURIIndex++
		}

		if expectingValue && requestChar == "/" {
			expectingValue = false
		}

		if expectingName && templateURIIndex < len(templateURI) {
			name += routingChar
			templateURIIndex++
		}

		if routingChar == "{" {
			expectingValue = true
			expectingName = true
			templateURIIndex++

		}

		if expectingValue && requestURIIndex < len(requestURI) {
			value += requestChar
			requestURIIndex++
		}

		if !expectingValue && !expectingName && len(name) > 0 {
			uriParameters[name] = value
			name = ""
			value = ""
		}

	}

	if len(name) > 0 && len(value) > 0 {
		uriParameters[name] = value
	}
	matched := requestURIIndex == len(requestURI) && templateURIIndex == len(templateURI)
	return uriParameters, matched
}

func URLPathJoin(baseURL, path string) string {
	if strings.HasSuffix(baseURL, "/") {
		return baseURL + path
	}
	if !strings.HasPrefix(path, "/") {
		path = "/" + path
	}

	return baseURL + path
}

//URLBase returns base URL
func URLBase(URL string) string {
	parsedURL, err := url.Parse(URL)
	if err != nil || parsedURL.Path == "" {
		return URL
	}
	pathPosition := strings.Index(URL, parsedURL.Path)
	if pathPosition == -1 {
		return URL
	}
	return string(URL[:pathPosition])
}

//URLSplit returns URL with parent path and resource name
func URLSplit(URL string) (string, string) {
	parsedURL, err := url.Parse(URL)
	if err != nil || parsedURL.Path == "" {
		return URL, ""
	}
	splitPosition := strings.LastIndex(parsedURL.Path, "/")
	if splitPosition == -1 {
		return URL, ""
	}
	return fmt.Sprintf("%v%v", URLBase(URL), string(parsedURL.Path[:splitPosition])), string(parsedURL.Path[splitPosition+1:])
}
<|endoftext|>


<commit_before>package utp

/*
#cgo CPPFLAGS: -DPOSIX
#include "utp.h"

uint64_t errorCallback(utp_callback_arguments *);
uint64_t logCallback(utp_callback_arguments *);
uint64_t acceptCallback(utp_callback_arguments *);
uint64_t sendtoCallback(utp_callback_arguments *);
uint64_t stateChangeCallback(utp_callback_arguments *);
uint64_t readCallback(utp_callback_arguments *);
*/
import "C"
import (
	"errors"
	"io"
	"log"
	"net"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

type socklen C.socklen_t

func (ctx *C.utp_context) setCallbacks() {
	C.utp_set_callback(ctx, C.UTP_LOG, (*C.utp_callback_t)(C.logCallback))
	C.utp_set_callback(ctx, C.UTP_ON_ACCEPT, (*C.utp_callback_t)(C.acceptCallback))
	C.utp_set_callback(ctx, C.UTP_SENDTO, (*C.utp_callback_t)(C.sendtoCallback))
	C.utp_set_callback(ctx, C.UTP_ON_STATE_CHANGE, (*C.utp_callback_t)(C.stateChangeCallback))
	C.utp_set_callback(ctx, C.UTP_ON_READ, (*C.utp_callback_t)(C.readCallback))
	C.utp_set_callback(ctx, C.UTP_ON_ERROR, (*C.utp_callback_t)(C.errorCallback))
}

func (ctx *C.utp_context) setOption(opt, val int) int {
	return int(C.utp_context_set_option(ctx, C.int(opt), C.int(val)))
}

func libStateName(state C.int) string {
	return C.GoString((*[5]*C.char)(unsafe.Pointer(&C.utp_state_names))[state])
}

func libErrorCodeNames(error_code C.int) string {
	return C.GoString((*[3]*C.char)(unsafe.Pointer(&C.utp_state_names))[error_code])
}

func newConn(s *C.utp_socket) *Conn {
	c := &Conn{s: s}
	c.cond.L = &c.mu
	libSocketToConn[s] = c
	return c
}

func getSocketForUtpContext(ctx *C.utp_context) *Socket {
	mu.Lock()
	defer mu.Unlock()
	return utpContextToSocket[ctx]
}

func (s *Socket) packetReader() {
	var b [0x1000]byte
	for {
		n, addr, err := s.pc.ReadFrom(b[:])
		if err != nil {
			s.mu.Lock()
			closed := s.closed
			s.mu.Unlock()
			if closed {
				return
			}
			panic(err)
		}
		log.Println(n, addr, err)
		// log.Printf("%#v", addr)
		sa, sal := netAddrToLibSockaddr(addr)
		func() {
			s.mu.Lock()
			defer s.mu.Unlock()
			if s.closed {
				return
			}
			C.utp_process_udp(s.ctx, (*C.byte)(&b[0]), C.size_t(n), sa, sal)
			C.utp_issue_deferred_acks(s.ctx)
		}()
	}
}

func (s *Socket) timeoutChecker() {
	for {
		s.mu.Lock()
		if s.closed {
			s.mu.Unlock()
			return
		}
		C.utp_check_timeouts(s.ctx)
		s.mu.Unlock()
		time.Sleep(500 * time.Millisecond)
	}
}

func NewSocket(network, addr string) (*Socket, error) {
	pc, err := net.ListenPacket(network, addr)
	if err != nil {
		return nil, err
	}
	ctx := C.utp_init(2)
	ctx.setCallbacks()
	// ctx.setOption(C.UTP_LOG_NORMAL, 1)
	// ctx.setOption(C.UTP_LOG_MTU, 1)
	// ctx.setOption(C.UTP_LOG_DEBUG, 1)
	s := &Socket{
		pc:      pc,
		ctx:     ctx,
		backlog: make(chan *Conn, 5),
	}
	mu.Lock()
	utpContextToSocket[ctx] = s
	mu.Unlock()
	go s.packetReader()
	return s, nil
}

type Socket struct {
	mu      sync.Mutex
	pc      net.PacketConn
	ctx     *C.utp_context
	backlog chan *Conn
	closed  bool
}

func (me *Socket) Close() error {
	me.mu.Lock()
	defer me.mu.Unlock()
	if me.closed {
		return nil
	}
	log.Print("destroy socket")
	C.utp_destroy(me.ctx)
	me.ctx = nil
	me.pc.Close()
	close(me.backlog)
	me.closed = true
	return nil
}

func (me *Socket) Addr() net.Addr {
	return me.pc.LocalAddr()
}

var (
	mu                 sync.Mutex
	utpContextToSocket = map[*C.utp_context]*Socket{}
	libSocketToConn    = map[*C.utp_socket]*Conn{}
)

func (s *Socket) Accept() (net.Conn, error) {
	log.Print("socket accept")
	c := <-s.backlog
	return c, nil
}

func (s *Socket) Dial(addr string) (net.Conn, error) {
	ua, err := net.ResolveUDPAddr(s.Addr().Network(), addr)
	if err != nil {
		panic(err)
	}
	sa, sl := netAddrToLibSockaddr(ua)
	c := newConn(C.utp_create_socket(s.ctx))
	C.utp_connect(c.s, sa, sl)
	err = c.waitForConnect()
	if err != nil {
		c.Close()
		return nil, err
	}
	return c, nil
}

func (s *Socket) pushBacklog(c *Conn) {
	select {
	case s.backlog <- c:
	default:
		c.Close()
	}
}

type Conn struct {
	s          *C.utp_socket
	mu         sync.Mutex
	cond       sync.Cond
	readBuf    []byte
	gotEOF     bool
	gotConnect bool
	writeBuf   []byte
	// Set on state changed to UTP_STATE_DESTROYING. Not valid to refer to the
	// socket after getting this.
	destroyed bool
	// Conn.Close was called.
	closed bool

	writeDeadline time.Time
	readDeadline  time.Time
}

func (c *Conn) setConnected() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.gotConnect = true
	c.cond.Broadcast()
}

func (c *Conn) waitForConnect() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	for !c.gotConnect {
		c.cond.Wait()
	}
	return nil
}

func (c *Conn) Close() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.closed {
		return nil
	}
	log.Print("closing conn")
	C.utp_close(c.s)
	c.closed = true
	c.cond.Broadcast()
	return nil
}

func (c *Conn) LocalAddr() net.Addr {
	return getSocketForUtpContext(C.utp_get_context(c.s)).pc.LocalAddr()
}

func (c *Conn) Read(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	for {
		n := copy(b, c.readBuf)
		c.readBuf = c.readBuf[n:]
		log.Println(n, len(c.readBuf))
		if n != 0 && len(c.readBuf) == 0 {
			C.utp_read_drained(c.s)
		}
		if len(c.readBuf) == 0 && c.gotEOF {
			return n, io.EOF
		}
		if n != 0 || len(b) == 0 {
			return n, nil
		}
		if c.destroyed {
			return 0, errors.New("destroyed")
		}
		if c.closed {
			return 0, errors.New("closed")
		}
		if !c.readDeadline.IsZero() && !time.Now().Before(c.readDeadline) {
			return 0, errDeadlineExceeded{}
		}
		c.cond.Wait()
	}
}

func (c *Conn) Write(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	n := 0
	for len(b) != 0 {
		if c.closed {
			return n, errors.New("closed")
		}
		n1 := C.utp_write(c.s, unsafe.Pointer(&b[0]), C.size_t(len(b)))
		if n1 < 0 {
			panic(n1)
		}
		b = b[n1:]
		n += int(n1)
		if n1 == 0 {
			if !c.writeDeadline.IsZero() && !time.Now().Before(c.writeDeadline) {
				return n, errDeadlineExceeded{}
			}
			c.cond.Wait()
		}
	}
	return n, nil
}

func (c *Conn) RemoteAddr() net.Addr {
	var rsa syscall.RawSockaddrAny
	var addrlen C.socklen_t = syscall.SizeofSockaddrAny
	C.utp_getpeername(c.s, (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), &addrlen)
	sa, err := anyToSockaddr(&rsa)
	if err != nil {
		panic(err)
	}
	return sockaddrToUDP(sa)
}

func (c *Conn) SetDeadline(t time.Time) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.readDeadline = t
	c.writeDeadline = t
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetReadDeadline(t time.Time) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.readDeadline = t
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetWriteDeadline(t time.Time) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.writeDeadline = t
	c.cond.Broadcast()
	return nil
}

func connForLibSocket(us *C.utp_socket) *Conn {
	return libSocketToConn[us]
}

func (c *Conn) setGotEOF() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.gotEOF = true
	c.cond.Broadcast()
}

func (c *Conn) onStateDestroying() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.destroyed = true
	c.cond.Broadcast()
}
<commit_msg>Nil the lib socket when we close it<commit_after>package utp

/*
#cgo CPPFLAGS: -DPOSIX
#include "utp.h"

uint64_t errorCallback(utp_callback_arguments *);
uint64_t logCallback(utp_callback_arguments *);
uint64_t acceptCallback(utp_callback_arguments *);
uint64_t sendtoCallback(utp_callback_arguments *);
uint64_t stateChangeCallback(utp_callback_arguments *);
uint64_t readCallback(utp_callback_arguments *);
*/
import "C"
import (
	"errors"
	"io"
	"log"
	"net"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

type socklen C.socklen_t

func (ctx *C.utp_context) setCallbacks() {
	C.utp_set_callback(ctx, C.UTP_LOG, (*C.utp_callback_t)(C.logCallback))
	C.utp_set_callback(ctx, C.UTP_ON_ACCEPT, (*C.utp_callback_t)(C.acceptCallback))
	C.utp_set_callback(ctx, C.UTP_SENDTO, (*C.utp_callback_t)(C.sendtoCallback))
	C.utp_set_callback(ctx, C.UTP_ON_STATE_CHANGE, (*C.utp_callback_t)(C.stateChangeCallback))
	C.utp_set_callback(ctx, C.UTP_ON_READ, (*C.utp_callback_t)(C.readCallback))
	C.utp_set_callback(ctx, C.UTP_ON_ERROR, (*C.utp_callback_t)(C.errorCallback))
}

func (ctx *C.utp_context) setOption(opt, val int) int {
	return int(C.utp_context_set_option(ctx, C.int(opt), C.int(val)))
}

func libStateName(state C.int) string {
	return C.GoString((*[5]*C.char)(unsafe.Pointer(&C.utp_state_names))[state])
}

func libErrorCodeNames(error_code C.int) string {
	return C.GoString((*[3]*C.char)(unsafe.Pointer(&C.utp_state_names))[error_code])
}

func newConn(s *C.utp_socket) *Conn {
	c := &Conn{s: s}
	c.cond.L = &c.mu
	libSocketToConn[s] = c
	return c
}

func getSocketForUtpContext(ctx *C.utp_context) *Socket {
	mu.Lock()
	defer mu.Unlock()
	return utpContextToSocket[ctx]
}

func (s *Socket) packetReader() {
	var b [0x1000]byte
	for {
		n, addr, err := s.pc.ReadFrom(b[:])
		if err != nil {
			s.mu.Lock()
			closed := s.closed
			s.mu.Unlock()
			if closed {
				return
			}
			panic(err)
		}
		log.Println(n, addr, err)
		// log.Printf("%#v", addr)
		sa, sal := netAddrToLibSockaddr(addr)
		func() {
			s.mu.Lock()
			defer s.mu.Unlock()
			if s.closed {
				return
			}
			C.utp_process_udp(s.ctx, (*C.byte)(&b[0]), C.size_t(n), sa, sal)
			C.utp_issue_deferred_acks(s.ctx)
		}()
	}
}

func (s *Socket) timeoutChecker() {
	for {
		s.mu.Lock()
		if s.closed {
			s.mu.Unlock()
			return
		}
		C.utp_check_timeouts(s.ctx)
		s.mu.Unlock()
		time.Sleep(500 * time.Millisecond)
	}
}

func NewSocket(network, addr string) (*Socket, error) {
	pc, err := net.ListenPacket(network, addr)
	if err != nil {
		return nil, err
	}
	ctx := C.utp_init(2)
	ctx.setCallbacks()
	// ctx.setOption(C.UTP_LOG_NORMAL, 1)
	// ctx.setOption(C.UTP_LOG_MTU, 1)
	// ctx.setOption(C.UTP_LOG_DEBUG, 1)
	s := &Socket{
		pc:      pc,
		ctx:     ctx,
		backlog: make(chan *Conn, 5),
	}
	mu.Lock()
	utpContextToSocket[ctx] = s
	mu.Unlock()
	go s.packetReader()
	return s, nil
}

type Socket struct {
	mu      sync.Mutex
	pc      net.PacketConn
	ctx     *C.utp_context
	backlog chan *Conn
	closed  bool
}

func (me *Socket) Close() error {
	me.mu.Lock()
	defer me.mu.Unlock()
	if me.closed {
		return nil
	}
	log.Print("destroy socket")
	C.utp_destroy(me.ctx)
	me.ctx = nil
	me.pc.Close()
	close(me.backlog)
	me.closed = true
	return nil
}

func (me *Socket) Addr() net.Addr {
	return me.pc.LocalAddr()
}

var (
	mu                 sync.Mutex
	utpContextToSocket = map[*C.utp_context]*Socket{}
	libSocketToConn    = map[*C.utp_socket]*Conn{}
)

func (s *Socket) Accept() (net.Conn, error) {
	log.Print("socket accept")
	c := <-s.backlog
	return c, nil
}

func (s *Socket) Dial(addr string) (net.Conn, error) {
	ua, err := net.ResolveUDPAddr(s.Addr().Network(), addr)
	if err != nil {
		panic(err)
	}
	sa, sl := netAddrToLibSockaddr(ua)
	c := newConn(C.utp_create_socket(s.ctx))
	C.utp_connect(c.s, sa, sl)
	err = c.waitForConnect()
	if err != nil {
		c.Close()
		return nil, err
	}
	return c, nil
}

func (s *Socket) pushBacklog(c *Conn) {
	select {
	case s.backlog <- c:
	default:
		c.Close()
	}
}

type Conn struct {
	s          *C.utp_socket
	mu         sync.Mutex
	cond       sync.Cond
	readBuf    []byte
	gotEOF     bool
	gotConnect bool
	writeBuf   []byte
	// Set on state changed to UTP_STATE_DESTROYING. Not valid to refer to the
	// socket after getting this.
	destroyed bool
	// Conn.Close was called.
	closed bool

	writeDeadline time.Time
	readDeadline  time.Time
}

func (c *Conn) setConnected() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.gotConnect = true
	c.cond.Broadcast()
}

func (c *Conn) waitForConnect() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	for !c.gotConnect {
		c.cond.Wait()
	}
	return nil
}

func (c *Conn) Close() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.closed {
		return nil
	}
	log.Print("closing conn")
	C.utp_close(c.s)
	c.s = nil
	c.closed = true
	c.cond.Broadcast()
	return nil
}

func (c *Conn) LocalAddr() net.Addr {
	return getSocketForUtpContext(C.utp_get_context(c.s)).pc.LocalAddr()
}

func (c *Conn) Read(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	for {
		n := copy(b, c.readBuf)
		c.readBuf = c.readBuf[n:]
		log.Println(n, len(c.readBuf))
		if n != 0 && len(c.readBuf) == 0 {
			C.utp_read_drained(c.s)
		}
		if len(c.readBuf) == 0 && c.gotEOF {
			return n, io.EOF
		}
		if n != 0 || len(b) == 0 {
			return n, nil
		}
		if c.destroyed {
			return 0, errors.New("destroyed")
		}
		if c.closed {
			return 0, errors.New("closed")
		}
		if !c.readDeadline.IsZero() && !time.Now().Before(c.readDeadline) {
			return 0, errDeadlineExceeded{}
		}
		c.cond.Wait()
	}
}

func (c *Conn) Write(b []byte) (int, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	n := 0
	for len(b) != 0 {
		if c.closed {
			return n, errors.New("closed")
		}
		n1 := C.utp_write(c.s, unsafe.Pointer(&b[0]), C.size_t(len(b)))
		if n1 < 0 {
			panic(n1)
		}
		b = b[n1:]
		n += int(n1)
		if n1 == 0 {
			if !c.writeDeadline.IsZero() && !time.Now().Before(c.writeDeadline) {
				return n, errDeadlineExceeded{}
			}
			c.cond.Wait()
		}
	}
	return n, nil
}

func (c *Conn) RemoteAddr() net.Addr {
	var rsa syscall.RawSockaddrAny
	var addrlen C.socklen_t = syscall.SizeofSockaddrAny
	C.utp_getpeername(c.s, (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), &addrlen)
	sa, err := anyToSockaddr(&rsa)
	if err != nil {
		panic(err)
	}
	return sockaddrToUDP(sa)
}

func (c *Conn) SetDeadline(t time.Time) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.readDeadline = t
	c.writeDeadline = t
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetReadDeadline(t time.Time) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.readDeadline = t
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetWriteDeadline(t time.Time) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.writeDeadline = t
	c.cond.Broadcast()
	return nil
}

func connForLibSocket(us *C.utp_socket) *Conn {
	return libSocketToConn[us]
}

func (c *Conn) setGotEOF() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.gotEOF = true
	c.cond.Broadcast()
}

func (c *Conn) onStateDestroying() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.destroyed = true
	c.cond.Broadcast()
}
<|endoftext|>


<commit_before>package geo

import (
	"encoding/hex"
	"errors"
	"math"
)

var (
	// ErrUnsupportedDataType is returned by Scan methods when asked to scan
	// non []byte data from the database. This should never happen
	// if the driver is acting appropriately.
	ErrUnsupportedDataType = errors.New("go.geo: scan value must be []byte")

	// ErrNotWKB is returned when unmarshalling WKB and the data is not valid.
	ErrNotWKB = errors.New("go.geo: invalid WKB data")

	// ErrIncorrectGeometry is returned when unmarshalling WKB data into the wrong type.
	// For example, unmarshaling linestring data into a point.
	ErrIncorrectGeometry = errors.New("go.geo: incorrect geometry")
)

// NewPointFromWKB will take raw WKB and set the data for a new point.
// The WKB data must be of type Point. Will return nil if invalid WKB point.
func NewPointFromWKB(wkb []byte) *Point {
	p := &Point{}
	if err := p.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return p
}

// NewLineFromWKB will take raw WKB and set the data for a new line.
// The WKB data must of type LineString and only contain 2 points.
// Will return nil if invalid WKB.
func NewLineFromWKB(wkb []byte) *Line {
	l := &Line{}
	if err := l.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return l
}

// NewPointSetFromWKB will take raw WKB and set the data for a new point set.
// The WKB data must be of type LineString, Polygon or MultiPoint.
// Will return nil if invalid WKB.
func NewPointSetFromWKB(wkb []byte) *PointSet {
	ps := &PointSet{}
	if err := ps.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return ps
}

// NewPathFromWKB will take raw WKB and set the data for a new path.
// The WKB data must be of type LineString, Polygon or MultiPoint.
// Will return nil if invalid WKB.
func NewPathFromWKB(wkb []byte) *Path {
	p := NewPath()
	if err := p.PointSet.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return p
}

// Scan implements the sql.Scanner interface allowing
// point structs to be passed into rows.Scan(...interface{})
// The column must be of type Point and must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if the data is of the right size.
// If the column is empty (not null) an empty point (0, 0) will be returned.
func (p *Point) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if !ok {
		return ErrUnsupportedDataType
	}

	//string of hex workaround
	//[]byte passed is a string of hex hence the need to decode hex string to real []byte
	if len(data) == 42 {
		dst := make([]byte, 21)
		_, err := hex.Decode(dst, data)
		if err != nil {
			return err
		}
	}

	if len(data) == 21 {
		// the length of a point type in WKB
		return p.unmarshalWKB(data)
	}

	if len(data) == 25 {
		// Most likely MySQL's SRID+WKB format.
		// However, could be a line string or multipoint with only one point.
		// But those would be invalid for parsing a point.
		return p.unmarshalWKB(data[4:])
	}

	if len(data) == 0 {
		// empty data, return empty go struct which in this case
		// would be [0,0]
		return nil
	}

	return ErrIncorrectGeometry
}

func (p *Point) unmarshalXY(data []byte, littleEndian bool) {
	p[0] = scanFloat64(data[:8], littleEndian)
	p[1] = scanFloat64(data[8:16], littleEndian)
}

func (p *Point) unmarshalWKB(data []byte) error {
	if len(data) != 21 {
		return ErrNotWKB
	}

	littleEndian, typeCode, err := scanPrefix(data)
	if err != nil {
		return err
	}

	if typeCode != 1 {
		return ErrIncorrectGeometry
	}

	p.unmarshalXY(data[5:], littleEndian)

	return nil
}

// Scan implements the sql.Scanner interface allowing
// line structs to be passed into rows.Scan(...interface{})
// The column must be of type LineString and contain 2 points,
// or an error will be returned. Data must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if the data is of the right size.
// If the column is empty (not null) an empty line [(0, 0), (0, 0)] will be returned.
func (l *Line) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if !ok {
		return ErrUnsupportedDataType
	}

	if len(data) == 41 {
		// the length of a 2 point linestring type in WKB
		return l.unmarshalWKB(data)
	}

	if len(data) == 45 {
		// Most likely MySQL's SRID+WKB format.
		// However, could be some encoding of another type.
		// But those would be invalid for parsing a line.
		return l.unmarshalWKB(data[4:])
	}

	if len(data) == 0 {
		return nil
	}

	return ErrIncorrectGeometry
}

func (l *Line) unmarshalWKB(data []byte) error {
	if len(data) != 41 {
		return ErrNotWKB
	}

	littleEndian, typeCode, err := scanPrefix(data)
	if err != nil {
		return err
	}

	if typeCode != 2 {
		return ErrIncorrectGeometry
	}

	length := scanUint32(data[5:9], littleEndian)
	if length != 2 {
		return ErrIncorrectGeometry
	}

	l.a.unmarshalXY(data[9:], littleEndian)
	l.b.unmarshalXY(data[25:], littleEndian)

	return nil
}

// Scan implements the sql.Scanner interface allowing
// line structs to be passed into rows.Scan(...interface{})
// The column must be of type LineString, Polygon or MultiPoint
// or an error will be returned. Data must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if obviously no WKB
// or parsing as WKB fails.
// If the column is empty (not null) an empty point set will be returned.
func (ps *PointSet) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if !ok {
		return ErrUnsupportedDataType
	}

	if len(data) == 0 {
		return nil
	}

	if len(data) < 6 {
		return ErrNotWKB
	}

	// first byte of real WKB data indicates endian and should 1 or 0.
	if data[0] == 0 || data[0] == 1 {
		return ps.unmarshalWKB(data)
	}

	return ps.unmarshalWKB(data[4:])
}

func (ps *PointSet) unmarshalLinearRing(data []byte, littleEndian bool) error {
	const pointSize = 16
	length := int(scanUint32(data[:4], littleEndian))
	if len(data) != 4+pointSize*length {
		return ErrNotWKB
	}
	points := make([]Point, length)
	for i := 0; i < length; i++ {
		points[i].unmarshalXY(data[4+pointSize*i:], littleEndian)
	}
	ps.SetPoints(points)
	return nil
}

func (ps *PointSet) unmarshalWKB(data []byte) error {
	if len(data) < 6 {
		return ErrNotWKB
	}

	littleEndian, typeCode, err := scanPrefix(data)
	if err != nil {
		return err
	}

	switch typeCode {
	case 2: // LineString
		return ps.unmarshalLinearRing(data[5:], littleEndian)
	case 3: // Polygon
		// For polygons there is a ring count.
		// We only allow one ring here.
		numRings := int(scanUint32(data[5:9], littleEndian))
		if numRings != 1 {
			return ErrIncorrectGeometry
		}
		return ps.unmarshalLinearRing(data[9:], littleEndian)
	case 4: // MultiPoint
		const wkbPointSize = 1 + 4 + 16
		length := int(scanUint32(data[5:9], littleEndian))
		if len(data) != 9+wkbPointSize*length {
			return ErrNotWKB
		}
		points := make([]Point, length)
		for i := 0; i < length; i++ {
			if err := points[i].unmarshalWKB(data[9+wkbPointSize*i : 9+wkbPointSize*i+wkbPointSize]); err != nil {
				return err
			}
		}
		ps.SetPoints(points)
	default:
		return ErrIncorrectGeometry
	}

	return nil
}

// Scan implements the sql.Scanner interface allowing
// line structs to be passed into rows.Scan(...interface{})
// The column must be of type LineString, Polygon or MultiPoint
// or an error will be returned. Data must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if obviously no WKB
// or parsing as WKB fails.
// If the column is empty (not null) an empty path will be returned.
func (p *Path) Scan(value interface{}) error {
	return p.PointSet.Scan(value)
}

func scanPrefix(data []byte) (bool, uint32, error) {
	if len(data) < 6 {
		return false, 0, ErrNotWKB
	}

	if data[0] == 0 {
		return false, scanUint32(data[1:5], false), nil
	}

	if data[0] == 1 {
		return true, scanUint32(data[1:5], true), nil
	}

	return false, 0, ErrNotWKB
}

func scanUint32(data []byte, littleEndian bool) uint32 {
	var v uint32

	if littleEndian {
		for i := 3; i >= 0; i-- {
			v <<= 8
			v |= uint32(data[i])
		}
	} else {
		for i := 0; i < 4; i++ {
			v <<= 8
			v |= uint32(data[i])
		}
	}

	return v
}

func scanFloat64(data []byte, littleEndian bool) float64 {
	var v uint64

	if littleEndian {
		for i := 7; i >= 0; i-- {
			v <<= 8
			v |= uint64(data[i])
		}
	} else {
		for i := 0; i < 8; i++ {
			v <<= 8
			v |= uint64(data[i])
		}
	}

	return math.Float64frombits(v)
}
<commit_msg>missing reassignment<commit_after>package geo

import (
	"encoding/hex"
	"errors"
	"math"
)

var (
	// ErrUnsupportedDataType is returned by Scan methods when asked to scan
	// non []byte data from the database. This should never happen
	// if the driver is acting appropriately.
	ErrUnsupportedDataType = errors.New("go.geo: scan value must be []byte")

	// ErrNotWKB is returned when unmarshalling WKB and the data is not valid.
	ErrNotWKB = errors.New("go.geo: invalid WKB data")

	// ErrIncorrectGeometry is returned when unmarshalling WKB data into the wrong type.
	// For example, unmarshaling linestring data into a point.
	ErrIncorrectGeometry = errors.New("go.geo: incorrect geometry")
)

// NewPointFromWKB will take raw WKB and set the data for a new point.
// The WKB data must be of type Point. Will return nil if invalid WKB point.
func NewPointFromWKB(wkb []byte) *Point {
	p := &Point{}
	if err := p.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return p
}

// NewLineFromWKB will take raw WKB and set the data for a new line.
// The WKB data must of type LineString and only contain 2 points.
// Will return nil if invalid WKB.
func NewLineFromWKB(wkb []byte) *Line {
	l := &Line{}
	if err := l.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return l
}

// NewPointSetFromWKB will take raw WKB and set the data for a new point set.
// The WKB data must be of type LineString, Polygon or MultiPoint.
// Will return nil if invalid WKB.
func NewPointSetFromWKB(wkb []byte) *PointSet {
	ps := &PointSet{}
	if err := ps.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return ps
}

// NewPathFromWKB will take raw WKB and set the data for a new path.
// The WKB data must be of type LineString, Polygon or MultiPoint.
// Will return nil if invalid WKB.
func NewPathFromWKB(wkb []byte) *Path {
	p := NewPath()
	if err := p.PointSet.unmarshalWKB(wkb); err != nil {
		return nil
	}

	return p
}

// Scan implements the sql.Scanner interface allowing
// point structs to be passed into rows.Scan(...interface{})
// The column must be of type Point and must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if the data is of the right size.
// If the column is empty (not null) an empty point (0, 0) will be returned.
func (p *Point) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if !ok {
		return ErrUnsupportedDataType
	}

	//string of hex workaround
	//[]byte passed is a string of hex hence the need to decode hex string to real []byte
	if len(data) == 42 {
		dst := make([]byte, 21)
		_, err := hex.Decode(dst, data)
		if err != nil {
			return err
		}
		data = dst
	}

	if len(data) == 21 {
		// the length of a point type in WKB
		return p.unmarshalWKB(data)
	}

	if len(data) == 25 {
		// Most likely MySQL's SRID+WKB format.
		// However, could be a line string or multipoint with only one point.
		// But those would be invalid for parsing a point.
		return p.unmarshalWKB(data[4:])
	}

	if len(data) == 0 {
		// empty data, return empty go struct which in this case
		// would be [0,0]
		return nil
	}

	return ErrIncorrectGeometry
}

func (p *Point) unmarshalXY(data []byte, littleEndian bool) {
	p[0] = scanFloat64(data[:8], littleEndian)
	p[1] = scanFloat64(data[8:16], littleEndian)
}

func (p *Point) unmarshalWKB(data []byte) error {
	if len(data) != 21 {
		return ErrNotWKB
	}

	littleEndian, typeCode, err := scanPrefix(data)
	if err != nil {
		return err
	}

	if typeCode != 1 {
		return ErrIncorrectGeometry
	}

	p.unmarshalXY(data[5:], littleEndian)

	return nil
}

// Scan implements the sql.Scanner interface allowing
// line structs to be passed into rows.Scan(...interface{})
// The column must be of type LineString and contain 2 points,
// or an error will be returned. Data must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if the data is of the right size.
// If the column is empty (not null) an empty line [(0, 0), (0, 0)] will be returned.
func (l *Line) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if !ok {
		return ErrUnsupportedDataType
	}

	if len(data) == 41 {
		// the length of a 2 point linestring type in WKB
		return l.unmarshalWKB(data)
	}

	if len(data) == 45 {
		// Most likely MySQL's SRID+WKB format.
		// However, could be some encoding of another type.
		// But those would be invalid for parsing a line.
		return l.unmarshalWKB(data[4:])
	}

	if len(data) == 0 {
		return nil
	}

	return ErrIncorrectGeometry
}

func (l *Line) unmarshalWKB(data []byte) error {
	if len(data) != 41 {
		return ErrNotWKB
	}

	littleEndian, typeCode, err := scanPrefix(data)
	if err != nil {
		return err
	}

	if typeCode != 2 {
		return ErrIncorrectGeometry
	}

	length := scanUint32(data[5:9], littleEndian)
	if length != 2 {
		return ErrIncorrectGeometry
	}

	l.a.unmarshalXY(data[9:], littleEndian)
	l.b.unmarshalXY(data[25:], littleEndian)

	return nil
}

// Scan implements the sql.Scanner interface allowing
// line structs to be passed into rows.Scan(...interface{})
// The column must be of type LineString, Polygon or MultiPoint
// or an error will be returned. Data must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if obviously no WKB
// or parsing as WKB fails.
// If the column is empty (not null) an empty point set will be returned.
func (ps *PointSet) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if !ok {
		return ErrUnsupportedDataType
	}

	if len(data) == 0 {
		return nil
	}

	if len(data) < 6 {
		return ErrNotWKB
	}

	// first byte of real WKB data indicates endian and should 1 or 0.
	if data[0] == 0 || data[0] == 1 {
		return ps.unmarshalWKB(data)
	}

	return ps.unmarshalWKB(data[4:])
}

func (ps *PointSet) unmarshalLinearRing(data []byte, littleEndian bool) error {
	const pointSize = 16
	length := int(scanUint32(data[:4], littleEndian))
	if len(data) != 4+pointSize*length {
		return ErrNotWKB
	}
	points := make([]Point, length)
	for i := 0; i < length; i++ {
		points[i].unmarshalXY(data[4+pointSize*i:], littleEndian)
	}
	ps.SetPoints(points)
	return nil
}

func (ps *PointSet) unmarshalWKB(data []byte) error {
	if len(data) < 6 {
		return ErrNotWKB
	}

	littleEndian, typeCode, err := scanPrefix(data)
	if err != nil {
		return err
	}

	switch typeCode {
	case 2: // LineString
		return ps.unmarshalLinearRing(data[5:], littleEndian)
	case 3: // Polygon
		// For polygons there is a ring count.
		// We only allow one ring here.
		numRings := int(scanUint32(data[5:9], littleEndian))
		if numRings != 1 {
			return ErrIncorrectGeometry
		}
		return ps.unmarshalLinearRing(data[9:], littleEndian)
	case 4: // MultiPoint
		const wkbPointSize = 1 + 4 + 16
		length := int(scanUint32(data[5:9], littleEndian))
		if len(data) != 9+wkbPointSize*length {
			return ErrNotWKB
		}
		points := make([]Point, length)
		for i := 0; i < length; i++ {
			if err := points[i].unmarshalWKB(data[9+wkbPointSize*i : 9+wkbPointSize*i+wkbPointSize]); err != nil {
				return err
			}
		}
		ps.SetPoints(points)
	default:
		return ErrIncorrectGeometry
	}

	return nil
}

// Scan implements the sql.Scanner interface allowing
// line structs to be passed into rows.Scan(...interface{})
// The column must be of type LineString, Polygon or MultiPoint
// or an error will be returned. Data must be fetched in WKB format.
// Will attempt to parse MySQL's SRID+WKB format if obviously no WKB
// or parsing as WKB fails.
// If the column is empty (not null) an empty path will be returned.
func (p *Path) Scan(value interface{}) error {
	return p.PointSet.Scan(value)
}

func scanPrefix(data []byte) (bool, uint32, error) {
	if len(data) < 6 {
		return false, 0, ErrNotWKB
	}

	if data[0] == 0 {
		return false, scanUint32(data[1:5], false), nil
	}

	if data[0] == 1 {
		return true, scanUint32(data[1:5], true), nil
	}

	return false, 0, ErrNotWKB
}

func scanUint32(data []byte, littleEndian bool) uint32 {
	var v uint32

	if littleEndian {
		for i := 3; i >= 0; i-- {
			v <<= 8
			v |= uint32(data[i])
		}
	} else {
		for i := 0; i < 4; i++ {
			v <<= 8
			v |= uint32(data[i])
		}
	}

	return v
}

func scanFloat64(data []byte, littleEndian bool) float64 {
	var v uint64

	if littleEndian {
		for i := 7; i >= 0; i-- {
			v <<= 8
			v |= uint64(data[i])
		}
	} else {
		for i := 0; i < 8; i++ {
			v <<= 8
			v |= uint64(data[i])
		}
	}

	return math.Float64frombits(v)
}
<|endoftext|>