<commit_before>package maps

import (
	"fmt"
	"image"
	"image/draw"
	"math"

	"github.com/ryankurte/go-mapbox/lib/base"
	"image/color"
)

// Tile is a wrapper around an image that includes positioning data
type Tile struct {
	draw.Image
	Level uint64 // Tile zoom level
	Size  uint64 // Tile size
	X, Y  uint64 // Tile X and Y postions (Web Mercurator projection)
}

const (
	SizeStandard uint64 = 256
	SizeHighDPI  uint64 = 512
)

// NewTile creates a tile with a base RGBA object
func NewTile(x, y, level, size uint64, src image.Image) Tile {
	// Convert image to RGBA
	b := src.Bounds()
	m := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
	draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)

	return Tile{
		Image: m,
		X:     x,
		Y:     y,
		Level: level,
		Size:  size,
	}
}

// Clone helper clones a tile instance with a new base image
func (t *Tile) Clone() Tile {
	n := *t
	b := t.Bounds()
	n.Image = image.NewRGBA(b)
	draw.Draw(n.Image, b, t, b.Min, draw.Src)
	return n
}

// LocationToPixel translates a global location to a pixel on the tile
func (t *Tile) LocationToPixel(loc base.Location) (float64, float64, error) {
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	offsetX, offsetY := x-float64(t.X*t.Size), y-float64(t.Y*t.Size)

	if xMax := float64(t.Image.Bounds().Max.X); (offsetX < 0) || (offsetX > xMax) {
		return 0, 0, fmt.Errorf("Tile LocationToPixel error: global X offset not within tile space (x: %d max: %d)", offsetX, int(xMax))
	}
	if yMax := float64(t.Image.Bounds().Max.Y); (offsetY < 0) || (offsetY > yMax) {
		return 0, 0, fmt.Errorf("Tile LocationToPixel error: global Y offset not within tile space (y: %d max: %d)", offsetY, int(yMax))
	}

	return offsetX, offsetY, nil
}

// PixelToLocation translates a pixel location in the tile into a global location
func (t *Tile) PixelToLocation(x, y float64) (*base.Location, error) {
	if xMax := float64(t.Image.Bounds().Max.X); (x < 0) || (x > xMax) {
		return nil, fmt.Errorf("Tile LocationToPixel error: global X offset not within tile space (x: %.2f max: %d)", x, int(xMax))
	}
	if yMax := float64(t.Image.Bounds().Max.Y); (y < 0) || (y > yMax) {
		return nil, fmt.Errorf("Tile LocationToPixel error: global Y offset not within tile space (y: %.2f max: %d)", y, int(yMax))
	}

	offsetX, offsetY := x+float64(t.X*t.Size), y+float64(t.Y*t.Size)
	lat, lng := MercatorPixelToLocation(offsetX, offsetY, t.Level, t.Size)

	return &base.Location{Latitude: lat, Longitude: lng}, nil
}

// Justify sets image offsets for drawing
type Justify string

// Constant justification types
const (
	JustifyTop    Justify = "top"
	JustifyLeft   Justify = "left"
	JustifyCenter Justify = "center"
	JustifyBottom Justify = "bottom"
	JustifyRight  Justify = "right"
)

// DrawConfig configures image drawing
type DrawConfig struct {
	Vertical   Justify
	Horizontal Justify
}

// Center preconfigured centering helper
var Center = DrawConfig{JustifyCenter, JustifyCenter}

// DrawLocalXY draws the provided image at the local X/Y coordinates
func (t *Tile) DrawLocalXY(src image.Image, x, y int, config DrawConfig) error {
	dp := image.Point{}

	switch config.Horizontal {
	case JustifyLeft:
		dp.X = x
	case JustifyCenter:
		dp.X = x - src.Bounds().Dx()/2
	case JustifyRight:
		dp.X = x - src.Bounds().Dx()
	default:
		return fmt.Errorf("Unsupported horizontal justification (%s)", config.Horizontal)
	}

	switch config.Vertical {
	case JustifyTop:
		dp.Y = y
	case JustifyCenter:
		dp.Y = y - src.Bounds().Dy()/2
	case JustifyBottom:
		dp.Y = y - src.Bounds().Dy()
	default:
		return fmt.Errorf("Unsupported vertical justification (%s)", config.Horizontal)
	}

	r := image.Rectangle{dp, dp.Add(src.Bounds().Size())}
	draw.Draw(t.Image.(draw.Image), r, src, src.Bounds().Min, draw.Over)

	return nil
}

func (t *Tile) translateGlobalToLocalXY(x, y int) (int, int, error) {
	offsetX := x - int(t.X*t.Size)
	offsetY := y - int(t.Y*t.Size)

	if xMax := int(t.Image.Bounds().Max.X); (offsetX < 0) || (offsetX > xMax) {
		return 0, 0, fmt.Errorf("Tile DrawGlobalXY error: global X offset not within tile space (x: %d max: %d)", offsetX, xMax)
	}
	if yMax := int(t.Image.Bounds().Max.Y); (offsetY < 0) || (offsetY > yMax) {
		return 0, 0, fmt.Errorf("Tile DrawGlobalXY error: global Y offset not within tile space (y: %d max: %d)", offsetY, yMax)
	}

	return offsetX, offsetY, nil
}

// DrawGlobalXY draws the provided image at the global X/Y coordinates
func (t *Tile) DrawGlobalXY(src image.Image, x, y int, config DrawConfig) error {
	offsetX, offsetY, err := t.translateGlobalToLocalXY(x, y)
	if err != nil {
		return err
	}
	t.DrawLocalXY(src, offsetX, offsetY, config)
	return nil
}

// DrawLocation draws the provided image at the provided lat lng
func (t *Tile) DrawLocation(src image.Image, loc base.Location, config DrawConfig) {
	// Calculate location in pixel space
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	t.DrawGlobalXY(src, int(x), int(y), config)
}

// Interpolate function to be passed to generic line interpolator
type Interpolate func(pixel color.Color) color.Color

// InterpolateLocalXY interpolates a line between two local points and calls the interpolate function on each point
func (t *Tile) InterpolateLocalXY(x1, y1, x2, y2 int, interpolate Interpolate) {
	// This is a bit insane because the ordering between (x1, y1) and (x2, y2) must be preserved
	// So that points

	dx := int(float64(x2) - float64(x1))
	dy := int(float64(y2) - float64(y1))

	len := int(math.Sqrt(math.Pow(float64(dx), 2) + math.Pow(float64(dy), 2)))

	img := t.Image.(draw.Image)

	for i := 0; i < len; i++ {
		x := x1 + i*dx/len
		y := y1 + i*dy/len
		pixel := interpolate(img.At(x, y))
		img.Set(x, y, pixel)
	}
}

// InterpolateGlobalXY interpolates a line between two global points and calls the interpolate function on each point
func (t *Tile) InterpolateGlobalXY(x1, y1, x2, y2 int, interpolate Interpolate) error {
	offsetX1, offsetY1, err := t.translateGlobalToLocalXY(x1, y1)
	if err != nil {
		return err
	}
	offsetX2, offsetY2, err := t.translateGlobalToLocalXY(x2, y2)
	if err != nil {
		return err
	}
	t.InterpolateLocalXY(offsetX1, offsetY1, offsetX2, offsetY2, interpolate)
	return nil
}

// InterpolateLocations interpolates a line between two locations and calls the interpolate function on each point
func (t *Tile) InterpolateLocations(loc1, loc2 base.Location, interpolate Interpolate) error {
	x1, y1 := MercatorLocationToPixel(loc1.Latitude, loc1.Longitude, t.Level, t.Size)
	x2, y2 := MercatorLocationToPixel(loc2.Latitude, loc2.Longitude, t.Level, t.Size)
	return t.InterpolateGlobalXY(int(x1), int(y1), int(x2), int(y2), interpolate)
}

// DrawLine uses InterpolateLocations to draw a line between two points
func (t *Tile) DrawLine(loc1, loc2 base.Location, c color.Color) {
	t.InterpolateLocations(loc1, loc2, func(color.Color) color.Color {
		return c
	})
}

func (t *Tile) DrawPoint(loc base.Location, size uint64, c color.Color) error {
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	offsetX, offsetY, err := t.translateGlobalToLocalXY(int(x), int(y))
	if err != nil {
		return err
	}
	img := t.Image.(draw.Image)

	for x := uint64(0); x < size; x++ {
		for y := uint64(0); y < size; y++ {
			img.Set(offsetX+int(x-size/2), offsetY+int(y-size/2), c)
		}
	}

	return nil
}

func (t *Tile) GetAltitude(loc base.Location) (float64, error) {
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	offsetX, offsetY, err := t.translateGlobalToLocalXY(int(x), int(y))
	if err != nil {
		return 0.0, err
	}
	p := t.Image.At(offsetX, offsetY).(color.NRGBA)
	return PixelToHeight(p.R, p.G, p.B), nil
}

func (t *Tile) InterpolateAltitudes(loc1, loc2 base.Location) []float64 {
	altitudes := make([]float64, 0)
	t.InterpolateLocations(loc1, loc2, func(c color.Color) color.Color {
		p := c.(color.NRGBA)
		alt := PixelToHeight(p.R, p.G, p.B)
		altitudes = append(altitudes, alt)
		return c
	})
	return altitudes
}

func (t *Tile) GetHighestAltitude() float64 {
	p := t.Image.At(0, 0).(color.NRGBA)
	max := PixelToHeight(p.R, p.G, p.B)
	for y := 0; y < t.Image.Bounds().Dy(); y++ {
		for x := 0; x < t.Image.Bounds().Dx(); x++ {
			p := t.Image.At(x, y).(color.NRGBA)
			alt := PixelToHeight(p.R, p.G, p.B)
			if alt > max {
				max = alt
			}
		}
	}
	return max
}

func (t *Tile) FlattenAltitudes(maxHeight float64) Tile {
	img := image.NewNRGBA(t.Image.Bounds())

	for y := 0; y < t.Image.Bounds().Dy(); y++ {
		for x := 0; x < t.Image.Bounds().Dx(); x++ {
			p := t.Image.At(x, y).(color.NRGBA)
			alt := uint8(PixelToHeight(p.R, p.G, p.B) / maxHeight * 255)
			img.Set(x, y, color.RGBA{R: alt, G: alt, B: alt, A: 255})
		}
	}

	return NewTile(t.X, t.Y, t.Level, t.Size, img)
}
<commit_msg>fix for error formatting<commit_after>package maps

import (
	"fmt"
	"image"
	"image/draw"
	"math"

	"github.com/ryankurte/go-mapbox/lib/base"
	"image/color"
)

// Tile is a wrapper around an image that includes positioning data
type Tile struct {
	draw.Image
	Level uint64 // Tile zoom level
	Size  uint64 // Tile size
	X, Y  uint64 // Tile X and Y postions (Web Mercurator projection)
}

const (
	SizeStandard uint64 = 256
	SizeHighDPI  uint64 = 512
)

// NewTile creates a tile with a base RGBA object
func NewTile(x, y, level, size uint64, src image.Image) Tile {
	// Convert image to RGBA
	b := src.Bounds()
	m := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
	draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)

	return Tile{
		Image: m,
		X:     x,
		Y:     y,
		Level: level,
		Size:  size,
	}
}

// Clone helper clones a tile instance with a new base image
func (t *Tile) Clone() Tile {
	n := *t
	b := t.Bounds()
	n.Image = image.NewRGBA(b)
	draw.Draw(n.Image, b, t, b.Min, draw.Src)
	return n
}

// LocationToPixel translates a global location to a pixel on the tile
func (t *Tile) LocationToPixel(loc base.Location) (float64, float64, error) {
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	offsetX, offsetY := x-float64(t.X*t.Size), y-float64(t.Y*t.Size)

	if xMax := float64(t.Image.Bounds().Max.X); (offsetX < 0) || (offsetX > xMax) {
		return 0, 0, fmt.Errorf("Tile LocationToPixel error: global X offset not within tile space (x: %.2f max: %d)", offsetX, int(xMax))
	}
	if yMax := float64(t.Image.Bounds().Max.Y); (offsetY < 0) || (offsetY > yMax) {
		return 0, 0, fmt.Errorf("Tile LocationToPixel error: global Y offset not within tile space (y: %.2f max: %d)", offsetY, int(yMax))
	}

	return offsetX, offsetY, nil
}

// PixelToLocation translates a pixel location in the tile into a global location
func (t *Tile) PixelToLocation(x, y float64) (*base.Location, error) {
	if xMax := float64(t.Image.Bounds().Max.X); (x < 0) || (x > xMax) {
		return nil, fmt.Errorf("Tile LocationToPixel error: global X offset not within tile space (x: %.2f max: %d)", x, int(xMax))
	}
	if yMax := float64(t.Image.Bounds().Max.Y); (y < 0) || (y > yMax) {
		return nil, fmt.Errorf("Tile LocationToPixel error: global Y offset not within tile space (y: %.2f max: %d)", y, int(yMax))
	}

	offsetX, offsetY := x+float64(t.X*t.Size), y+float64(t.Y*t.Size)
	lat, lng := MercatorPixelToLocation(offsetX, offsetY, t.Level, t.Size)

	return &base.Location{Latitude: lat, Longitude: lng}, nil
}

// Justify sets image offsets for drawing
type Justify string

// Constant justification types
const (
	JustifyTop    Justify = "top"
	JustifyLeft   Justify = "left"
	JustifyCenter Justify = "center"
	JustifyBottom Justify = "bottom"
	JustifyRight  Justify = "right"
)

// DrawConfig configures image drawing
type DrawConfig struct {
	Vertical   Justify
	Horizontal Justify
}

// Center preconfigured centering helper
var Center = DrawConfig{JustifyCenter, JustifyCenter}

// DrawLocalXY draws the provided image at the local X/Y coordinates
func (t *Tile) DrawLocalXY(src image.Image, x, y int, config DrawConfig) error {
	dp := image.Point{}

	switch config.Horizontal {
	case JustifyLeft:
		dp.X = x
	case JustifyCenter:
		dp.X = x - src.Bounds().Dx()/2
	case JustifyRight:
		dp.X = x - src.Bounds().Dx()
	default:
		return fmt.Errorf("Unsupported horizontal justification (%s)", config.Horizontal)
	}

	switch config.Vertical {
	case JustifyTop:
		dp.Y = y
	case JustifyCenter:
		dp.Y = y - src.Bounds().Dy()/2
	case JustifyBottom:
		dp.Y = y - src.Bounds().Dy()
	default:
		return fmt.Errorf("Unsupported vertical justification (%s)", config.Horizontal)
	}

	r := image.Rectangle{dp, dp.Add(src.Bounds().Size())}
	draw.Draw(t.Image.(draw.Image), r, src, src.Bounds().Min, draw.Over)

	return nil
}

func (t *Tile) translateGlobalToLocalXY(x, y int) (int, int, error) {
	offsetX := x - int(t.X*t.Size)
	offsetY := y - int(t.Y*t.Size)

	if xMax := int(t.Image.Bounds().Max.X); (offsetX < 0) || (offsetX > xMax) {
		return 0, 0, fmt.Errorf("Tile DrawGlobalXY error: global X offset not within tile space (x: %d max: %d)", offsetX, xMax)
	}
	if yMax := int(t.Image.Bounds().Max.Y); (offsetY < 0) || (offsetY > yMax) {
		return 0, 0, fmt.Errorf("Tile DrawGlobalXY error: global Y offset not within tile space (y: %d max: %d)", offsetY, yMax)
	}

	return offsetX, offsetY, nil
}

// DrawGlobalXY draws the provided image at the global X/Y coordinates
func (t *Tile) DrawGlobalXY(src image.Image, x, y int, config DrawConfig) error {
	offsetX, offsetY, err := t.translateGlobalToLocalXY(x, y)
	if err != nil {
		return err
	}
	t.DrawLocalXY(src, offsetX, offsetY, config)
	return nil
}

// DrawLocation draws the provided image at the provided lat lng
func (t *Tile) DrawLocation(src image.Image, loc base.Location, config DrawConfig) {
	// Calculate location in pixel space
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	t.DrawGlobalXY(src, int(x), int(y), config)
}

// Interpolate function to be passed to generic line interpolator
type Interpolate func(pixel color.Color) color.Color

// InterpolateLocalXY interpolates a line between two local points and calls the interpolate function on each point
func (t *Tile) InterpolateLocalXY(x1, y1, x2, y2 int, interpolate Interpolate) {
	// This is a bit insane because the ordering between (x1, y1) and (x2, y2) must be preserved
	// So that points

	dx := int(float64(x2) - float64(x1))
	dy := int(float64(y2) - float64(y1))

	len := int(math.Sqrt(math.Pow(float64(dx), 2) + math.Pow(float64(dy), 2)))

	img := t.Image.(draw.Image)

	for i := 0; i < len; i++ {
		x := x1 + i*dx/len
		y := y1 + i*dy/len
		pixel := interpolate(img.At(x, y))
		img.Set(x, y, pixel)
	}
}

// InterpolateGlobalXY interpolates a line between two global points and calls the interpolate function on each point
func (t *Tile) InterpolateGlobalXY(x1, y1, x2, y2 int, interpolate Interpolate) error {
	offsetX1, offsetY1, err := t.translateGlobalToLocalXY(x1, y1)
	if err != nil {
		return err
	}
	offsetX2, offsetY2, err := t.translateGlobalToLocalXY(x2, y2)
	if err != nil {
		return err
	}
	t.InterpolateLocalXY(offsetX1, offsetY1, offsetX2, offsetY2, interpolate)
	return nil
}

// InterpolateLocations interpolates a line between two locations and calls the interpolate function on each point
func (t *Tile) InterpolateLocations(loc1, loc2 base.Location, interpolate Interpolate) error {
	x1, y1 := MercatorLocationToPixel(loc1.Latitude, loc1.Longitude, t.Level, t.Size)
	x2, y2 := MercatorLocationToPixel(loc2.Latitude, loc2.Longitude, t.Level, t.Size)
	return t.InterpolateGlobalXY(int(x1), int(y1), int(x2), int(y2), interpolate)
}

// DrawLine uses InterpolateLocations to draw a line between two points
func (t *Tile) DrawLine(loc1, loc2 base.Location, c color.Color) {
	t.InterpolateLocations(loc1, loc2, func(color.Color) color.Color {
		return c
	})
}

func (t *Tile) DrawPoint(loc base.Location, size uint64, c color.Color) error {
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	offsetX, offsetY, err := t.translateGlobalToLocalXY(int(x), int(y))
	if err != nil {
		return err
	}
	img := t.Image.(draw.Image)

	for x := uint64(0); x < size; x++ {
		for y := uint64(0); y < size; y++ {
			img.Set(offsetX+int(x-size/2), offsetY+int(y-size/2), c)
		}
	}

	return nil
}

func (t *Tile) GetAltitude(loc base.Location) (float64, error) {
	x, y := MercatorLocationToPixel(loc.Latitude, loc.Longitude, t.Level, t.Size)
	offsetX, offsetY, err := t.translateGlobalToLocalXY(int(x), int(y))
	if err != nil {
		return 0.0, err
	}
	p := t.Image.At(offsetX, offsetY).(color.NRGBA)
	return PixelToHeight(p.R, p.G, p.B), nil
}

func (t *Tile) InterpolateAltitudes(loc1, loc2 base.Location) []float64 {
	altitudes := make([]float64, 0)
	t.InterpolateLocations(loc1, loc2, func(c color.Color) color.Color {
		p := c.(color.NRGBA)
		alt := PixelToHeight(p.R, p.G, p.B)
		altitudes = append(altitudes, alt)
		return c
	})
	return altitudes
}

func (t *Tile) GetHighestAltitude() float64 {
	p := t.Image.At(0, 0).(color.NRGBA)
	max := PixelToHeight(p.R, p.G, p.B)
	for y := 0; y < t.Image.Bounds().Dy(); y++ {
		for x := 0; x < t.Image.Bounds().Dx(); x++ {
			p := t.Image.At(x, y).(color.NRGBA)
			alt := PixelToHeight(p.R, p.G, p.B)
			if alt > max {
				max = alt
			}
		}
	}
	return max
}

func (t *Tile) FlattenAltitudes(maxHeight float64) Tile {
	img := image.NewNRGBA(t.Image.Bounds())

	for y := 0; y < t.Image.Bounds().Dy(); y++ {
		for x := 0; x < t.Image.Bounds().Dx(); x++ {
			p := t.Image.At(x, y).(color.NRGBA)
			alt := uint8(PixelToHeight(p.R, p.G, p.B) / maxHeight * 255)
			img.Set(x, y, color.RGBA{R: alt, G: alt, B: alt, A: 255})
		}
	}

	return NewTile(t.X, t.Y, t.Level, t.Size, img)
}
<|endoftext|>


<commit_before>package tao

import (
  "bytes"
  "log"
  "net"
  "encoding/binary"
  "errors"
  "sync"
)

const (
  NTYPE = 4
  NLEN = 4
  MAXLEN = 1 << 23  // 8M
)

var ErrorWouldBlock error = errors.New("Would block")

type TcpConnection struct {
  conn *net.TCPConn
  name string
  closeOnce sync.Once
  wg *sync.WaitGroup
  messageSendChan chan Message
  handlerRecvChan chan ProtocolHandler
  closeConnChan chan struct{}
  onConnect onConnectCallbackType
  onMessage onMessageCallbackType
  onClose onCloseCallbackType
  onError onErrorCallbackType
}

func NewTcpConnection(s *TcpServer, c *net.TCPConn) *TcpConnection {
  tcpConn := &TcpConnection {
    conn: c,
    wg: &sync.WaitGroup{},
    messageSendChan: make(chan Message, 1024), // todo: make it configurable
    handlerRecvChan: make(chan ProtocolHandler, 1024), // todo: make it configurable
    closeConnChan: make(chan struct{}),
  }
  if s != nil {
    tcpConn.SetOnConnectCallback(s.onConnect)
    tcpConn.SetOnMessageCallback(s.onMessage)
    tcpConn.SetOnErrorCallback(s.onError)
    tcpConn.SetOnCloseCallback(s.onClose)
  }
  return tcpConn
}

func (client *TcpConnection) SetOnConnectCallback(cb func() bool) {
  if cb != nil {
    client.onConnect = onConnectCallbackType(cb)
  }
}

func (client *TcpConnection) SetOnMessageCallback(cb func(Message, *TcpConnection)) {
  if cb != nil {
    client.onMessage = onMessageCallbackType(cb)
  }
}

func (client *TcpConnection) SetOnErrorCallback(cb func()) {
  if cb != nil {
    client.onError = onErrorCallbackType(cb)
  }
}

func (client *TcpConnection) SetOnCloseCallback(cb func(*TcpConnection)) {
  if cb != nil {
    client.onClose = onCloseCallbackType(cb)
  }
}

func (client *TcpConnection) RemoteAddr() net.Addr {
  return client.conn.RemoteAddr()
}

func (client *TcpConnection) SetName(n string) {
  client.name = n
}

func (client *TcpConnection) String() string {
  return client.name
}

func (client *TcpConnection) Close() {
  client.closeOnce.Do(func() {
    close(client.closeConnChan)
    close(client.messageSendChan)
    close(client.handlerRecvChan)
    client.conn.Close()
    if (client.onClose != nil) {
      client.onClose(client)
    }
  })
}

func (client *TcpConnection) Write(msg Message) (err error) {
  select {
  case client.messageSendChan<- msg:
    return nil
  default:
    return ErrorWouldBlock
  }
}

func (client *TcpConnection) Do() {
  if client.onConnect != nil && !client.onConnect() {
    log.Fatalln("Error onConnect()\n")
  }

  // start read, write and handle loop
  client.startLoop(client.readLoop)
  client.startLoop(client.writeLoop)
  client.startLoop(client.handleLoop)
}

func (client *TcpConnection) startLoop(looper func()) {
  client.wg.Add(1)
  go func() {
    looper()
    client.wg.Done()
  }()
}

// use type-length-value format: |4 bytes|4 bytes|n bytes <= 8M|
func (client *TcpConnection) readLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  typeBytes := make([]byte, NTYPE)
  lengthBytes := make([]byte, NLEN)
  for {
    select {
    case <-client.closeConnChan:
      return

    default:
    }

    // read type info
    if _, err := client.conn.Read(typeBytes); err != nil {
      log.Println(err)
      return
    }
    typeBuf := bytes.NewReader(typeBytes)
    var msgType int32
    if err := binary.Read(typeBuf, binary.BigEndian, &msgType); err != nil {
      log.Fatalln(err)
    }

    // read length info
    if _, err := client.conn.Read(lengthBytes); err != nil {
      log.Println(err)
      return
    }
    lengthBuf := bytes.NewReader(lengthBytes)
    var msgLen uint32
    if err := binary.Read(lengthBuf, binary.BigEndian, &msgLen); err != nil {
      log.Fatalln(err)
    }
    if msgLen > MAXLEN {
      log.Printf("Error more than 8M data:%d\n", msgLen)
      return
    }

    // read real application message
    msgBytes := make([]byte, msgLen)
    if _, err := client.conn.Read(msgBytes); err != nil {
      log.Println(err)
      return
    }

    // deserialize message from bytes
    unmarshaler := MessageMap.get(msgType)
    if unmarshaler == nil {
      log.Printf("Error undefined message %d\n", msgType)
      continue
    }
    var msg Message
    var err error
    if msg, err = unmarshaler(msgBytes); err != nil {
      log.Printf("Error unmarshal message %d\n", msgType)
      continue
    }

    handlerFactory := HandlerMap.get(msgType)
    if handlerFactory == nil {
      log.Printf("message %d call onMessage()\n", msgType)
      client.onMessage(msg, client)
      continue
    }

    // send handler to handleLoop
    handler := handlerFactory(msg)
    client.handlerRecvChan<- handler
  }
}

func (client *TcpConnection) writeLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case msg := <-client.messageSendChan:
      data, err := msg.MarshalBinary();
      if err != nil {
        log.Printf("Error serializing data\n")
        continue
      }
      buf := new(bytes.Buffer)
      binary.Write(buf, binary.BigEndian, msg.MessageNumber())
      binary.Write(buf, binary.BigEndian, int32(len(data)))
      binary.Write(buf, binary.BigEndian, data)
      packet := buf.Bytes()
      if _, err = client.conn.Write(packet); err != nil {
        log.Printf("Error writing data %s\n", err)
      }
    }
  }
}

func (client *TcpConnection) handleLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case handler := <-client.handlerRecvChan:
      // todo: put handler into workers
      handler.Process(client)
    }
  }
}
<commit_msg>add todo comment<commit_after>package tao

import (
  "bytes"
  "log"
  "net"
  "encoding/binary"
  "errors"
  "sync"
)

const (
  NTYPE = 4
  NLEN = 4
  MAXLEN = 1 << 23  // 8M
)

var ErrorWouldBlock error = errors.New("Would block")

type TcpConnection struct {
  conn *net.TCPConn
  name string
  closeOnce sync.Once
  wg *sync.WaitGroup
  messageSendChan chan Message
  handlerRecvChan chan ProtocolHandler
  closeConnChan chan struct{}
  onConnect onConnectCallbackType
  onMessage onMessageCallbackType
  onClose onCloseCallbackType
  onError onErrorCallbackType
}

func NewTcpConnection(s *TcpServer, c *net.TCPConn) *TcpConnection {
  tcpConn := &TcpConnection {
    conn: c,
    wg: &sync.WaitGroup{},
    messageSendChan: make(chan Message, 1024), // todo: make it configurable
    handlerRecvChan: make(chan ProtocolHandler, 1024), // todo: make it configurable
    closeConnChan: make(chan struct{}),
  }
  if s != nil {
    tcpConn.SetOnConnectCallback(s.onConnect)
    tcpConn.SetOnMessageCallback(s.onMessage)
    tcpConn.SetOnErrorCallback(s.onError)
    tcpConn.SetOnCloseCallback(s.onClose)
  }
  return tcpConn
}

func (client *TcpConnection) SetOnConnectCallback(cb func() bool) {
  if cb != nil {
    client.onConnect = onConnectCallbackType(cb)
  }
}

func (client *TcpConnection) SetOnMessageCallback(cb func(Message, *TcpConnection)) {
  if cb != nil {
    client.onMessage = onMessageCallbackType(cb)
  }
}

func (client *TcpConnection) SetOnErrorCallback(cb func()) {
  if cb != nil {
    client.onError = onErrorCallbackType(cb)
  }
}

func (client *TcpConnection) SetOnCloseCallback(cb func(*TcpConnection)) {
  if cb != nil {
    client.onClose = onCloseCallbackType(cb)
  }
}

func (client *TcpConnection) RemoteAddr() net.Addr {
  return client.conn.RemoteAddr()
}

func (client *TcpConnection) SetName(n string) {
  client.name = n
}

func (client *TcpConnection) String() string {
  return client.name
}

func (client *TcpConnection) Close() {
  client.closeOnce.Do(func() {
    close(client.closeConnChan)
    close(client.messageSendChan)
    close(client.handlerRecvChan)
    client.conn.Close()
    if (client.onClose != nil) {
      client.onClose(client)
    }
  })
}

func (client *TcpConnection) Write(msg Message) (err error) {
  select {
  case client.messageSendChan<- msg:
    return nil
  default:
    return ErrorWouldBlock
  }
}

func (client *TcpConnection) Do() {
  if client.onConnect != nil && !client.onConnect() {
    log.Fatalln("Error onConnect()\n")
  }

  // start read, write and handle loop
  client.startLoop(client.readLoop)
  client.startLoop(client.writeLoop)
  client.startLoop(client.handleLoop)
}

func (client *TcpConnection) startLoop(looper func()) {
  client.wg.Add(1)
  go func() {
    looper()
    client.wg.Done()
  }()
}

// use type-length-value format: |4 bytes|4 bytes|n bytes <= 8M|
// todo: maybe a special codec?
func (client *TcpConnection) readLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  typeBytes := make([]byte, NTYPE)
  lengthBytes := make([]byte, NLEN)
  for {
    select {
    case <-client.closeConnChan:
      return

    default:
    }

    // read type info
    if _, err := client.conn.Read(typeBytes); err != nil {
      log.Println(err)
      return
    }
    typeBuf := bytes.NewReader(typeBytes)
    var msgType int32
    if err := binary.Read(typeBuf, binary.BigEndian, &msgType); err != nil {
      log.Fatalln(err)
    }

    // read length info
    if _, err := client.conn.Read(lengthBytes); err != nil {
      log.Println(err)
      return
    }
    lengthBuf := bytes.NewReader(lengthBytes)
    var msgLen uint32
    if err := binary.Read(lengthBuf, binary.BigEndian, &msgLen); err != nil {
      log.Fatalln(err)
    }
    if msgLen > MAXLEN {
      log.Printf("Error more than 8M data:%d\n", msgLen)
      return
    }

    // read real application message
    msgBytes := make([]byte, msgLen)
    if _, err := client.conn.Read(msgBytes); err != nil {
      log.Println(err)
      return
    }

    // deserialize message from bytes
    unmarshaler := MessageMap.get(msgType)
    if unmarshaler == nil {
      log.Printf("Error undefined message %d\n", msgType)
      continue
    }
    var msg Message
    var err error
    if msg, err = unmarshaler(msgBytes); err != nil {
      log.Printf("Error unmarshal message %d\n", msgType)
      continue
    }

    handlerFactory := HandlerMap.get(msgType)
    if handlerFactory == nil {
      log.Printf("message %d call onMessage()\n", msgType)
      client.onMessage(msg, client)
      continue
    }

    // send handler to handleLoop
    handler := handlerFactory(msg)
    client.handlerRecvChan<- handler
  }
}

func (client *TcpConnection) writeLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case msg := <-client.messageSendChan:
      data, err := msg.MarshalBinary();
      if err != nil {
        log.Printf("Error serializing data\n")
        continue
      }
      buf := new(bytes.Buffer)
      binary.Write(buf, binary.BigEndian, msg.MessageNumber())
      binary.Write(buf, binary.BigEndian, int32(len(data)))
      binary.Write(buf, binary.BigEndian, data)
      packet := buf.Bytes()
      if _, err = client.conn.Write(packet); err != nil {
        log.Printf("Error writing data %s\n", err)
      }
    }
  }
}

func (client *TcpConnection) handleLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case handler := <-client.handlerRecvChan:
      // todo: put handler into workers
      handler.Process(client)
    }
  }
}
<|endoftext|>


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

package fuse

import (
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"sync"
	"syscall"

	"golang.org/x/net/context"

	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/internal/buffer"
	"github.com/jacobsa/fuse/internal/fusekernel"
	"github.com/jacobsa/fuse/internal/fuseshim"
)

// A connection to the fuse kernel process.
type Connection struct {
	debugLogger *log.Logger
	errorLogger *log.Logger
	wrapped     *fuseshim.Conn

	// The context from which all op contexts inherit.
	parentCtx context.Context

	// For logging purposes only.
	nextOpID uint32

	mu sync.Mutex

	// A map from fuse "unique" request ID (*not* the op ID for logging used
	// above) to a function that cancel's its associated context.
	//
	// GUARDED_BY(mu)
	cancelFuncs map[uint64]func()
}

// Responsibility for closing the wrapped connection is transferred to the
// result. You must call c.close() eventually.
//
// The loggers may be nil.
func newConnection(
	parentCtx context.Context,
	debugLogger *log.Logger,
	errorLogger *log.Logger,
	wrapped *fuseshim.Conn) (c *Connection, err error) {
	c = &Connection{
		debugLogger: debugLogger,
		errorLogger: errorLogger,
		wrapped:     wrapped,
		parentCtx:   parentCtx,
		cancelFuncs: make(map[uint64]func()),
	}

	return
}

// Log information for an operation with the given ID. calldepth is the depth
// to use when recovering file:line information with runtime.Caller.
func (c *Connection) debugLog(
	opID uint32,
	calldepth int,
	format string,
	v ...interface{}) {
	if c.debugLogger == nil {
		return
	}

	// Get file:line info.
	var file string
	var line int
	var ok bool

	_, file, line, ok = runtime.Caller(calldepth)
	if !ok {
		file = "???"
	}

	fileLine := fmt.Sprintf("%v:%v", path.Base(file), line)

	// Format the actual message to be printed.
	msg := fmt.Sprintf(
		"Op 0x%08x %24s] %v",
		opID,
		fileLine,
		fmt.Sprintf(format, v...))

	// Print it.
	c.debugLogger.Println(msg)
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) recordCancelFunc(
	fuseID uint64,
	f func()) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.cancelFuncs[fuseID]; ok {
		panic(fmt.Sprintf("Already have cancel func for request %v", fuseID))
	}

	c.cancelFuncs[fuseID] = f
}

// Set up state for an op that is about to be returned to the user, given its
// underlying fuse opcode and request ID.
//
// Return a context that should be used for the op.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) beginOp(
	opCode uint32,
	fuseID uint64) (ctx context.Context) {
	// Start with the parent context.
	ctx = c.parentCtx

	// Set up a cancellation function.
	//
	// Special case: On Darwin, osxfuse aggressively reuses "unique" request IDs.
	// This matters for Forget requests, which have no reply associated and
	// therefore have IDs that are immediately eligible for reuse. For these, we
	// should not record any state keyed on their ID.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	if opCode != fusekernel.OpForget {
		var cancel func()
		ctx, cancel = context.WithCancel(ctx)
		c.recordCancelFunc(fuseID, cancel)
	}

	return
}

// Clean up all state associated with an op to which the user has responded,
// given its underlying fuse opcode and request ID. This must be called before
// a response is sent to the kernel, to avoid a race where the request's ID
// might be reused by osxfuse.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) finishOp(
	opCode uint32,
	fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Even though the op is finished, context.WithCancel requires us to arrange
	// for the cancellation function to be invoked. We also must remove it from
	// our map.
	//
	// Special case: we don't do this for Forget requests. See the note in
	// beginOp above.
	if opCode != fusekernel.OpForget {
		cancel, ok := c.cancelFuncs[fuseID]
		if !ok {
			panic(fmt.Sprintf("Unknown request ID in finishOp: %v", fuseID))
		}

		cancel()
		delete(c.cancelFuncs, fuseID)
	}
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) handleInterrupt(fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// NOTE(jacobsa): fuse.txt in the Linux kernel documentation
	// (https://goo.gl/H55Dnr) defines the kernel <-> userspace protocol for
	// interrupts.
	//
	// In particular, my reading of it is that an interrupt request cannot be
	// delivered to userspace before the original request. The part about the
	// race and EAGAIN appears to be aimed at userspace programs that
	// concurrently process requests (cf. http://goo.gl/BES2rs).
	//
	// So in this method if we can't find the ID to be interrupted, it means that
	// the request has already been replied to.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	// Cf. http://comments.gmane.org/gmane.comp.file-systems.fuse.devel/14675
	cancel, ok := c.cancelFuncs[fuseID]
	if !ok {
		return
	}

	cancel()
}

func (c *Connection) allocateInMessage() (m *buffer.InMessage) {
	// TODO(jacobsa): Use a freelist.
	m = new(buffer.InMessage)
	return
}

func (c *Connection) destroyInMessage(m *buffer.InMessage) {
	// TODO(jacobsa): Use a freelist.
}

// Read the next message from the kernel. The message must later be destroyed
// using destroyInMessage.
func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
	// Allocate a message.
	m = c.allocateInMessage()

	// Loop past transient errors.
	for {
		// Attempt a reaed.
		err = m.Init(c.wrapped.Dev)

		// Special cases:
		//
		//  *  ENODEV means fuse has hung up.
		//
		//  *  EINTR means we should try again. (This seems to happen often on
		//     OS X, cf. http://golang.org/issue/11180)
		//
		if pe, ok := err.(*os.PathError); ok {
			switch pe.Err {
			case syscall.ENODEV:
				err = io.EOF

			case syscall.EINTR:
				err = nil
				continue
			}
		}

		if err != nil {
			c.destroyInMessage(m)
			m = nil
			return
		}

		return
	}
}

// Read the next op from the kernel process. Return io.EOF if the kernel has
// closed the connection.
//
// This function delivers ops in exactly the order they are received from
// /dev/fuse. It must not be called multiple times concurrently.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) ReadOp() (op fuseops.Op, err error) {
	// Keep going until we find a request we know how to convert.
	for {
		// Read the next message from the kernel.
		var m *buffer.InMessage
		m, err = c.readMessage()
		if err != nil {
			return
		}

		// Choose an ID for this operation for the purposes of logging.
		opID := c.nextOpID
		c.nextOpID++

		// Set up op dependencies.
		opCtx := c.beginOp(m.Header().Opcode, m.Header().Unique)

		var debugLogForOp func(int, string, ...interface{})
		if c.debugLogger != nil {
			debugLogForOp = func(calldepth int, format string, v ...interface{}) {
				c.debugLog(opID, calldepth+1, format, v...)
			}
		}

		sendReply := func(
			op fuseops.Op,
			fuseID uint64,
			replyMsg []byte,
			opErr error) (err error) {
			// Make sure we destroy the message, as required by readMessage.
			defer c.destroyInMessage(m)

			// Clean up state for this op.
			c.finishOp(m.Header().Opcode, m.Header().Unique)

			// Debug logging
			if c.debugLogger != nil {
				if opErr == nil {
					op.Logf("-> OK: %s", op.DebugString())
				} else {
					op.Logf("-> error: %v", opErr)
				}
			}

			// Error logging
			if opErr != nil && c.errorLogger != nil {
				c.errorLogger.Printf("(%s) error: %v", op.ShortDesc(), opErr)
			}

			// Send the reply to the kernel.
			err = c.wrapped.WriteToKernel(replyMsg)
			if err != nil {
				err = fmt.Errorf("WriteToKernel: %v", err)
				return
			}

			return
		}

		// Convert the message to an Op.
		op, err = fuseops.Convert(
			opCtx,
			m,
			c.wrapped.Protocol(),
			debugLogForOp,
			c.errorLogger,
			sendReply)

		if err != nil {
			err = fmt.Errorf("fuseops.Convert: %v", err)
			return
		}

		// Log the receipt of the operation.
		c.debugLog(opID, 1, "<- %v", op.ShortDesc())

		// Special case: responding to statfs is required to make mounting work on
		// OS X. We don't currently expose the capability for the file system to
		// intercept this.
		if _, ok := op.(*fuseops.InternalStatFSOp); ok {
			op.Respond(nil)
			continue
		}

		// Special case: handle interrupt requests.
		if interruptOp, ok := op.(*fuseops.InternalInterruptOp); ok {
			c.handleInterrupt(interruptOp.FuseID)
			continue
		}

		return
	}
}

func (c *Connection) waitForReady() (err error) {
	<-c.wrapped.Ready
	err = c.wrapped.MountError
	return
}

// Close the connection. Must not be called until operations that were read
// from the connection have been responded to.
func (c *Connection) close() (err error) {
	err = c.wrapped.Close()
	return
}
<commit_msg>Don't depend on fuseshim.Conn for sending messages.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fuse

import (
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"sync"
	"syscall"

	"golang.org/x/net/context"

	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/internal/buffer"
	"github.com/jacobsa/fuse/internal/fusekernel"
	"github.com/jacobsa/fuse/internal/fuseshim"
)

// A connection to the fuse kernel process.
type Connection struct {
	debugLogger *log.Logger
	errorLogger *log.Logger
	wrapped     *fuseshim.Conn

	// The context from which all op contexts inherit.
	parentCtx context.Context

	// For logging purposes only.
	nextOpID uint32

	mu sync.Mutex

	// A map from fuse "unique" request ID (*not* the op ID for logging used
	// above) to a function that cancel's its associated context.
	//
	// GUARDED_BY(mu)
	cancelFuncs map[uint64]func()
}

// Responsibility for closing the wrapped connection is transferred to the
// result. You must call c.close() eventually.
//
// The loggers may be nil.
func newConnection(
	parentCtx context.Context,
	debugLogger *log.Logger,
	errorLogger *log.Logger,
	wrapped *fuseshim.Conn) (c *Connection, err error) {
	c = &Connection{
		debugLogger: debugLogger,
		errorLogger: errorLogger,
		wrapped:     wrapped,
		parentCtx:   parentCtx,
		cancelFuncs: make(map[uint64]func()),
	}

	return
}

// Log information for an operation with the given ID. calldepth is the depth
// to use when recovering file:line information with runtime.Caller.
func (c *Connection) debugLog(
	opID uint32,
	calldepth int,
	format string,
	v ...interface{}) {
	if c.debugLogger == nil {
		return
	}

	// Get file:line info.
	var file string
	var line int
	var ok bool

	_, file, line, ok = runtime.Caller(calldepth)
	if !ok {
		file = "???"
	}

	fileLine := fmt.Sprintf("%v:%v", path.Base(file), line)

	// Format the actual message to be printed.
	msg := fmt.Sprintf(
		"Op 0x%08x %24s] %v",
		opID,
		fileLine,
		fmt.Sprintf(format, v...))

	// Print it.
	c.debugLogger.Println(msg)
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) recordCancelFunc(
	fuseID uint64,
	f func()) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.cancelFuncs[fuseID]; ok {
		panic(fmt.Sprintf("Already have cancel func for request %v", fuseID))
	}

	c.cancelFuncs[fuseID] = f
}

// Set up state for an op that is about to be returned to the user, given its
// underlying fuse opcode and request ID.
//
// Return a context that should be used for the op.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) beginOp(
	opCode uint32,
	fuseID uint64) (ctx context.Context) {
	// Start with the parent context.
	ctx = c.parentCtx

	// Set up a cancellation function.
	//
	// Special case: On Darwin, osxfuse aggressively reuses "unique" request IDs.
	// This matters for Forget requests, which have no reply associated and
	// therefore have IDs that are immediately eligible for reuse. For these, we
	// should not record any state keyed on their ID.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	if opCode != fusekernel.OpForget {
		var cancel func()
		ctx, cancel = context.WithCancel(ctx)
		c.recordCancelFunc(fuseID, cancel)
	}

	return
}

// Clean up all state associated with an op to which the user has responded,
// given its underlying fuse opcode and request ID. This must be called before
// a response is sent to the kernel, to avoid a race where the request's ID
// might be reused by osxfuse.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) finishOp(
	opCode uint32,
	fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Even though the op is finished, context.WithCancel requires us to arrange
	// for the cancellation function to be invoked. We also must remove it from
	// our map.
	//
	// Special case: we don't do this for Forget requests. See the note in
	// beginOp above.
	if opCode != fusekernel.OpForget {
		cancel, ok := c.cancelFuncs[fuseID]
		if !ok {
			panic(fmt.Sprintf("Unknown request ID in finishOp: %v", fuseID))
		}

		cancel()
		delete(c.cancelFuncs, fuseID)
	}
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) handleInterrupt(fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// NOTE(jacobsa): fuse.txt in the Linux kernel documentation
	// (https://goo.gl/H55Dnr) defines the kernel <-> userspace protocol for
	// interrupts.
	//
	// In particular, my reading of it is that an interrupt request cannot be
	// delivered to userspace before the original request. The part about the
	// race and EAGAIN appears to be aimed at userspace programs that
	// concurrently process requests (cf. http://goo.gl/BES2rs).
	//
	// So in this method if we can't find the ID to be interrupted, it means that
	// the request has already been replied to.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	// Cf. http://comments.gmane.org/gmane.comp.file-systems.fuse.devel/14675
	cancel, ok := c.cancelFuncs[fuseID]
	if !ok {
		return
	}

	cancel()
}

func (c *Connection) allocateInMessage() (m *buffer.InMessage) {
	// TODO(jacobsa): Use a freelist.
	m = new(buffer.InMessage)
	return
}

func (c *Connection) destroyInMessage(m *buffer.InMessage) {
	// TODO(jacobsa): Use a freelist.
}

// Read the next message from the kernel. The message must later be destroyed
// using destroyInMessage.
func (c *Connection) readMessage() (m *buffer.InMessage, err error) {
	// Allocate a message.
	m = c.allocateInMessage()

	// Loop past transient errors.
	for {
		// Attempt a reaed.
		err = m.Init(c.wrapped.Dev)

		// Special cases:
		//
		//  *  ENODEV means fuse has hung up.
		//
		//  *  EINTR means we should try again. (This seems to happen often on
		//     OS X, cf. http://golang.org/issue/11180)
		//
		if pe, ok := err.(*os.PathError); ok {
			switch pe.Err {
			case syscall.ENODEV:
				err = io.EOF

			case syscall.EINTR:
				err = nil
				continue
			}
		}

		if err != nil {
			c.destroyInMessage(m)
			m = nil
			return
		}

		return
	}
}

// Write the supplied message to the kernel.
func (c *Connection) writeMessage(msg []byte) (err error) {
	// Avoid the retry loop in os.File.Write.
	n, err := syscall.Write(int(c.wrapped.Dev.Fd()), msg)
	if err != nil {
		return
	}

	if n != len(msg) {
		err = fmt.Errorf("Wrote %d bytes; expected %d", n, len(msg))
		return
	}

	return
}

// Read the next op from the kernel process. Return io.EOF if the kernel has
// closed the connection.
//
// This function delivers ops in exactly the order they are received from
// /dev/fuse. It must not be called multiple times concurrently.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) ReadOp() (op fuseops.Op, err error) {
	// Keep going until we find a request we know how to convert.
	for {
		// Read the next message from the kernel.
		var m *buffer.InMessage
		m, err = c.readMessage()
		if err != nil {
			return
		}

		// Choose an ID for this operation for the purposes of logging.
		opID := c.nextOpID
		c.nextOpID++

		// Set up op dependencies.
		opCtx := c.beginOp(m.Header().Opcode, m.Header().Unique)

		var debugLogForOp func(int, string, ...interface{})
		if c.debugLogger != nil {
			debugLogForOp = func(calldepth int, format string, v ...interface{}) {
				c.debugLog(opID, calldepth+1, format, v...)
			}
		}

		sendReply := func(
			op fuseops.Op,
			fuseID uint64,
			replyMsg []byte,
			opErr error) (err error) {
			// Make sure we destroy the message, as required by readMessage.
			defer c.destroyInMessage(m)

			// Clean up state for this op.
			c.finishOp(m.Header().Opcode, m.Header().Unique)

			// Debug logging
			if c.debugLogger != nil {
				if opErr == nil {
					op.Logf("-> OK: %s", op.DebugString())
				} else {
					op.Logf("-> error: %v", opErr)
				}
			}

			// Error logging
			if opErr != nil && c.errorLogger != nil {
				c.errorLogger.Printf("(%s) error: %v", op.ShortDesc(), opErr)
			}

			// Send the reply to the kernel.
			err = c.writeMessage(replyMsg)
			if err != nil {
				err = fmt.Errorf("writeMessage: %v", err)
				return
			}

			return
		}

		// Convert the message to an Op.
		op, err = fuseops.Convert(
			opCtx,
			m,
			c.wrapped.Protocol(),
			debugLogForOp,
			c.errorLogger,
			sendReply)

		if err != nil {
			err = fmt.Errorf("fuseops.Convert: %v", err)
			return
		}

		// Log the receipt of the operation.
		c.debugLog(opID, 1, "<- %v", op.ShortDesc())

		// Special case: responding to statfs is required to make mounting work on
		// OS X. We don't currently expose the capability for the file system to
		// intercept this.
		if _, ok := op.(*fuseops.InternalStatFSOp); ok {
			op.Respond(nil)
			continue
		}

		// Special case: handle interrupt requests.
		if interruptOp, ok := op.(*fuseops.InternalInterruptOp); ok {
			c.handleInterrupt(interruptOp.FuseID)
			continue
		}

		return
	}
}

func (c *Connection) waitForReady() (err error) {
	<-c.wrapped.Ready
	err = c.wrapped.MountError
	return
}

// Close the connection. Must not be called until operations that were read
// from the connection have been responded to.
func (c *Connection) close() (err error) {
	err = c.wrapped.Close()
	return
}
<|endoftext|>


<commit_before>//
// Copyright © 2011-2013 Guy M. Allard
//
// 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 stompngo

import (
	"log"
	"time"
)

// Exported Connection methods

/*
	Connected returns the current connection status.
*/
func (c *Connection) Connected() bool {
	return c.connected
}

/*
	Session returns the broker assigned session id.
*/
func (c *Connection) Session() string {
	return c.session
}

/*
	Protocol returns the current connection protocol level.
*/
func (c *Connection) Protocol() string {
	return c.protocol
}

/*
	SetLogger enables a client defined logger for this connection.

	Set to "nil" to disable logging.

	Example:
		// Start logging
		l := log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds)
		c.SetLogger(l)
*/
func (c *Connection) SetLogger(l *log.Logger) {
	c.logger = l
}

/*
	SendTickerInterval returns any heartbeat send ticker interval in ms.  A return
	value of zero means	no heartbeats are being sent.
*/
func (c *Connection) SendTickerInterval() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.sti / 1000000
}

/*
	ReceiveTickerInterval returns any heartbeat receive ticker interval in ms.
	A return value of zero means no heartbeats are being received.
*/
func (c *Connection) ReceiveTickerInterval() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.rti / 1000000
}

/*
	SendTickerCount returns any heartbeat send ticker count.  A return value of
	zero usually indicates no send heartbeats are enabled.
*/
func (c *Connection) SendTickerCount() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.sc
}

/*
	ReceiveTickerCount returns any heartbeat receive ticker count. A return
	value of zero usually indicates no read heartbeats are enabled.
*/
func (c *Connection) ReceiveTickerCount() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.rc
}

// Package exported functions

/*
	Supported checks if a particular STOMP version is supported in the current
	implementation.
*/
func Supported(v string) bool {
	return hasValue(supported, v)
}

/*
	Protocols returns a slice of client supported protocol levels.
*/
func Protocols() []string {
	return supported
}

/*
	FramesRead returns a count of the number of frames read on the connection.
*/
func (c *Connection) FramesRead() int64 {
	return c.mets.tfr
}

/*
	BytesRead returns a count of the number of bytes read on the connection.
*/
func (c *Connection) BytesRead() int64 {
	return c.mets.tbr
}

/*
	FramesWritten returns a count of the number of frames written on the connection.
*/
func (c *Connection) FramesWritten() int64 {
	return c.mets.tfw
}

/*
	BytesWritten returns a count of the number of bytes written on the connection.
*/
func (c *Connection) BytesWritten() int64 {
	return c.mets.tbw
}

/*
	Running returns a time duration since connection start.
*/
func (c *Connection) Running() time.Duration {
	return time.Since(c.mets.st)
}

/*
	SubChanCap returns the current scribe channel capacity.
*/
func (c *Connection) SubChanCap() int {
	return c.scc
}

/*
	SetSubChanCap sets a new subscribe channel capacity, to be used during future
	SUBSCRIBE operations.
*/
func (c *Connection) SetSubChanCap(nc int) {
	c.scc = nc
	return
}

// Unexported Connection methods

/*
	Log data if possible.
*/
func (c *Connection) log(v ...interface{}) {
	if c.logger == nil {
		return
	}
	c.logger.Print(c.session, v)
	return
}

/*
	Shutdown logic.
*/
func (c *Connection) shutdown() {
	// Shutdown heartbeats if necessary
	if c.hbd != nil {
		if c.hbd.hbs {
			c.hbd.ssd <- true
		}
		if c.hbd.hbr {
			c.hbd.rsd <- true
		}
	}
	// Stop writer go routine
	c.wsd <- true
	// We are not connected
	c.connected = false
	return
}

/*
	Read error handler.
*/
func (c *Connection) handleReadError(md MessageData) {
	// Notify any general subscriber of error
	c.input <- md
	// Notify all individual subscribers of error
	c.subsLock.Lock()
	for key := range c.subs {
		c.subs[key] <- md
	}
	c.subsLock.Unlock()
	// Let further shutdown logic proceed normally.
	return
}
<commit_msg>Typo in comment / spelling.<commit_after>//
// Copyright © 2011-2013 Guy M. Allard
//
// 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 stompngo

import (
	"log"
	"time"
)

// Exported Connection methods

/*
	Connected returns the current connection status.
*/
func (c *Connection) Connected() bool {
	return c.connected
}

/*
	Session returns the broker assigned session id.
*/
func (c *Connection) Session() string {
	return c.session
}

/*
	Protocol returns the current connection protocol level.
*/
func (c *Connection) Protocol() string {
	return c.protocol
}

/*
	SetLogger enables a client defined logger for this connection.

	Set to "nil" to disable logging.

	Example:
		// Start logging
		l := log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds)
		c.SetLogger(l)
*/
func (c *Connection) SetLogger(l *log.Logger) {
	c.logger = l
}

/*
	SendTickerInterval returns any heartbeat send ticker interval in ms.  A return
	value of zero means	no heartbeats are being sent.
*/
func (c *Connection) SendTickerInterval() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.sti / 1000000
}

/*
	ReceiveTickerInterval returns any heartbeat receive ticker interval in ms.
	A return value of zero means no heartbeats are being received.
*/
func (c *Connection) ReceiveTickerInterval() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.rti / 1000000
}

/*
	SendTickerCount returns any heartbeat send ticker count.  A return value of
	zero usually indicates no send heartbeats are enabled.
*/
func (c *Connection) SendTickerCount() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.sc
}

/*
	ReceiveTickerCount returns any heartbeat receive ticker count. A return
	value of zero usually indicates no read heartbeats are enabled.
*/
func (c *Connection) ReceiveTickerCount() int64 {
	if c.hbd == nil {
		return 0
	}
	return c.hbd.rc
}

// Package exported functions

/*
	Supported checks if a particular STOMP version is supported in the current
	implementation.
*/
func Supported(v string) bool {
	return hasValue(supported, v)
}

/*
	Protocols returns a slice of client supported protocol levels.
*/
func Protocols() []string {
	return supported
}

/*
	FramesRead returns a count of the number of frames read on the connection.
*/
func (c *Connection) FramesRead() int64 {
	return c.mets.tfr
}

/*
	BytesRead returns a count of the number of bytes read on the connection.
*/
func (c *Connection) BytesRead() int64 {
	return c.mets.tbr
}

/*
	FramesWritten returns a count of the number of frames written on the connection.
*/
func (c *Connection) FramesWritten() int64 {
	return c.mets.tfw
}

/*
	BytesWritten returns a count of the number of bytes written on the connection.
*/
func (c *Connection) BytesWritten() int64 {
	return c.mets.tbw
}

/*
	Running returns a time duration since connection start.
*/
func (c *Connection) Running() time.Duration {
	return time.Since(c.mets.st)
}

/*
	SubChanCap returns the current subscribe channel capacity.
*/
func (c *Connection) SubChanCap() int {
	return c.scc
}

/*
	SetSubChanCap sets a new subscribe channel capacity, to be used during future
	SUBSCRIBE operations.
*/
func (c *Connection) SetSubChanCap(nc int) {
	c.scc = nc
	return
}

// Unexported Connection methods

/*
	Log data if possible.
*/
func (c *Connection) log(v ...interface{}) {
	if c.logger == nil {
		return
	}
	c.logger.Print(c.session, v)
	return
}

/*
	Shutdown logic.
*/
func (c *Connection) shutdown() {
	// Shutdown heartbeats if necessary
	if c.hbd != nil {
		if c.hbd.hbs {
			c.hbd.ssd <- true
		}
		if c.hbd.hbr {
			c.hbd.rsd <- true
		}
	}
	// Stop writer go routine
	c.wsd <- true
	// We are not connected
	c.connected = false
	return
}

/*
	Read error handler.
*/
func (c *Connection) handleReadError(md MessageData) {
	// Notify any general subscriber of error
	c.input <- md
	// Notify all individual subscribers of error
	c.subsLock.Lock()
	for key := range c.subs {
		c.subs[key] <- md
	}
	c.subsLock.Unlock()
	// Let further shutdown logic proceed normally.
	return
}
<|endoftext|>


<commit_before>package pearl

import (
	"io"
	"net"

	"go.uber.org/multierr"

	"github.com/mmcloughlin/pearl/check"
	"github.com/mmcloughlin/pearl/fork/tls"

	"github.com/mmcloughlin/pearl/log"
	"github.com/pkg/errors"
)

// Connection encapsulates a router connection.
type Connection struct {
	router      *Router
	tlsCtx      *TLSContext
	tlsConn     *tls.Conn
	connID      ConnID
	fingerprint []byte

	circuits *SenderManager

	r io.Reader
	w io.Writer
	CellReceiver
	CellSender

	logger log.Logger
}

// NewServer constructs a server connection.
func NewServer(r *Router, conn net.Conn, logger log.Logger) (*Connection, error) {
	tlsCtx, err := NewTLSContext(r.IdentityKey())
	if err != nil {
		return nil, err
	}
	tlsConn := tlsCtx.ServerConn(conn)
	c := newConnection(r, tlsCtx, tlsConn, false, logger.With("role", "server"))
	return c, nil
}

// NewClient constructs a client-side connection.
func NewClient(r *Router, conn net.Conn, logger log.Logger) (*Connection, error) {
	tlsCtx, err := NewTLSContext(r.IdentityKey())
	if err != nil {
		return nil, err
	}
	tlsConn := tlsCtx.ClientConn(conn)
	c := newConnection(r, tlsCtx, tlsConn, true, logger.With("role", "client"))
	return c, nil
}

func newConnection(r *Router, tlsCtx *TLSContext, tlsConn *tls.Conn, outbound bool, logger log.Logger) *Connection {
	connID := NewConnID()
	rw := tlsConn // TODO(mbm): use bufio
	rd := r.metrics.Inbound.WrapReader(rw)
	wr := r.metrics.Outbound.WrapWriter(rw)
	r.metrics.Connections.Alloc()
	return &Connection{
		router:      r,
		tlsCtx:      tlsCtx,
		tlsConn:     tlsConn,
		connID:      connID,
		fingerprint: nil,

		circuits: NewSenderManager(outbound),

		r:            rd,
		w:            wr,
		CellReceiver: NewCellReader(rd, logger),
		CellSender:   NewCellWriter(wr, logger),

		logger: log.ForConn(logger, tlsConn).With("conn_id", connID),
	}
}

func (c *Connection) newHandshake() *Handshake {
	return &Handshake{
		Conn:        c.tlsConn,
		Link:        NewHandshakeLink(c.r, c.w, c.logger),
		TLSContext:  c.tlsCtx,
		IdentityKey: &c.router.IdentityKey().PublicKey,
		logger:      c.logger,
	}
}

func (c *Connection) ConnID() ConnID {
	return c.connID
}

// Fingerprint returns the fingerprint of the connected peer.
func (c *Connection) Fingerprint() (Fingerprint, error) {
	if c.fingerprint == nil {
		return Fingerprint{}, errors.New("peer fingerprint not established")
	}
	return NewFingerprintFromBytes(c.fingerprint)
}

func (c *Connection) Serve() error {
	c.logger.Info("serving new connection")

	h := c.newHandshake()
	err := h.Server()
	if err != nil {
		log.Err(c.logger, err, "server handshake failed")
		return nil
	}
	c.fingerprint = h.PeerFingerprint
	c.logger.Info("handshake complete")

	if err := c.router.connections.AddConnection(c); err != nil {
		return err
	}

	c.loop()
	return nil
}

func (c *Connection) StartClient() error {
	h := c.newHandshake()
	err := h.Client()
	if err != nil {
		return errors.Wrap(err, "client handshake failed")
	}
	c.fingerprint = h.PeerFingerprint
	c.logger.Info("handshake complete")

	if err := c.router.connections.AddConnection(c); err != nil {
		return err
	}

	// TODO(mbm): goroutine management
	go c.loop()

	return nil
}

func (c *Connection) loop() {
	var err error
	for err == nil {
		err = c.oneCell()
	}

	c.logger.Debug("exit read loop")
	if !check.EOF(err) {
		log.Err(c.logger, err, "cell handling error")
	}

	if err := c.cleanup(); err != nil {
		log.WithErr(c.logger, err).Debug("connection cleanup error")
	}
}

func (c *Connection) oneCell() error {
	cell, err := c.ReceiveCell()
	if err != nil {
		return err
	}

	logger := CellLogger(c.logger, cell)
	logger.Trace("received cell")

	switch cell.Command() {
	// Cells to be handled by this Connection
	case CommandCreate:
		err = CreateHandler(c, cell) // XXX error return
		if err != nil {
			log.Err(logger, err, "failed to handle create")
		}
	case CommandCreate2:
		err = Create2Handler(c, cell) // XXX error return
		if err != nil {
			log.Err(logger, err, "failed to handle create2")
		}
		// Cells related to a circuit
	case CommandCreated, CommandCreated2, CommandRelay, CommandRelayEarly, CommandDestroy:
		logger.Trace("directing cell to circuit channel")
		s, ok := c.circuits.Sender(cell.CircID())
		if !ok {
			// BUG(mbm): is logging the correct behavior
			logger.Error("unrecognized circ id")
			return nil
		}
		err = s.SendCell(cell)
		if err != nil {
			logger.Error("failed to send cell to circuit")
		}
	// Cells to be ignored
	case CommandPadding, CommandVpadding:
		logger.Debug("skipping padding cell")
	// Something which shouldn't happen
	default:
		logger.Error("no handler registered")
	}
	return nil
}

// cleanup cleans up resources related to the connection.
func (c *Connection) cleanup() error {
	c.logger.Info("cleanup connection")
	c.router.metrics.Connections.Free()

	var result error
	for _, circ := range c.circuits.Empty() {
		if err := circ.Close(); err != nil {
			result = multierr.Append(result, err)
		}
	}

	return multierr.Combine(
		result,
		c.router.connections.RemoveConnection(c),
		c.tlsConn.Close(), // BUG(mbm): potential double close?
	)
}

func CellLogger(l log.Logger, cell Cell) log.Logger {
	return l.With("cmd", cell.Command()).With("circid", cell.CircID())
}
<commit_msg>use bufio.Reader<commit_after>package pearl

import (
	"bufio"
	"io"
	"net"

	"go.uber.org/multierr"

	"github.com/mmcloughlin/pearl/check"
	"github.com/mmcloughlin/pearl/fork/tls"

	"github.com/mmcloughlin/pearl/log"
	"github.com/pkg/errors"
)

const (
	maxTLSRecordSize      = 16384 // 16 KiB
	defaultReadBufferSize = 2 * maxTLSRecordSize
)

// Connection encapsulates a router connection.
type Connection struct {
	router      *Router
	tlsCtx      *TLSContext
	tlsConn     *tls.Conn
	connID      ConnID
	fingerprint []byte

	circuits *SenderManager

	r io.Reader
	w io.Writer
	CellReceiver
	CellSender

	logger log.Logger
}

// NewServer constructs a server connection.
func NewServer(r *Router, conn net.Conn, logger log.Logger) (*Connection, error) {
	tlsCtx, err := NewTLSContext(r.IdentityKey())
	if err != nil {
		return nil, err
	}
	tlsConn := tlsCtx.ServerConn(conn)
	c := newConnection(r, tlsCtx, tlsConn, false, logger.With("role", "server"))
	return c, nil
}

// NewClient constructs a client-side connection.
func NewClient(r *Router, conn net.Conn, logger log.Logger) (*Connection, error) {
	tlsCtx, err := NewTLSContext(r.IdentityKey())
	if err != nil {
		return nil, err
	}
	tlsConn := tlsCtx.ClientConn(conn)
	c := newConnection(r, tlsCtx, tlsConn, true, logger.With("role", "client"))
	return c, nil
}

func newConnection(r *Router, tlsCtx *TLSContext, tlsConn *tls.Conn, outbound bool, logger log.Logger) *Connection {
	connID := NewConnID()
	rd := bufio.NewReaderSize(r.metrics.Inbound.WrapReader(tlsConn), defaultReadBufferSize)
	wr := r.metrics.Outbound.WrapWriter(tlsConn) // TODO(mbm): use bufio
	r.metrics.Connections.Alloc()
	return &Connection{
		router:      r,
		tlsCtx:      tlsCtx,
		tlsConn:     tlsConn,
		connID:      connID,
		fingerprint: nil,

		circuits: NewSenderManager(outbound),

		r:            rd,
		w:            wr,
		CellReceiver: NewCellReader(rd, logger),
		CellSender:   NewCellWriter(wr, logger),

		logger: log.ForConn(logger, tlsConn).With("conn_id", connID),
	}
}

func (c *Connection) newHandshake() *Handshake {
	return &Handshake{
		Conn:        c.tlsConn,
		Link:        NewHandshakeLink(c.r, c.w, c.logger),
		TLSContext:  c.tlsCtx,
		IdentityKey: &c.router.IdentityKey().PublicKey,
		logger:      c.logger,
	}
}

func (c *Connection) ConnID() ConnID {
	return c.connID
}

// Fingerprint returns the fingerprint of the connected peer.
func (c *Connection) Fingerprint() (Fingerprint, error) {
	if c.fingerprint == nil {
		return Fingerprint{}, errors.New("peer fingerprint not established")
	}
	return NewFingerprintFromBytes(c.fingerprint)
}

func (c *Connection) Serve() error {
	c.logger.Info("serving new connection")

	h := c.newHandshake()
	err := h.Server()
	if err != nil {
		log.Err(c.logger, err, "server handshake failed")
		return nil
	}
	c.fingerprint = h.PeerFingerprint
	c.logger.Info("handshake complete")

	if err := c.router.connections.AddConnection(c); err != nil {
		return err
	}

	c.loop()
	return nil
}

func (c *Connection) StartClient() error {
	h := c.newHandshake()
	err := h.Client()
	if err != nil {
		return errors.Wrap(err, "client handshake failed")
	}
	c.fingerprint = h.PeerFingerprint
	c.logger.Info("handshake complete")

	if err := c.router.connections.AddConnection(c); err != nil {
		return err
	}

	// TODO(mbm): goroutine management
	go c.loop()

	return nil
}

func (c *Connection) loop() {
	var err error
	for err == nil {
		err = c.oneCell()
	}

	c.logger.Debug("exit read loop")
	if !check.EOF(err) {
		log.Err(c.logger, err, "cell handling error")
	}

	if err := c.cleanup(); err != nil {
		log.WithErr(c.logger, err).Debug("connection cleanup error")
	}
}

func (c *Connection) oneCell() error {
	cell, err := c.ReceiveCell()
	if err != nil {
		return err
	}

	logger := CellLogger(c.logger, cell)
	logger.Trace("received cell")

	switch cell.Command() {
	// Cells to be handled by this Connection
	case CommandCreate:
		err = CreateHandler(c, cell) // XXX error return
		if err != nil {
			log.Err(logger, err, "failed to handle create")
		}
	case CommandCreate2:
		err = Create2Handler(c, cell) // XXX error return
		if err != nil {
			log.Err(logger, err, "failed to handle create2")
		}
		// Cells related to a circuit
	case CommandCreated, CommandCreated2, CommandRelay, CommandRelayEarly, CommandDestroy:
		logger.Trace("directing cell to circuit channel")
		s, ok := c.circuits.Sender(cell.CircID())
		if !ok {
			// BUG(mbm): is logging the correct behavior
			logger.Error("unrecognized circ id")
			return nil
		}
		err = s.SendCell(cell)
		if err != nil {
			logger.Error("failed to send cell to circuit")
		}
	// Cells to be ignored
	case CommandPadding, CommandVpadding:
		logger.Debug("skipping padding cell")
	// Something which shouldn't happen
	default:
		logger.Error("no handler registered")
	}
	return nil
}

// cleanup cleans up resources related to the connection.
func (c *Connection) cleanup() error {
	c.logger.Info("cleanup connection")
	c.router.metrics.Connections.Free()

	var result error
	for _, circ := range c.circuits.Empty() {
		if err := circ.Close(); err != nil {
			result = multierr.Append(result, err)
		}
	}

	return multierr.Combine(
		result,
		c.router.connections.RemoveConnection(c),
		c.tlsConn.Close(), // BUG(mbm): potential double close?
	)
}

func CellLogger(l log.Logger, cell Cell) log.Logger {
	return l.With("cmd", cell.Command()).With("circid", cell.CircID())
}
<|endoftext|>


<commit_before>package sip

import (
	"strings"
)

func StartSIP(lAddr string, rAddr string, transport string) (chan SipMessage, chan SipMessage) {
	if strings.ToLower(transport) == "udp" {
		return StartUDP(lAddr, rAddr)
	}
	return StartTCPClient(lAddr, rAddr)
}
<commit_msg>adding license header<commit_after>// Copyright 2016 sip authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package sip

import (
	"strings"
)

func StartSIP(lAddr string, rAddr string, transport string) (chan SipMessage, chan SipMessage) {
	if strings.ToLower(transport) == "udp" {
		return StartUDP(lAddr, rAddr)
	}
	return StartTCPClient(lAddr, rAddr)
}
<|endoftext|>


<commit_before>package data

import (
	"io"
)

type Hashable interface {
	GetType() string
	Hash() Hash256
	Raw() []byte
	SetHash([]byte)
	SetRaw([]byte)
	String() string
}

type Wire interface {
	Unmarshal(Reader) error
	Marshal(io.Writer) error
}

type LedgerEntry interface {
	Hashable
	GetLedgerEntryType() LedgerEntryType
}

type Transaction interface {
	Hashable
	GetTransactionType() TransactionType
	GetAccount() string
	// GetAffectedNodes() []NodeEffect
	GetBase() *TxBase
}

type Delta interface {
	// String() string
}
<commit_msg>Remove unused Delta interface<commit_after>package data

import (
	"io"
)

type Hashable interface {
	GetType() string
	Hash() Hash256
	Raw() []byte
	SetHash([]byte)
	SetRaw([]byte)
	String() string
}

type Wire interface {
	Unmarshal(Reader) error
	Marshal(io.Writer) error
}

type LedgerEntry interface {
	Hashable
	GetLedgerEntryType() LedgerEntryType
}

type Transaction interface {
	Hashable
	GetTransactionType() TransactionType
	GetAccount() string
	// GetAffectedNodes() []NodeEffect
	GetBase() *TxBase
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"io/ioutil"
	"testing"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/require"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/testutils"
	"github.com/loadimpact/k6/lib/testutils/minirunner"
	"github.com/loadimpact/k6/stats"
)

func simpleRunner(vuFn func(context.Context) error) lib.Runner {
	return &minirunner.MiniRunner{
		Fn: func(ctx context.Context, _ chan<- stats.SampleContainer) error {
			return vuFn(ctx)
		},
	}
}

func setupExecutor(t *testing.T, config lib.ExecutorConfig, es *lib.ExecutionState, runner lib.Runner) (
	context.Context, context.CancelFunc, lib.Executor, *testutils.SimpleLogrusHook,
) {
	ctx, cancel := context.WithCancel(context.Background())
	engineOut := make(chan stats.SampleContainer, 100) // TODO: return this for more complicated tests?

	logHook := &testutils.SimpleLogrusHook{HookedLevels: []logrus.Level{logrus.WarnLevel}}
	testLog := logrus.New()
	testLog.AddHook(logHook)
	testLog.SetOutput(ioutil.Discard)
	logEntry := logrus.NewEntry(testLog)

	es.SetInitVUFunc(func(_ context.Context, logger *logrus.Entry) (lib.InitializedVU, error) {
		return runner.NewVU(int64(es.GetUniqueVUIdentifier()), engineOut)
	})

	et, err := lib.NewExecutionTuple(es.Options.ExecutionSegment, es.Options.ExecutionSegmentSequence)
	require.NoError(t, err)

	maxVUs := lib.GetMaxPossibleVUs(config.GetExecutionRequirements(et))
	initializeVUs(ctx, t, logEntry, es, maxVUs)

	executor, err := config.NewExecutor(es, logEntry)
	require.NoError(t, err)

	err = executor.Init(ctx)
	require.NoError(t, err)
	return ctx, cancel, executor, logHook
}

func initializeVUs(
	ctx context.Context, t testing.TB, logEntry *logrus.Entry, es *lib.ExecutionState, number uint64,
) {
	// This is not how the local ExecutionScheduler initializes VUs, but should do the same job
	for i := uint64(0); i < number; i++ {
		vu, err := es.InitializeNewVU(ctx, logEntry)
		require.NoError(t, err)
		es.AddInitializedVU(vu)
	}
}
<commit_msg>Fix double increment of initializedVUs in executor tests<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"io/ioutil"
	"testing"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/require"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/testutils"
	"github.com/loadimpact/k6/lib/testutils/minirunner"
	"github.com/loadimpact/k6/stats"
)

func simpleRunner(vuFn func(context.Context) error) lib.Runner {
	return &minirunner.MiniRunner{
		Fn: func(ctx context.Context, _ chan<- stats.SampleContainer) error {
			return vuFn(ctx)
		},
	}
}

func setupExecutor(t *testing.T, config lib.ExecutorConfig, es *lib.ExecutionState, runner lib.Runner) (
	context.Context, context.CancelFunc, lib.Executor, *testutils.SimpleLogrusHook,
) {
	ctx, cancel := context.WithCancel(context.Background())
	engineOut := make(chan stats.SampleContainer, 100) // TODO: return this for more complicated tests?

	logHook := &testutils.SimpleLogrusHook{HookedLevels: []logrus.Level{logrus.WarnLevel}}
	testLog := logrus.New()
	testLog.AddHook(logHook)
	testLog.SetOutput(ioutil.Discard)
	logEntry := logrus.NewEntry(testLog)

	initVUFunc := func(_ context.Context, logger *logrus.Entry) (lib.InitializedVU, error) {
		return runner.NewVU(int64(es.GetUniqueVUIdentifier()), engineOut)
	}
	es.SetInitVUFunc(initVUFunc)

	et, err := lib.NewExecutionTuple(es.Options.ExecutionSegment, es.Options.ExecutionSegmentSequence)
	require.NoError(t, err)

	maxVUs := lib.GetMaxPossibleVUs(config.GetExecutionRequirements(et))
	initializeVUs(ctx, t, logEntry, es, maxVUs, initVUFunc)

	executor, err := config.NewExecutor(es, logEntry)
	require.NoError(t, err)

	err = executor.Init(ctx)
	require.NoError(t, err)
	return ctx, cancel, executor, logHook
}

func initializeVUs(
	ctx context.Context, t testing.TB, logEntry *logrus.Entry, es *lib.ExecutionState, number uint64, initVU lib.InitVUFunc,
) {
	// This is not how the local ExecutionScheduler initializes VUs, but should do the same job
	for i := uint64(0); i < number; i++ {
		// Not calling es.InitializeNewVU() here to avoid a double increment of initializedVUs,
		// which is done in es.AddInitializedVU().
		vu, err := initVU(ctx, logEntry)
		require.NoError(t, err)
		es.AddInitializedVU(vu)
	}
}
<|endoftext|>


<commit_before>package dbus

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

var (
	byteType        = reflect.TypeOf(byte(0))
	boolType        = reflect.TypeOf(false)
	uint8Type       = reflect.TypeOf(uint8(0))
	int16Type       = reflect.TypeOf(int16(0))
	uint16Type      = reflect.TypeOf(uint16(0))
	intType         = reflect.TypeOf(int(0))
	uintType        = reflect.TypeOf(uint(0))
	int32Type       = reflect.TypeOf(int32(0))
	uint32Type      = reflect.TypeOf(uint32(0))
	int64Type       = reflect.TypeOf(int64(0))
	uint64Type      = reflect.TypeOf(uint64(0))
	float64Type     = reflect.TypeOf(float64(0))
	stringType      = reflect.TypeOf("")
	signatureType   = reflect.TypeOf(Signature{""})
	objectPathType  = reflect.TypeOf(ObjectPath(""))
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
	interfacesType  = reflect.TypeOf([]interface{}{})
	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
	unixFDType      = reflect.TypeOf(UnixFD(0))
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
	errType         = reflect.TypeOf((*error)(nil)).Elem()
)

// An InvalidTypeError signals that a value which cannot be represented in the
// D-Bus wire format was passed to a function.
type InvalidTypeError struct {
	Type reflect.Type
}

func (e InvalidTypeError) Error() string {
	return "dbus: invalid type " + e.Type.String()
}

// Store copies the values contained in src to dest, which must be a slice of
// pointers. It converts slices of interfaces from src to corresponding structs
// in dest. An error is returned if the lengths of src and dest or the types of
// their elements don't match.
func Store(src []interface{}, dest ...interface{}) error {
	if len(src) != len(dest) {
		return errors.New("dbus.Store: length mismatch")
	}

	for i := range src {
		if err := storeInterfaces(src[i], dest[i]); err != nil {
			return err
		}
	}
	return nil
}

func storeInterfaces(src, dest interface{}) error {
	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
}

func store(dest, src reflect.Value) error {
	if dest.Kind() == reflect.Ptr {
		if dest.IsNil() {
			dest.Set(reflect.New(dest.Type().Elem()))
		}
		return store(dest.Elem(), src)
	}
	switch src.Kind() {
	case reflect.Slice:
		return storeSlice(dest, src)
	case reflect.Map:
		return storeMap(dest, src)
	default:
		return storeBase(dest, src)
	}
}

func storeBase(dest, src reflect.Value) error {
	return setDest(dest, src)
}

func setDest(dest, src reflect.Value) error {
	if !isVariant(src.Type()) && isVariant(dest.Type()) {
		//special conversion for dbus.Variant
		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
		return nil
	}
	if isVariant(src.Type()) && !isVariant(dest.Type()) {
		src = getVariantValue(src)
		return store(dest, src)
	}
	if !src.Type().ConvertibleTo(dest.Type()) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: cannot convert %s to %s",
			src.Type(), dest.Type())
	}
	dest.Set(src.Convert(dest.Type()))
	return nil
}

func kindsAreCompatible(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	default:
		return dest.Kind() == src.Kind()
	}
}

func isConvertibleTo(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	case dest.Kind() == reflect.Slice:
		return src.Kind() == reflect.Slice &&
			isConvertibleTo(dest.Elem(), src.Elem())
	case dest.Kind() == reflect.Ptr:
		dest = dest.Elem()
		return isConvertibleTo(dest, src)
	case dest.Kind() == reflect.Struct:
		return src == interfacesType
	default:
		return src.ConvertibleTo(dest)
	}
}

func storeMap(dest, src reflect.Value) error {
	switch {
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeMapIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeMapIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeMapIntoMap(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeMapIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeMap(src.Type())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeMap(
			reflect.MapOf(src.Type().Key(), interfaceType))
	} else {
		dv = reflect.MakeMap(src.Type())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoMap(dest, src reflect.Value) error {
	if dest.IsNil() {
		dest.Set(reflect.MakeMap(dest.Type()))
	}
	keys := src.MapKeys()
	for _, key := range keys {
		dkey := key.Convert(dest.Type().Key())
		dval := reflect.New(dest.Type().Elem()).Elem()
		err := store(dval, getVariantValue(src.MapIndex(key)))
		if err != nil {
			return err
		}
		dest.SetMapIndex(dkey, dval)
	}
	return nil
}

func storeSlice(dest, src reflect.Value) error {
	switch {
	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
		//The decoder always decodes structs as slices of interface{}
		return storeStruct(dest, src)
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeSliceIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeSliceIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeSliceIntoSlice(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeStruct(dest, src reflect.Value) error {
	if isVariant(dest.Type()) {
		return storeBase(dest, src)
	}
	dval := make([]interface{}, 0, dest.NumField())
	dtype := dest.Type()
	for i := 0; i < dest.NumField(); i++ {
		field := dest.Field(i)
		ftype := dtype.Field(i)
		if ftype.PkgPath != "" {
			continue
		}
		if ftype.Tag.Get("dbus") == "-" {
			continue
		}
		dval = append(dval, field.Addr().Interface())
	}
	if src.Len() != len(dval) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"destination struct does not have "+
				"enough fields need: %d have: %d",
			src.Len(), len(dval))
	}
	return Store(src.Interface().([]interface{}), dval...)
}

func storeSliceIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
			src.Len(), src.Cap())
	} else {
		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoSlice(dest, src reflect.Value) error {
	if dest.IsNil() || dest.Len() < src.Len() {
		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
	}
	if dest.Len() != src.Len() {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slices are different lengths "+
				"need: %d have: %d",
			src.Len(), dest.Len())
	}
	for i := 0; i < src.Len(); i++ {
		err := store(dest.Index(i), getVariantValue(src.Index(i)))
		if err != nil {
			return err
		}
	}
	return nil
}

func getVariantValue(in reflect.Value) reflect.Value {
	if isVariant(in.Type()) {
		return reflect.ValueOf(in.Interface().(Variant).Value())
	}
	return in
}

func isVariant(t reflect.Type) bool {
	return t == variantType
}

// An ObjectPath is an object path as defined by the D-Bus spec.
type ObjectPath string

// IsValid returns whether the object path is valid.
func (o ObjectPath) IsValid() bool {
	s := string(o)
	if len(s) == 0 {
		return false
	}
	if s[0] != '/' {
		return false
	}
	if s[len(s)-1] == '/' && len(s) != 1 {
		return false
	}
	// probably not used, but technically possible
	if s == "/" {
		return true
	}
	split := strings.Split(s[1:], "/")
	for _, v := range split {
		if len(v) == 0 {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
// documentation for more information about Unix file descriptor passsing.
type UnixFD int32

// A UnixFDIndex is the representation of a Unix file descriptor in a message.
type UnixFDIndex uint32

// alignment returns the alignment of values of type t.
func alignment(t reflect.Type) int {
	switch t {
	case variantType:
		return 1
	case objectPathType:
		return 4
	case signatureType:
		return 1
	case interfacesType:
		return 4
	}
	switch t.Kind() {
	case reflect.Uint8:
		return 1
	case reflect.Uint16, reflect.Int16:
		return 2
	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
		return 4
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
		return 8
	case reflect.Ptr:
		return alignment(t.Elem())
	}
	return 1
}

// isKeyType returns whether t is a valid type for a D-Bus dict.
func isKeyType(t reflect.Type) bool {
	switch t.Kind() {
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
		reflect.String, reflect.Uint, reflect.Int:

		return true
	}
	return false
}

// isValidInterface returns whether s is a valid name for an interface.
func isValidInterface(s string) bool {
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
		return false
	}
	elem := strings.Split(s, ".")
	if len(elem) < 2 {
		return false
	}
	for _, v := range elem {
		if len(v) == 0 {
			return false
		}
		if v[0] >= '0' && v[0] <= '9' {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// isValidMember returns whether s is a valid name for a member.
func isValidMember(s string) bool {
	if len(s) == 0 || len(s) > 255 {
		return false
	}
	i := strings.Index(s, ".")
	if i != -1 {
		return false
	}
	if s[0] >= '0' && s[0] <= '9' {
		return false
	}
	for _, c := range s {
		if !isMemberChar(c) {
			return false
		}
	}
	return true
}

func isMemberChar(c rune) bool {
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') || c == '_'
}
<commit_msg>fix: type check slice of struct<commit_after>package dbus

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

var (
	byteType        = reflect.TypeOf(byte(0))
	boolType        = reflect.TypeOf(false)
	uint8Type       = reflect.TypeOf(uint8(0))
	int16Type       = reflect.TypeOf(int16(0))
	uint16Type      = reflect.TypeOf(uint16(0))
	intType         = reflect.TypeOf(int(0))
	uintType        = reflect.TypeOf(uint(0))
	int32Type       = reflect.TypeOf(int32(0))
	uint32Type      = reflect.TypeOf(uint32(0))
	int64Type       = reflect.TypeOf(int64(0))
	uint64Type      = reflect.TypeOf(uint64(0))
	float64Type     = reflect.TypeOf(float64(0))
	stringType      = reflect.TypeOf("")
	signatureType   = reflect.TypeOf(Signature{""})
	objectPathType  = reflect.TypeOf(ObjectPath(""))
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
	interfacesType  = reflect.TypeOf([]interface{}{})
	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
	unixFDType      = reflect.TypeOf(UnixFD(0))
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
	errType         = reflect.TypeOf((*error)(nil)).Elem()
)

// An InvalidTypeError signals that a value which cannot be represented in the
// D-Bus wire format was passed to a function.
type InvalidTypeError struct {
	Type reflect.Type
}

func (e InvalidTypeError) Error() string {
	return "dbus: invalid type " + e.Type.String()
}

// Store copies the values contained in src to dest, which must be a slice of
// pointers. It converts slices of interfaces from src to corresponding structs
// in dest. An error is returned if the lengths of src and dest or the types of
// their elements don't match.
func Store(src []interface{}, dest ...interface{}) error {
	if len(src) != len(dest) {
		return errors.New("dbus.Store: length mismatch")
	}

	for i := range src {
		if err := storeInterfaces(src[i], dest[i]); err != nil {
			return err
		}
	}
	return nil
}

func storeInterfaces(src, dest interface{}) error {
	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
}

func store(dest, src reflect.Value) error {
	if dest.Kind() == reflect.Ptr {
		if dest.IsNil() {
			dest.Set(reflect.New(dest.Type().Elem()))
		}
		return store(dest.Elem(), src)
	}
	switch src.Kind() {
	case reflect.Slice:
		return storeSlice(dest, src)
	case reflect.Map:
		return storeMap(dest, src)
	default:
		return storeBase(dest, src)
	}
}

func storeBase(dest, src reflect.Value) error {
	return setDest(dest, src)
}

func setDest(dest, src reflect.Value) error {
	if !isVariant(src.Type()) && isVariant(dest.Type()) {
		//special conversion for dbus.Variant
		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
		return nil
	}
	if isVariant(src.Type()) && !isVariant(dest.Type()) {
		src = getVariantValue(src)
		return store(dest, src)
	}
	if !src.Type().ConvertibleTo(dest.Type()) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: cannot convert %s to %s",
			src.Type(), dest.Type())
	}
	dest.Set(src.Convert(dest.Type()))
	return nil
}

func kindsAreCompatible(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	default:
		return dest.Kind() == src.Kind()
	}
}

func isConvertibleTo(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	case dest.Kind() == reflect.Slice:
		return src.Kind() == reflect.Slice &&
			isConvertibleTo(dest.Elem(), src.Elem())
	case dest.Kind() == reflect.Ptr:
		dest = dest.Elem()
		return isConvertibleTo(dest, src)
	case dest.Kind() == reflect.Struct:
		return src == interfacesType || dest.Kind() == src.Kind()
	default:
		return src.ConvertibleTo(dest)
	}
}

func storeMap(dest, src reflect.Value) error {
	switch {
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeMapIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeMapIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeMapIntoMap(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeMapIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeMap(src.Type())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeMap(
			reflect.MapOf(src.Type().Key(), interfaceType))
	} else {
		dv = reflect.MakeMap(src.Type())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoMap(dest, src reflect.Value) error {
	if dest.IsNil() {
		dest.Set(reflect.MakeMap(dest.Type()))
	}
	keys := src.MapKeys()
	for _, key := range keys {
		dkey := key.Convert(dest.Type().Key())
		dval := reflect.New(dest.Type().Elem()).Elem()
		err := store(dval, getVariantValue(src.MapIndex(key)))
		if err != nil {
			return err
		}
		dest.SetMapIndex(dkey, dval)
	}
	return nil
}

func storeSlice(dest, src reflect.Value) error {
	switch {
	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
		//The decoder always decodes structs as slices of interface{}
		return storeStruct(dest, src)
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeSliceIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeSliceIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeSliceIntoSlice(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeStruct(dest, src reflect.Value) error {
	if isVariant(dest.Type()) {
		return storeBase(dest, src)
	}
	dval := make([]interface{}, 0, dest.NumField())
	dtype := dest.Type()
	for i := 0; i < dest.NumField(); i++ {
		field := dest.Field(i)
		ftype := dtype.Field(i)
		if ftype.PkgPath != "" {
			continue
		}
		if ftype.Tag.Get("dbus") == "-" {
			continue
		}
		dval = append(dval, field.Addr().Interface())
	}
	if src.Len() != len(dval) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"destination struct does not have "+
				"enough fields need: %d have: %d",
			src.Len(), len(dval))
	}
	return Store(src.Interface().([]interface{}), dval...)
}

func storeSliceIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
			src.Len(), src.Cap())
	} else {
		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoSlice(dest, src reflect.Value) error {
	if dest.IsNil() || dest.Len() < src.Len() {
		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
	}
	if dest.Len() != src.Len() {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slices are different lengths "+
				"need: %d have: %d",
			src.Len(), dest.Len())
	}
	for i := 0; i < src.Len(); i++ {
		err := store(dest.Index(i), getVariantValue(src.Index(i)))
		if err != nil {
			return err
		}
	}
	return nil
}

func getVariantValue(in reflect.Value) reflect.Value {
	if isVariant(in.Type()) {
		return reflect.ValueOf(in.Interface().(Variant).Value())
	}
	return in
}

func isVariant(t reflect.Type) bool {
	return t == variantType
}

// An ObjectPath is an object path as defined by the D-Bus spec.
type ObjectPath string

// IsValid returns whether the object path is valid.
func (o ObjectPath) IsValid() bool {
	s := string(o)
	if len(s) == 0 {
		return false
	}
	if s[0] != '/' {
		return false
	}
	if s[len(s)-1] == '/' && len(s) != 1 {
		return false
	}
	// probably not used, but technically possible
	if s == "/" {
		return true
	}
	split := strings.Split(s[1:], "/")
	for _, v := range split {
		if len(v) == 0 {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
// documentation for more information about Unix file descriptor passsing.
type UnixFD int32

// A UnixFDIndex is the representation of a Unix file descriptor in a message.
type UnixFDIndex uint32

// alignment returns the alignment of values of type t.
func alignment(t reflect.Type) int {
	switch t {
	case variantType:
		return 1
	case objectPathType:
		return 4
	case signatureType:
		return 1
	case interfacesType:
		return 4
	}
	switch t.Kind() {
	case reflect.Uint8:
		return 1
	case reflect.Uint16, reflect.Int16:
		return 2
	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
		return 4
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
		return 8
	case reflect.Ptr:
		return alignment(t.Elem())
	}
	return 1
}

// isKeyType returns whether t is a valid type for a D-Bus dict.
func isKeyType(t reflect.Type) bool {
	switch t.Kind() {
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
		reflect.String, reflect.Uint, reflect.Int:

		return true
	}
	return false
}

// isValidInterface returns whether s is a valid name for an interface.
func isValidInterface(s string) bool {
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
		return false
	}
	elem := strings.Split(s, ".")
	if len(elem) < 2 {
		return false
	}
	for _, v := range elem {
		if len(v) == 0 {
			return false
		}
		if v[0] >= '0' && v[0] <= '9' {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// isValidMember returns whether s is a valid name for a member.
func isValidMember(s string) bool {
	if len(s) == 0 || len(s) > 255 {
		return false
	}
	i := strings.Index(s, ".")
	if i != -1 {
		return false
	}
	if s[0] >= '0' && s[0] <= '9' {
		return false
	}
	for _, c := range s {
		if !isMemberChar(c) {
			return false
		}
	}
	return true
}

func isMemberChar(c rune) bool {
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') || c == '_'
}
<|endoftext|>