<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/aws-sdk-go/aws"
	"github.com/hashicorp/aws-sdk-go/gen/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpc() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcCreate,
		Read:   resourceAwsVpcRead,
		Update: resourceAwsVpcUpdate,
		Delete: resourceAwsVpcDelete,

		Schema: map[string]*schema.Schema{
			"cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"instance_tenancy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"enable_dns_hostnames": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"enable_dns_support": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"main_route_table_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_network_acl_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_security_group_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn
	instance_tenancy := "default"
	if v, ok := d.GetOk("instance_tenancy"); ok {
		instance_tenancy = v.(string)
	}
	// Create the VPC
	createOpts := &ec2.CreateVPCRequest{
		CIDRBlock:       aws.String(d.Get("cidr_block").(string)),
		InstanceTenancy: aws.String(instance_tenancy),
	}
	log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
	vpcResp, err := ec2conn.CreateVPC(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating VPC: %s", err)
	}

	// Get the ID and store it
	vpc := vpcResp.VPC
	d.SetId(*vpc.VPCID)
	log.Printf("[INFO] VPC ID: %s", d.Id())

	// Set partial mode and say that we setup the cidr block
	d.Partial(true)
	d.SetPartial("cidr_block")

	// Wait for the VPC to become available
	log.Printf(
		"[DEBUG] Waiting for VPC (%s) to become available",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "available",
		Refresh: VPCStateRefreshFunc(ec2conn, d.Id()),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for VPC (%s) to become available: %s",
			d.Id(), err)
	}

	// Update our attributes and return
	return resourceAwsVpcUpdate(d, meta)
}

func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	// Refresh the VPC state
	vpcRaw, _, err := VPCStateRefreshFunc(ec2conn, d.Id())()
	if err != nil {
		return err
	}
	if vpcRaw == nil {
		d.SetId("")
		return nil
	}

	// VPC stuff
	vpc := vpcRaw.(*ec2.VPC)
	vpcid := d.Id()
	d.Set("cidr_block", vpc.CIDRBlock)

	// Tags
	d.Set("tags", tagsToMap(vpc.Tags))

	// Attributes
	attribute := "enableDnsSupport"
	DescribeAttrOpts := &ec2.DescribeVPCAttributeRequest{
		Attribute: aws.String(attribute),
		VPCID:     aws.String(vpcid),
	}
	resp, err := ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_support", *resp.EnableDNSSupport)
	attribute = "enableDnsHostnames"
	DescribeAttrOpts = &ec2.DescribeVPCAttributeRequest{
		Attribute: &attribute,
		VPCID:     &vpcid,
	}
	resp, err = ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_hostnames", *resp.EnableDNSHostnames)

	// Get the main routing table for this VPC
	// Really Ugly need to make this better - rmenn
	filter1 := &ec2.Filter{
		Name:   aws.String("association.main"),
		Values: []string{("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []string{(d.Id())},
	}
	DescribeRouteOpts := &ec2.DescribeRouteTablesRequest{
		Filters: []ec2.Filter{*filter1, *filter2},
	}
	routeResp, err := ec2conn.DescribeRouteTables(DescribeRouteOpts)
	if err != nil {
		return err
	}
	if v := routeResp.RouteTables; len(v) > 0 {
		d.Set("main_route_table_id", *v[0].RouteTableID)
	}

	resourceAwsVpcSetDefaultNetworkAcl(ec2conn, d)
	resourceAwsVpcSetDefaultSecurityGroup(ec2conn, d)

	return nil
}

func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	// Turn on partial mode
	d.Partial(true)
	vpcid := d.Id()
	modifyOpts := &ec2.ModifyVPCAttributeRequest{
		VPCID: &vpcid,
	}
	if d.HasChange("enable_dns_hostnames") {
		val := d.Get("enable_dns_hostnames").(bool)
		modifyOpts.EnableDNSHostnames = &ec2.AttributeBooleanValue{
			Value: &val,
		}

		log.Printf(
			"[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_hostnames")
	}

	if d.HasChange("enable_dns_support") {
		val := d.Get("enable_dns_hostnames").(bool)
		modifyOpts.EnableDNSSupport = &ec2.AttributeBooleanValue{
			Value: &val,
		}

		log.Printf(
			"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_support")
	}

	if err := setTags(ec2conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	d.Partial(false)
	return resourceAwsVpcRead(d, meta)
}

func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn
	vpcID := d.Id()
	DeleteVpcOpts := &ec2.DeleteVPCRequest{
		VPCID: &vpcID,
	}
	log.Printf("[INFO] Deleting VPC: %s", d.Id())
	if err := ec2conn.DeleteVPC(DeleteVpcOpts); err != nil {
		ec2err, ok := err.(aws.APIError)
		if ok && ec2err.Code == "InvalidVpcID.NotFound" {
			return nil
		}

		return fmt.Errorf("Error deleting VPC: %s", err)
	}

	return nil
}

// VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VPC.
func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		DescribeVpcOpts := &ec2.DescribeVPCsRequest{
			VPCIDs: []string{id},
		}
		resp, err := conn.DescribeVPCs(DescribeVpcOpts)
		if err != nil {
			if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on VPCStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		vpc := &resp.VPCs[0]
		return vpc, *vpc.State, nil
	}
}

func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("default"),
		Values: []string{("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []string{(d.Id())},
	}
	DescribeNetworkACLOpts := &ec2.DescribeNetworkACLsRequest{
		Filters: []ec2.Filter{*filter1, *filter2},
	}
	networkAclResp, err := conn.DescribeNetworkACLs(DescribeNetworkACLOpts)

	if err != nil {
		return err
	}
	if v := networkAclResp.NetworkACLs; len(v) > 0 {
		d.Set("default_network_acl_id", v[0].NetworkACLID)
	}

	return nil
}

func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("group-name"),
		Values: []string{("default")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []string{(d.Id())},
	}
	DescribeSgOpts := &ec2.DescribeSecurityGroupsRequest{
		Filters: []ec2.Filter{*filter1, *filter2},
	}
	securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts)

	if err != nil {
		return err
	}
	if v := securityGroupResp.SecurityGroups; len(v) > 0 {
		d.Set("default_security_group_id", v[0].GroupID)
	}

	return nil
}
<commit_msg>Don't error when enabling DNS hostnames in a VPC<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/aws-sdk-go/aws"
	"github.com/hashicorp/aws-sdk-go/gen/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpc() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcCreate,
		Read:   resourceAwsVpcRead,
		Update: resourceAwsVpcUpdate,
		Delete: resourceAwsVpcDelete,

		Schema: map[string]*schema.Schema{
			"cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"instance_tenancy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"enable_dns_hostnames": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"enable_dns_support": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"main_route_table_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_network_acl_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_security_group_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn
	instance_tenancy := "default"
	if v, ok := d.GetOk("instance_tenancy"); ok {
		instance_tenancy = v.(string)
	}
	// Create the VPC
	createOpts := &ec2.CreateVPCRequest{
		CIDRBlock:       aws.String(d.Get("cidr_block").(string)),
		InstanceTenancy: aws.String(instance_tenancy),
	}
	log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
	vpcResp, err := ec2conn.CreateVPC(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating VPC: %s", err)
	}

	// Get the ID and store it
	vpc := vpcResp.VPC
	d.SetId(*vpc.VPCID)
	log.Printf("[INFO] VPC ID: %s", d.Id())

	// Set partial mode and say that we setup the cidr block
	d.Partial(true)
	d.SetPartial("cidr_block")

	// Wait for the VPC to become available
	log.Printf(
		"[DEBUG] Waiting for VPC (%s) to become available",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "available",
		Refresh: VPCStateRefreshFunc(ec2conn, d.Id()),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for VPC (%s) to become available: %s",
			d.Id(), err)
	}

	// Update our attributes and return
	return resourceAwsVpcUpdate(d, meta)
}

func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	// Refresh the VPC state
	vpcRaw, _, err := VPCStateRefreshFunc(ec2conn, d.Id())()
	if err != nil {
		return err
	}
	if vpcRaw == nil {
		d.SetId("")
		return nil
	}

	// VPC stuff
	vpc := vpcRaw.(*ec2.VPC)
	vpcid := d.Id()
	d.Set("cidr_block", vpc.CIDRBlock)

	// Tags
	d.Set("tags", tagsToMap(vpc.Tags))

	// Attributes
	attribute := "enableDnsSupport"
	DescribeAttrOpts := &ec2.DescribeVPCAttributeRequest{
		Attribute: aws.String(attribute),
		VPCID:     aws.String(vpcid),
	}
	resp, err := ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_support", *resp.EnableDNSSupport)
	attribute = "enableDnsHostnames"
	DescribeAttrOpts = &ec2.DescribeVPCAttributeRequest{
		Attribute: &attribute,
		VPCID:     &vpcid,
	}
	resp, err = ec2conn.DescribeVPCAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_hostnames", *resp.EnableDNSHostnames)

	// Get the main routing table for this VPC
	// Really Ugly need to make this better - rmenn
	filter1 := &ec2.Filter{
		Name:   aws.String("association.main"),
		Values: []string{("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []string{(d.Id())},
	}
	DescribeRouteOpts := &ec2.DescribeRouteTablesRequest{
		Filters: []ec2.Filter{*filter1, *filter2},
	}
	routeResp, err := ec2conn.DescribeRouteTables(DescribeRouteOpts)
	if err != nil {
		return err
	}
	if v := routeResp.RouteTables; len(v) > 0 {
		d.Set("main_route_table_id", *v[0].RouteTableID)
	}

	resourceAwsVpcSetDefaultNetworkAcl(ec2conn, d)
	resourceAwsVpcSetDefaultSecurityGroup(ec2conn, d)

	return nil
}

func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	// Turn on partial mode
	d.Partial(true)
	vpcid := d.Id()

	if d.HasChange("enable_dns_support") {
		val := d.Get("enable_dns_support").(bool)
		modifyOpts := &ec2.ModifyVPCAttributeRequest{
			VPCID: &vpcid,
			EnableDNSSupport: &ec2.AttributeBooleanValue{
				Value: &val,
			},
		}

		log.Printf(
			"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_support")
	}

	if d.HasChange("enable_dns_hostnames") {
		val := d.Get("enable_dns_hostnames").(bool)
		modifyOpts := &ec2.ModifyVPCAttributeRequest{
			VPCID: &vpcid,
			EnableDNSHostnames: &ec2.AttributeBooleanValue{
				Value: &val,
			},
		}

		log.Printf(
			"[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if err := ec2conn.ModifyVPCAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_hostnames")
	}

	if err := setTags(ec2conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	d.Partial(false)
	return resourceAwsVpcRead(d, meta)
}

func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn
	vpcID := d.Id()
	DeleteVpcOpts := &ec2.DeleteVPCRequest{
		VPCID: &vpcID,
	}
	log.Printf("[INFO] Deleting VPC: %s", d.Id())
	if err := ec2conn.DeleteVPC(DeleteVpcOpts); err != nil {
		ec2err, ok := err.(aws.APIError)
		if ok && ec2err.Code == "InvalidVpcID.NotFound" {
			return nil
		}

		return fmt.Errorf("Error deleting VPC: %s", err)
	}

	return nil
}

// VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VPC.
func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		DescribeVpcOpts := &ec2.DescribeVPCsRequest{
			VPCIDs: []string{id},
		}
		resp, err := conn.DescribeVPCs(DescribeVpcOpts)
		if err != nil {
			if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on VPCStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		vpc := &resp.VPCs[0]
		return vpc, *vpc.State, nil
	}
}

func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("default"),
		Values: []string{("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []string{(d.Id())},
	}
	DescribeNetworkACLOpts := &ec2.DescribeNetworkACLsRequest{
		Filters: []ec2.Filter{*filter1, *filter2},
	}
	networkAclResp, err := conn.DescribeNetworkACLs(DescribeNetworkACLOpts)

	if err != nil {
		return err
	}
	if v := networkAclResp.NetworkACLs; len(v) > 0 {
		d.Set("default_network_acl_id", v[0].NetworkACLID)
	}

	return nil
}

func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("group-name"),
		Values: []string{("default")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []string{(d.Id())},
	}
	DescribeSgOpts := &ec2.DescribeSecurityGroupsRequest{
		Filters: []ec2.Filter{*filter1, *filter2},
	}
	securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts)

	if err != nil {
		return err
	}
	if v := securityGroupResp.SecurityGroups; len(v) > 0 {
		d.Set("default_security_group_id", v[0].GroupID)
	}

	return nil
}
<|endoftext|>


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

package axes

// label.go contains code that calculates the positions of labels on the axes.

import (
	"fmt"
	"image"

	"github.com/mum4k/termdash/align"
)

// Label is one value label on an axis.
type Label struct {
	// Value if the value to be displayed.
	Value *Value

	// Position of the label within the canvas.
	Pos image.Point
}

// yLabels returns labels that should be placed next to the Y axis.
// The labelWidth is the width of the area from the left-most side of the
// canvas until the Y axis (not including the Y axis). This is the area where
// the labels will be placed and aligned.
// Labels are returned in an increasing value order.
// Label value is not trimmed to the provided labelWidth, the label width is
// only used to align the labels. Alignment is done with the assumption that
// longer labels will be trimmed.
func yLabels(scale *YScale, labelWidth int) ([]*Label, error) {
	if min := 2; scale.GraphHeight < min {
		return nil, fmt.Errorf("cannot place labels on a canvas with height %d, minimum is %d", scale.GraphHeight, min)
	}
	if min := 1; labelWidth < min {
		return nil, fmt.Errorf("cannot place labels in label area width %d, minimum is %d", labelWidth, min)
	}

	var labels []*Label
	const labelSpacing = 4
	seen := map[string]bool{}
	for y := scale.GraphHeight - 1; y >= 0; y -= labelSpacing {
		label, err := rowLabel(scale, y, labelWidth)
		if err != nil {
			return nil, err
		}
		if !seen[label.Value.Text()] {
			labels = append(labels, label)
			seen[label.Value.Text()] = true
		}
	}

	// If we have data, place at least two labels, first and last.
	haveData := scale.Min.Rounded != 0 || scale.Max.Rounded != 0
	if len(labels) < 2 && haveData {
		const maxRow = 0
		label, err := rowLabel(scale, maxRow, labelWidth)
		if err != nil {
			return nil, err
		}
		labels = append(labels, label)
	}
	return labels, nil
}

// rowLabelArea determines the area available for labels on the specified row.
// The row is the Y coordinate of the row, Y coordinates grow down.
func rowLabelArea(row int, labelWidth int) image.Rectangle {
	return image.Rect(0, row, labelWidth, row+1)
}

// rowLabel returns label for the specified row.
func rowLabel(scale *YScale, y int, labelWidth int) (*Label, error) {
	v, err := scale.CellLabel(y)
	if err != nil {
		return nil, fmt.Errorf("unable to determine label value for row %d: %v", y, err)
	}

	ar := rowLabelArea(y, labelWidth)
	pos, err := align.Text(ar, v.Text(), align.HorizontalRight, align.VerticalMiddle)
	return &Label{
		Value: v,
		Pos:   pos,
	}, nil
}

// xSpace represents an available space among the X axis.
type xSpace struct {
	// min is the current relative coordinate.
	// These are zero based, i.e. not adjusted to axisStart.
	cur int
	// max is the maximum relative coordinate.
	// These are zero based, i.e. not adjusted to axisStart.
	// The xSpace instance contains points 0 <= x < max
	max int

	// graphZero is the (0, 0) point on the graph.
	graphZero image.Point
}

// newXSpace returns a new xSpace instance initialized for the provided width.
func newXSpace(graphZero image.Point, graphWidth int) *xSpace {
	return &xSpace{
		cur:       0,
		max:       graphWidth,
		graphZero: graphZero,
	}
}

// Implements fmt.Stringer.
func (xs *xSpace) String() string {
	return fmt.Sprintf("xSpace(size:%d)-cur:%v-max:%v", xs.Remaining(), image.Point{xs.cur, xs.graphZero.Y}, image.Point{xs.max, xs.graphZero.Y})
}

// Remaining returns the remaining size on the X axis.
func (xs *xSpace) Remaining() int {
	return xs.max - xs.cur
}

// Relative returns the relative coordinate within the space, these are zero
// based.
func (xs *xSpace) Relative() image.Point {
	return image.Point{xs.cur, xs.graphZero.Y + 1}
}

// LabelPos returns the absolute coordinate on the canvas where a label should
// be placed. The is the coordinate that represents the current relative
// coordinate of the space.
func (xs *xSpace) LabelPos() image.Point {
	return image.Point{xs.cur + xs.graphZero.X, xs.graphZero.Y + 2} // First down is the axis, second the label.
}

// Sub subtracts the specified size from the beginning of the available
// space.
func (xs *xSpace) Sub(size int) error {
	if xs.Remaining() < size {
		return fmt.Errorf("unable to subtract %d from the start, not enough size in %v", size, xs)
	}
	xs.cur += size
	return nil
}

// xLabels returns labels that should be placed under the X axis.
// The graphZero is the (0, 0) point of the graph area on the canvas.
// Labels are returned in an increasing value order.
// Returned labels shouldn't be trimmed, their count is adjusted so that they
// fit under the width of the axis.
// The customLabels map value positions in the series to the desired custom
// label. These are preferred if present.
func xLabels(scale *XScale, graphZero image.Point, customLabels map[int]string) ([]*Label, error) {
	space := newXSpace(graphZero, scale.GraphWidth)
	const minSpacing = 3
	var res []*Label

	next := 0
	for haveLabels := 0; haveLabels <= int(scale.Max.Value); haveLabels = len(res) {
		label, err := colLabel(scale, space, next, customLabels)
		if err != nil {
			return nil, err
		}
		if label == nil {
			break
		}
		res = append(res, label)

		next++
		if next > int(scale.Max.Value) {
			break
		}
		nextCell, err := scale.ValueToCell(next)
		if err != nil {
			return nil, err
		}

		skip := nextCell - space.Relative().X
		if skip < minSpacing {
			skip = minSpacing
		}

		if space.Remaining() <= skip {
			break
		}
		if err := space.Sub(skip); err != nil {
			return nil, err
		}
	}
	return res, nil
}

// colLabel returns a label placed either at the beginning of the space.
// The space is adjusted according to how much space was taken by the label.
// Returns nil, nil if the label doesn't fit in the space.
func colLabel(scale *XScale, space *xSpace, labelNum int, customLabels map[int]string) (*Label, error) {
	var val *Value
	if custom, ok := customLabels[labelNum]; ok {
		val = NewTextValue(custom)
	} else {
		pos := space.Relative()
		v, err := scale.CellLabel(pos.X)
		if err != nil {
			return nil, fmt.Errorf("unable to determine label value for column %d: %v", pos.X, err)
		}
		val = v
	}

	labelLen := len(val.Text())
	if labelLen > space.Remaining() {
		return nil, nil
	}

	abs := space.LabelPos()
	if err := space.Sub(labelLen); err != nil {
		return nil, err
	}

	return &Label{
		Value: val,
		Pos:   abs,
	}, nil
}
<commit_msg>Handle error instead of swallowing it<commit_after>// Copyright 2019 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package axes

// label.go contains code that calculates the positions of labels on the axes.

import (
	"fmt"
	"image"

	"github.com/mum4k/termdash/align"
)

// Label is one value label on an axis.
type Label struct {
	// Value if the value to be displayed.
	Value *Value

	// Position of the label within the canvas.
	Pos image.Point
}

// yLabels returns labels that should be placed next to the Y axis.
// The labelWidth is the width of the area from the left-most side of the
// canvas until the Y axis (not including the Y axis). This is the area where
// the labels will be placed and aligned.
// Labels are returned in an increasing value order.
// Label value is not trimmed to the provided labelWidth, the label width is
// only used to align the labels. Alignment is done with the assumption that
// longer labels will be trimmed.
func yLabels(scale *YScale, labelWidth int) ([]*Label, error) {
	if min := 2; scale.GraphHeight < min {
		return nil, fmt.Errorf("cannot place labels on a canvas with height %d, minimum is %d", scale.GraphHeight, min)
	}
	if min := 1; labelWidth < min {
		return nil, fmt.Errorf("cannot place labels in label area width %d, minimum is %d", labelWidth, min)
	}

	var labels []*Label
	const labelSpacing = 4
	seen := map[string]bool{}
	for y := scale.GraphHeight - 1; y >= 0; y -= labelSpacing {
		label, err := rowLabel(scale, y, labelWidth)
		if err != nil {
			return nil, err
		}
		if !seen[label.Value.Text()] {
			labels = append(labels, label)
			seen[label.Value.Text()] = true
		}
	}

	// If we have data, place at least two labels, first and last.
	haveData := scale.Min.Rounded != 0 || scale.Max.Rounded != 0
	if len(labels) < 2 && haveData {
		const maxRow = 0
		label, err := rowLabel(scale, maxRow, labelWidth)
		if err != nil {
			return nil, err
		}
		labels = append(labels, label)
	}
	return labels, nil
}

// rowLabelArea determines the area available for labels on the specified row.
// The row is the Y coordinate of the row, Y coordinates grow down.
func rowLabelArea(row int, labelWidth int) image.Rectangle {
	return image.Rect(0, row, labelWidth, row+1)
}

// rowLabel returns label for the specified row.
func rowLabel(scale *YScale, y int, labelWidth int) (*Label, error) {
	v, err := scale.CellLabel(y)
	if err != nil {
		return nil, fmt.Errorf("unable to determine label value for row %d: %v", y, err)
	}

	ar := rowLabelArea(y, labelWidth)
	pos, err := align.Text(ar, v.Text(), align.HorizontalRight, align.VerticalMiddle)
	if err != nil {
		return nil, err
	}
	return &Label{
		Value: v,
		Pos:   pos,
	}, nil
}

// xSpace represents an available space among the X axis.
type xSpace struct {
	// min is the current relative coordinate.
	// These are zero based, i.e. not adjusted to axisStart.
	cur int
	// max is the maximum relative coordinate.
	// These are zero based, i.e. not adjusted to axisStart.
	// The xSpace instance contains points 0 <= x < max
	max int

	// graphZero is the (0, 0) point on the graph.
	graphZero image.Point
}

// newXSpace returns a new xSpace instance initialized for the provided width.
func newXSpace(graphZero image.Point, graphWidth int) *xSpace {
	return &xSpace{
		cur:       0,
		max:       graphWidth,
		graphZero: graphZero,
	}
}

// Implements fmt.Stringer.
func (xs *xSpace) String() string {
	return fmt.Sprintf("xSpace(size:%d)-cur:%v-max:%v", xs.Remaining(), image.Point{xs.cur, xs.graphZero.Y}, image.Point{xs.max, xs.graphZero.Y})
}

// Remaining returns the remaining size on the X axis.
func (xs *xSpace) Remaining() int {
	return xs.max - xs.cur
}

// Relative returns the relative coordinate within the space, these are zero
// based.
func (xs *xSpace) Relative() image.Point {
	return image.Point{xs.cur, xs.graphZero.Y + 1}
}

// LabelPos returns the absolute coordinate on the canvas where a label should
// be placed. The is the coordinate that represents the current relative
// coordinate of the space.
func (xs *xSpace) LabelPos() image.Point {
	return image.Point{xs.cur + xs.graphZero.X, xs.graphZero.Y + 2} // First down is the axis, second the label.
}

// Sub subtracts the specified size from the beginning of the available
// space.
func (xs *xSpace) Sub(size int) error {
	if xs.Remaining() < size {
		return fmt.Errorf("unable to subtract %d from the start, not enough size in %v", size, xs)
	}
	xs.cur += size
	return nil
}

// xLabels returns labels that should be placed under the X axis.
// The graphZero is the (0, 0) point of the graph area on the canvas.
// Labels are returned in an increasing value order.
// Returned labels shouldn't be trimmed, their count is adjusted so that they
// fit under the width of the axis.
// The customLabels map value positions in the series to the desired custom
// label. These are preferred if present.
func xLabels(scale *XScale, graphZero image.Point, customLabels map[int]string) ([]*Label, error) {
	space := newXSpace(graphZero, scale.GraphWidth)
	const minSpacing = 3
	var res []*Label

	next := 0
	for haveLabels := 0; haveLabels <= int(scale.Max.Value); haveLabels = len(res) {
		label, err := colLabel(scale, space, next, customLabels)
		if err != nil {
			return nil, err
		}
		if label == nil {
			break
		}
		res = append(res, label)

		next++
		if next > int(scale.Max.Value) {
			break
		}
		nextCell, err := scale.ValueToCell(next)
		if err != nil {
			return nil, err
		}

		skip := nextCell - space.Relative().X
		if skip < minSpacing {
			skip = minSpacing
		}

		if space.Remaining() <= skip {
			break
		}
		if err := space.Sub(skip); err != nil {
			return nil, err
		}
	}
	return res, nil
}

// colLabel returns a label placed either at the beginning of the space.
// The space is adjusted according to how much space was taken by the label.
// Returns nil, nil if the label doesn't fit in the space.
func colLabel(scale *XScale, space *xSpace, labelNum int, customLabels map[int]string) (*Label, error) {
	var val *Value
	if custom, ok := customLabels[labelNum]; ok {
		val = NewTextValue(custom)
	} else {
		pos := space.Relative()
		v, err := scale.CellLabel(pos.X)
		if err != nil {
			return nil, fmt.Errorf("unable to determine label value for column %d: %v", pos.X, err)
		}
		val = v
	}

	labelLen := len(val.Text())
	if labelLen > space.Remaining() {
		return nil, nil
	}

	abs := space.LabelPos()
	if err := space.Sub(labelLen); err != nil {
		return nil, err
	}

	return &Label{
		Value: val,
		Pos:   abs,
	}, nil
}
<|endoftext|>


<commit_before>package firewaller

import (
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/watcher"
	"launchpad.net/tomb"
)

// Firewaller watches the state for ports opened or closed
// and reflects those changes onto the backing environment.
type Firewaller struct {
	st                  *state.State
	tomb                tomb.Tomb
	machinesWatcher     *state.MachinesWatcher
	machines            map[int]*machineTracker
	machineUnitsChanges chan *machineUnitsChange
	units               map[string]*unitTracker
	unitPortsChanges    chan *unitPortsChange
	services            map[string]*serviceTracker
}

// NewFirewaller returns a new Firewaller.
func NewFirewaller(st *state.State) (*Firewaller, error) {
	fw := &Firewaller{
		st:                  st,
		machinesWatcher:     st.WatchMachines(),
		machines:            make(map[int]*machineTracker),
		machineUnitsChanges: make(chan *machineUnitsChange),
		units:               make(map[string]*unitTracker),
		unitPortsChanges:    make(chan *unitPortsChange),
		services:            make(map[string]*serviceTracker),
	}
	go fw.loop()
	return fw, nil
}

func (fw *Firewaller) loop() {
	defer fw.finish()
	for {
		select {
		case <-fw.tomb.Dying():
			return
		case change, ok := <-fw.machinesWatcher.Changes():
			if !ok {
				return
			}
			for _, removedMachine := range change.Removed {
				mt, ok := fw.machines[removedMachine.Id()]
				if !ok {
					panic("trying to remove machine that wasn't added")
				}
				delete(fw.machines, removedMachine.Id())
				if err := mt.stop(); err != nil {
					log.Printf("machine tracker %d returned error when stopping: %v", removedMachine.Id(), err)
				}
				log.Debugf("firewaller: stopped tracking machine %d", removedMachine.Id())
			}
			for _, addedMachine := range change.Added {
				mt := newMachineTracker(addedMachine, fw)
				fw.machines[addedMachine.Id()] = mt
				log.Debugf("firewaller: started tracking machine %d", mt.id)
			}
		case change := <-fw.machineUnitsChanges:
			if change.change == nil {
				log.Printf("tracker of machine %d terminated prematurely: %v", change.machine.id, change.machine.stop())
				delete(fw.machines, change.machine.id)
				continue
			}
			for _, removedUnit := range change.change.Removed {
				ut, ok := fw.units[removedUnit.Name()]
				if !ok {
					panic("trying to remove unit that wasn't added")
				}
				delete(fw.units, removedUnit.Name())
				if err := ut.stop(); err != nil {
					log.Printf("unit tracker %s returned error when stopping: %v", removedUnit.Name(), err)
				}
				log.Debugf("firewaller: stopped tracking unit %s", removedUnit.Name())
			}
			for _, addedUnit := range change.change.Added {
				ut := newUnitTracker(addedUnit, fw)
				fw.units[addedUnit.Name()] = ut
				if fw.services[addedUnit.ServiceName()] == nil {
					// TODO(mue) Add service watcher.
				}
				log.Debugf("firewaller: started tracking unit %s", ut.name)
			}
		case <-fw.unitPortsChanges:
			// TODO(mue) Handle changes of ports.
		}
	}
}

// finishes cleans up when the firewaller is stopping.
func (fw *Firewaller) finish() {
	watcher.Stop(fw.machinesWatcher, &fw.tomb)
	for _, ut := range fw.units {
		fw.tomb.Kill(ut.stop())
	}
	for _, mt := range fw.machines {
		fw.tomb.Kill(mt.stop())
	}
	fw.tomb.Done()
}

// Wait waits for the Firewaller to exit.
func (fw *Firewaller) Wait() error {
	return fw.tomb.Wait()
}

// Stop stops the Firewaller and returns any error encountered while stopping.
func (fw *Firewaller) Stop() error {
	fw.tomb.Kill(nil)
	return fw.tomb.Wait()
}

// machineUnitsChange contains the changed units for one specific machine.
type machineUnitsChange struct {
	machine *machineTracker
	change  *state.MachineUnitsChange
}

// machineTracker keeps track of the unit changes of a machine.
type machineTracker struct {
	tomb       tomb.Tomb
	firewaller *Firewaller
	id         int
	watcher    *state.MachineUnitsWatcher
	ports      map[state.Port]*unitTracker
}

// newMachineTracker tracks unit changes to the given machine and sends them
// to the central firewaller loop.
func newMachineTracker(mst *state.Machine, fw *Firewaller) *machineTracker {
	mt := &machineTracker{
		firewaller: fw,
		id:         mst.Id(),
		watcher:    mst.WatchUnits(),
		ports:      make(map[state.Port]*unitTracker),
	}
	go mt.loop()
	return mt
}

// loop is the backend watching for machine units changes.
func (mt *machineTracker) loop() {
	defer mt.tomb.Done()
	defer mt.watcher.Stop()
	for {
		select {
		case <-mt.tomb.Dying():
			return
		case change, ok := <-mt.watcher.Changes():
			// Send change or nil in case of an error.
			select {
			case mt.firewaller.machineUnitsChanges <- &machineUnitsChange{mt, change}:
			case <-mt.tomb.Dying():
				return
			}
			// The watcher terminated prematurely, so end the loop.
			if !ok {
				mt.firewaller.tomb.Kill(watcher.MustErr(mt.watcher))
				return
			}
		}
	}
}

// stop stops the machine tracker.
func (mt *machineTracker) stop() error {
	mt.tomb.Kill(nil)
	return mt.tomb.Wait()
}

// unitPortsChange contains the changed ports for one specific unit.
type unitPortsChange struct {
	unit   *unitTracker
	change []state.Port
}

// unitTracker keeps track of the port changes of a unit.
type unitTracker struct {
	tomb       tomb.Tomb
	firewaller *Firewaller
	name       string
	watcher    *state.PortsWatcher
	service    *serviceTracker
	ports      []state.Port
}

// newUnitTracker creates a new machine tracker keeping track of
// unit changes of the passed machine.
func newUnitTracker(ust *state.Unit, fw *Firewaller) *unitTracker {
	ut := &unitTracker{
		firewaller: fw,
		name:       ust.Name(),
		watcher:    ust.WatchPorts(),
		ports:      make([]state.Port, 0),
	}
	go ut.loop()
	return ut
}

func (ut *unitTracker) loop() {
	defer ut.tomb.Done()
	defer ut.watcher.Stop()
	for {
		select {
		case <-ut.tomb.Dying():
			return
		case change, ok := <-ut.watcher.Changes():
			// Send change or nil in case of an error.
			select {
			case ut.firewaller.unitPortsChanges <- &unitPortsChange{ut, change}:
			case <-ut.tomb.Dying():
				return
			}
			// The watcher terminated prematurely, so end the loop.
			if !ok {
				ut.firewaller.tomb.Kill(watcher.MustErr(ut.watcher))
				return
			}
		}
	}
}

// stop stops the unit tracker.
func (ut *unitTracker) stop() error {
	ut.tomb.Kill(nil)
	return ut.tomb.Wait()
}

// serviceTracker  keeps track of the changes of a service.
type serviceTracker struct {
	name    string
	exposed bool
}
<commit_msg>firewaller: commit due to wrong system clock<commit_after>package firewaller

import (
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/watcher"
	"launchpad.net/tomb"
)

// Firewaller watches the state for ports opened or closed
// and reflects those changes onto the backing environment.
type Firewaller struct {
	st                  *state.State
	tomb                tomb.Tomb
	machinesWatcher     *state.MachinesWatcher
	machines            map[int]*machineTracker
	machineUnitsChanges chan *machineUnitsChange
	units               map[string]*unitTracker
	unitPortsChanges    chan *unitPortsChange
	services            map[string]*serviceTracker
}

// NewFirewaller returns a new Firewaller.
func NewFirewaller(st *state.State) (*Firewaller, error) {
	fw := &Firewaller{
		st:                  st,
		machinesWatcher:     st.WatchMachines(),
		machines:            make(map[int]*machineTracker),
		machineUnitsChanges: make(chan *machineUnitsChange),
		units:               make(map[string]*unitTracker),
		unitPortsChanges:    make(chan *unitPortsChange),
		services:            make(map[string]*serviceTracker),
	}
	go fw.loop()
	return fw, nil
}

func (fw *Firewaller) loop() {
	defer fw.finish()
	for {
		select {
		case <-fw.tomb.Dying():
			return
		case change, ok := <-fw.machinesWatcher.Changes():
			if !ok {
				return
			}
			for _, removedMachine := range change.Removed {
				mt, ok := fw.machines[removedMachine.Id()]
				if !ok {
					panic("trying to remove machine that wasn't added")
				}
				delete(fw.machines, removedMachine.Id())
				if err := mt.stop(); err != nil {
					log.Printf("machine tracker %d returned error when stopping: %v", removedMachine.Id(), err)
				}
				log.Debugf("firewaller: stopped tracking machine %d", removedMachine.Id())
			}
			for _, addedMachine := range change.Added {
				mt := newMachineTracker(addedMachine, fw)
				fw.machines[addedMachine.Id()] = mt
				log.Debugf("firewaller: started tracking machine %d", mt.id)
			}
		case change := <-fw.machineUnitsChanges:
			if change.change == nil {
				log.Printf("tracker of machine %d terminated prematurely: %v", change.machine.id, change.machine.stop())
				delete(fw.machines, change.machine.id)
				continue
			}
			for _, removedUnit := range change.change.Removed {
				ut, ok := fw.units[removedUnit.Name()]
				if !ok {
					panic("trying to remove unit that wasn't added")
				}
				delete(fw.units, removedUnit.Name())
				if err := ut.stop(); err != nil {
					log.Printf("unit tracker %s returned error when stopping: %v", removedUnit.Name(), err)
				}
				log.Debugf("firewaller: stopped tracking unit %s", removedUnit.Name())
			}
			for _, addedUnit := range change.change.Added {
				ut := newUnitTracker(addedUnit, fw)
				fw.units[addedUnit.Name()] = ut
				if fw.services[addedUnit.ServiceName()] == nil {
					// TODO(mue) Add service watcher.
				}
				log.Debugf("firewaller: started tracking unit %s", ut.name)
			}
		case <-fw.unitPortsChanges:
			// TODO(mue) Handle changes of ports.
		}
	}
}

// finishes cleans up when the firewaller is stopping.
func (fw *Firewaller) finish() {
	watcher.Stop(fw.machinesWatcher, &fw.tomb)
	for _, ut := range fw.units {
		fw.tomb.Kill(ut.stop())
	}
	for _, mt := range fw.machines {
		fw.tomb.Kill(mt.stop())
	}
	fw.tomb.Done()
}

// Wait waits for the Firewaller to exit.
func (fw *Firewaller) Wait() error {
	return fw.tomb.Wait()
}

// Stop stops the Firewaller and returns any error encountered while stopping.
func (fw *Firewaller) Stop() error {
	fw.tomb.Kill(nil)
	return fw.tomb.Wait()
}

// machineUnitsChange contains the changed units for one specific machine.
type machineUnitsChange struct {
	machine *machineTracker
	change  *state.MachineUnitsChange
}

// machineTracker keeps track of the unit changes of a machine.
type machineTracker struct {
	tomb       tomb.Tomb
	firewaller *Firewaller
	id         int
	watcher    *state.MachineUnitsWatcher
	ports      map[state.Port]*unitTracker
}

// newMachineTracker tracks unit changes to the given machine and sends them
// to the central firewaller loop.
func newMachineTracker(mst *state.Machine, fw *Firewaller) *machineTracker {
	mt := &machineTracker{
		firewaller: fw,
		id:         mst.Id(),
		watcher:    mst.WatchUnits(),
		ports:      make(map[state.Port]*unitTracker),
	}
	go mt.loop()
	return mt
}

// loop is the backend watching for machine units changes.
func (mt *machineTracker) loop() {
	defer mt.tomb.Done()
	defer mt.watcher.Stop()
	for {
		select {
		case <-mt.tomb.Dying():
			return
		case change, ok := <-mt.watcher.Changes():
			// Send change or nil in case of an error.
			select {
			case mt.firewaller.machineUnitsChanges <- &machineUnitsChange{mt, change}:
			case <-mt.tomb.Dying():
				return
			}
			// The watcher terminated prematurely, so end the loop.
			if !ok {
				mt.firewaller.tomb.Kill(watcher.MustErr(mt.watcher))
				return
			}
		}
	}
}

// stop stops the machine tracker.
func (mt *machineTracker) stop() error {
	mt.tomb.Kill(nil)
	return mt.tomb.Wait()
}

// unitPortsChange contains the changed ports for one specific unit.
type unitPortsChange struct {
	unit   *unitTracker
	change []state.Port
}

// unitTracker keeps track of the port changes of a unit.
type unitTracker struct {
	tomb       tomb.Tomb
	firewaller *Firewaller
	name       string
	watcher    *state.PortsWatcher
	service    *serviceTracker
	ports      []state.Port
}

// newUnitTracker creates a new machine tracker keeping track of
// unit changes of the passed machine.
func newUnitTracker(ust *state.Unit, fw *Firewaller) *unitTracker {
	ut := &unitTracker{
		firewaller: fw,
		name:       ust.Name(),
		watcher:    ust.WatchPorts(),
		ports:      make([]state.Port, 0),
	}
	go ut.loop()
	return ut
}

func (ut *unitTracker) loop() {
	defer ut.tomb.Done()
	defer ut.watcher.Stop()
	for {
		select {
		case <-ut.tomb.Dying():
			return
		case change, ok := <-ut.watcher.Changes():
			// Send change or nil in case of an error.
			select {
			case ut.firewaller.unitPortsChanges <- &unitPortsChange{ut, change}:
			case <-ut.tomb.Dying():
				return
			}
			// The watcher terminated prematurely, so end the loop.
			if !ok {
				ut.firewaller.tomb.Kill(watcher.MustErr(ut.watcher))
				return
			}
		}
	}
}

// stop stops the unit tracker.
func (ut *unitTracker) stop() error {
	ut.tomb.Kill(nil)
	return ut.tomb.Wait()
}

// serviceTracker  keeps track of the changes of a service.
type serviceTracker struct {
	name    string
	exposed bool
}
<|endoftext|>


<commit_before>package s3gof3r

import (
	"crypto/md5"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"syscall"
	"time"
)

const (
	qWaitSz = 2
)

type getter struct {
	url   url.URL
	b     *Bucket
	bufsz int64
	err   error

	chunkID    int
	rChunk     *chunk
	contentLen int64
	bytesRead  int64
	chunkTotal int

	readCh chan *chunk
	getCh  chan *chunk
	quit   chan struct{}
	qWait  map[int]*chunk

	sp *bp

	closed bool
	c      *Config

	md5  hash.Hash
	cIdx int64
}

type chunk struct {
	id     int
	header http.Header
	start  int64
	size   int64
	b      []byte
}

func newGetter(getURL url.URL, c *Config, b *Bucket) (io.ReadCloser, http.Header, error) {
	g := new(getter)
	g.url = getURL
	g.c, g.b = new(Config), new(Bucket)
	*g.c, *g.b = *c, *b
	g.bufsz = max64(c.PartSize, 1)
	g.c.NTry = max(c.NTry, 1)
	g.c.Concurrency = max(c.Concurrency, 1)

	g.getCh = make(chan *chunk)
	g.readCh = make(chan *chunk)
	g.quit = make(chan struct{})
	g.qWait = make(map[int]*chunk)
	g.b = b
	g.md5 = md5.New()

	// use get instead of head for error messaging
	resp, err := g.retryRequest("GET", g.url.String(), nil)
	if err != nil {
		return nil, nil, err
	}
	defer checkClose(resp.Body, &err)
	if resp.StatusCode != 200 {
		return nil, nil, newRespError(resp)
	}

	// Golang changes content-length to -1 when chunked transfer encoding / EOF close response detected
	if resp.ContentLength == -1 {
		return nil, nil, fmt.Errorf("Retrieving objects with undefined content-length " +
			" responses (chunked transfer encoding / EOF close) is not supported")
	}

	g.contentLen = resp.ContentLength
	g.chunkTotal = int((g.contentLen + g.bufsz - 1) / g.bufsz) // round up, integer division
	logger.debugPrintf("object size: %3.2g MB", float64(g.contentLen)/float64((1*mb)))

	g.sp = bufferPool(g.bufsz)

	for i := 0; i < g.c.Concurrency; i++ {
		go g.worker()
	}
	go g.initChunks()
	return g, resp.Header, nil
}

func (g *getter) retryRequest(method, urlStr string, body io.ReadSeeker) (resp *http.Response, err error) {
	for i := 0; i < g.c.NTry; i++ {
		var req *http.Request
		req, err = http.NewRequest(method, urlStr, body)
		if err != nil {
			return
		}
		g.b.Sign(req)
		resp, err = g.c.Client.Do(req)
		if err == nil {
			return
		}
		logger.debugPrintln(err)
		if body != nil {
			if _, err = body.Seek(0, 0); err != nil {
				return
			}
		}
	}
	return
}

func (g *getter) initChunks() {
	id := 0
	for i := int64(0); i < g.contentLen; {
		for len(g.qWait) >= qWaitSz {
			// Limit growth of qWait
			time.Sleep(100 * time.Millisecond)
		}
		size := min64(g.bufsz, g.contentLen-i)
		c := &chunk{
			id: id,
			header: http.Header{
				"Range": {fmt.Sprintf("bytes=%d-%d",
					i, i+size-1)},
			},
			start: i,
			size:  size,
			b:     nil,
		}
		i += size
		id++
		g.getCh <- c
	}
	close(g.getCh)
}

func (g *getter) worker() {
	for c := range g.getCh {
		g.retryGetChunk(c)
	}

}

func (g *getter) retryGetChunk(c *chunk) {
	var err error
	c.b = <-g.sp.get
	for i := 0; i < g.c.NTry; i++ {
		time.Sleep(time.Duration(math.Exp2(float64(i))) * 100 * time.Millisecond) // exponential back-off
		err = g.getChunk(c)
		if err == nil {
			return
		}
		logger.debugPrintf("error on attempt %d: retrying chunk: %v, error: %s", i, c.id, err)
	}
	g.err = err
	close(g.quit) // out of tries, ensure quit by closing channel
}

func (g *getter) getChunk(c *chunk) error {
	// ensure buffer is empty

	r, err := http.NewRequest("GET", g.url.String(), nil)
	if err != nil {
		return err
	}
	r.Header = c.header
	g.b.Sign(r)
	resp, err := g.c.Client.Do(r)
	if err != nil {
		return err
	}
	defer checkClose(resp.Body, &err)
	if resp.StatusCode != 206 {
		return newRespError(resp)
	}
	n, err := io.ReadAtLeast(resp.Body, c.b, int(c.size))
	if err != nil {
		return err
	}
	if int64(n) != c.size {
		return fmt.Errorf("chunk %d: Expected %d bytes, received %d",
			c.id, c.size, n)
	}
	g.readCh <- c
	return nil
}

func (g *getter) Read(p []byte) (int, error) {
	var err error
	if g.closed {
		return 0, syscall.EINVAL
	}
	if g.err != nil {
		return 0, g.err
	}
	nw := 0
	for nw < len(p) {
		if g.bytesRead == g.contentLen {
			return nw, io.EOF
		} else if g.bytesRead > g.contentLen {
			// Here for robustness / completeness
			// Should not occur as golang uses LimitedReader up to content-length
			return nw, fmt.Errorf("Expected %d bytes, received %d (too many bytes)",
				g.contentLen, g.bytesRead)
		}

		// If for some reason no more chunks to be read and bytes are off, error, incomplete result
		if g.chunkID >= g.chunkTotal {
			return nw, fmt.Errorf("Expected %d bytes, received %d and chunkID %d >= chunkTotal %d (no more chunks remaining)",
				g.contentLen, g.bytesRead, g.chunkID, g.chunkTotal)
		}

		if g.rChunk == nil {
			g.rChunk, err = g.nextChunk()
			if err != nil {
				return 0, err
			}
			g.cIdx = 0
		}

		n := copy(p[nw:], g.rChunk.b[g.cIdx:g.rChunk.size])
		g.cIdx += int64(n)
		nw += n
		g.bytesRead += int64(n)

		if g.cIdx >= g.rChunk.size { // chunk complete
			g.sp.give <- g.rChunk.b
			g.chunkID++
			g.rChunk = nil
		}
	}
	return nw, nil

}

func (g *getter) nextChunk() (*chunk, error) {
	for {

		// first check qWait
		c := g.qWait[g.chunkID]
		if c != nil {
			delete(g.qWait, g.chunkID)
			if g.c.Md5Check {
				if _, err := g.md5.Write(c.b[:c.size]); err != nil {
					return nil, err
				}
			}
			return c, nil
		}
		// if next chunk not in qWait, read from channel
		select {
		case c := <-g.readCh:
			g.qWait[c.id] = c
		case <-g.quit:
			return nil, g.err // fatal error, quit.
		}
	}
}

func (g *getter) Close() error {
	if g.closed {
		return syscall.EINVAL
	}
	g.closed = true
	close(g.sp.quit)
	if g.err != nil {
		return g.err
	}
	if g.bytesRead != g.contentLen {
		return fmt.Errorf("read error: %d bytes read. expected: %d", g.bytesRead, g.contentLen)
	}
	if g.c.Md5Check {
		if err := g.checkMd5(); err != nil {
			return err
		}
	}
	return nil
}

func (g *getter) checkMd5() (err error) {
	calcMd5 := fmt.Sprintf("%x", g.md5.Sum(nil))
	md5Path := fmt.Sprint(".md5", g.url.Path, ".md5")
	md5Url, err := g.b.url(md5Path, g.c)
	if err != nil {
		return err
	}

	logger.debugPrintln("md5: ", calcMd5)
	logger.debugPrintln("md5Path: ", md5Path)
	resp, err := g.retryRequest("GET", md5Url.String(), nil)
	if err != nil {
		return
	}
	defer checkClose(resp.Body, &err)
	if resp.StatusCode != 200 {
		return fmt.Errorf("MD5 check failed: %s not found: %s", md5Url.String(), newRespError(resp))
	}
	givenMd5, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	if calcMd5 != string(givenMd5) {
		return fmt.Errorf("MD5 mismatch. given:%s calculated:%s", givenMd5, calcMd5)
	}
	return
}
<commit_msg>use sync.Cond to limit memory growth on gets<commit_after>package s3gof3r

import (
	"crypto/md5"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"sync"
	"syscall"
	"time"
)

const (
	qWaitMax = 2
)

type getter struct {
	url   url.URL
	b     *Bucket
	bufsz int64
	err   error

	chunkID    int
	rChunk     *chunk
	contentLen int64
	bytesRead  int64
	chunkTotal int

	readCh   chan *chunk
	getCh    chan *chunk
	quit     chan struct{}
	qWait    map[int]*chunk
	qWaitLen uint
	cond     sync.Cond

	sp *bp

	closed bool
	c      *Config

	md5  hash.Hash
	cIdx int64
}

type chunk struct {
	id     int
	header http.Header
	start  int64
	size   int64
	b      []byte
}

func newGetter(getURL url.URL, c *Config, b *Bucket) (io.ReadCloser, http.Header, error) {
	g := new(getter)
	g.url = getURL
	g.c, g.b = new(Config), new(Bucket)
	*g.c, *g.b = *c, *b
	g.bufsz = max64(c.PartSize, 1)
	g.c.NTry = max(c.NTry, 1)
	g.c.Concurrency = max(c.Concurrency, 1)

	g.getCh = make(chan *chunk)
	g.readCh = make(chan *chunk)
	g.quit = make(chan struct{})
	g.qWait = make(map[int]*chunk)
	g.b = b
	g.md5 = md5.New()
	g.cond = sync.Cond{L: &sync.Mutex{}}

	// use get instead of head for error messaging
	resp, err := g.retryRequest("GET", g.url.String(), nil)
	if err != nil {
		return nil, nil, err
	}
	defer checkClose(resp.Body, &err)
	if resp.StatusCode != 200 {
		return nil, nil, newRespError(resp)
	}

	// Golang changes content-length to -1 when chunked transfer encoding / EOF close response detected
	if resp.ContentLength == -1 {
		return nil, nil, fmt.Errorf("Retrieving objects with undefined content-length " +
			" responses (chunked transfer encoding / EOF close) is not supported")
	}

	g.contentLen = resp.ContentLength
	g.chunkTotal = int((g.contentLen + g.bufsz - 1) / g.bufsz) // round up, integer division
	logger.debugPrintf("object size: %3.2g MB", float64(g.contentLen)/float64((1*mb)))

	g.sp = bufferPool(g.bufsz)

	for i := 0; i < g.c.Concurrency; i++ {
		go g.worker()
	}
	go g.initChunks()
	return g, resp.Header, nil
}

func (g *getter) retryRequest(method, urlStr string, body io.ReadSeeker) (resp *http.Response, err error) {
	for i := 0; i < g.c.NTry; i++ {
		var req *http.Request
		req, err = http.NewRequest(method, urlStr, body)
		if err != nil {
			return
		}
		g.b.Sign(req)
		resp, err = g.c.Client.Do(req)
		if err == nil {
			return
		}
		logger.debugPrintln(err)
		if body != nil {
			if _, err = body.Seek(0, 0); err != nil {
				return
			}
		}
	}
	return
}

func (g *getter) initChunks() {
	id := 0
	for i := int64(0); i < g.contentLen; {
		size := min64(g.bufsz, g.contentLen-i)
		c := &chunk{
			id: id,
			header: http.Header{
				"Range": {fmt.Sprintf("bytes=%d-%d",
					i, i+size-1)},
			},
			start: i,
			size:  size,
			b:     nil,
		}
		i += size
		id++
		g.getCh <- c
	}
	close(g.getCh)
}

func (g *getter) worker() {
	for c := range g.getCh {
		g.retryGetChunk(c)
	}

}

func (g *getter) retryGetChunk(c *chunk) {
	var err error
	c.b = <-g.sp.get
	for i := 0; i < g.c.NTry; i++ {
		time.Sleep(time.Duration(math.Exp2(float64(i))) * 100 * time.Millisecond) // exponential back-off
		err = g.getChunk(c)
		if err == nil {
			return
		}
		logger.debugPrintf("error on attempt %d: retrying chunk: %v, error: %s", i, c.id, err)
	}
	g.err = err
	close(g.quit) // out of tries, ensure quit by closing channel
}

func (g *getter) getChunk(c *chunk) error {
	// ensure buffer is empty

	r, err := http.NewRequest("GET", g.url.String(), nil)
	if err != nil {
		return err
	}
	r.Header = c.header
	g.b.Sign(r)
	resp, err := g.c.Client.Do(r)
	if err != nil {
		return err
	}
	defer checkClose(resp.Body, &err)
	if resp.StatusCode != 206 {
		return newRespError(resp)
	}
	n, err := io.ReadAtLeast(resp.Body, c.b, int(c.size))
	if err != nil {
		return err
	}
	if err := resp.Body.Close(); err != nil {
		return err
	}
	if int64(n) != c.size {
		return fmt.Errorf("chunk %d: Expected %d bytes, received %d",
			c.id, c.size, n)
	}
	g.readCh <- c

	// wait for qWait to drain before starting next chunk
	g.cond.L.Lock()
	for g.qWaitLen >= qWaitMax {
		g.cond.Wait()
	}
	g.cond.L.Unlock()
	return nil
}

func (g *getter) Read(p []byte) (int, error) {
	var err error
	if g.closed {
		return 0, syscall.EINVAL
	}
	if g.err != nil {
		return 0, g.err
	}
	nw := 0
	for nw < len(p) {
		if g.bytesRead == g.contentLen {
			return nw, io.EOF
		} else if g.bytesRead > g.contentLen {
			// Here for robustness / completeness
			// Should not occur as golang uses LimitedReader up to content-length
			return nw, fmt.Errorf("Expected %d bytes, received %d (too many bytes)",
				g.contentLen, g.bytesRead)
		}

		// If for some reason no more chunks to be read and bytes are off, error, incomplete result
		if g.chunkID >= g.chunkTotal {
			return nw, fmt.Errorf("Expected %d bytes, received %d and chunkID %d >= chunkTotal %d (no more chunks remaining)",
				g.contentLen, g.bytesRead, g.chunkID, g.chunkTotal)
		}

		if g.rChunk == nil {
			g.rChunk, err = g.nextChunk()
			if err != nil {
				return 0, err
			}
			g.cIdx = 0
		}

		n := copy(p[nw:], g.rChunk.b[g.cIdx:g.rChunk.size])
		g.cIdx += int64(n)
		nw += n
		g.bytesRead += int64(n)

		if g.cIdx >= g.rChunk.size { // chunk complete
			g.sp.give <- g.rChunk.b
			g.chunkID++
			g.rChunk = nil
		}
	}
	return nw, nil

}

func (g *getter) nextChunk() (*chunk, error) {
	for {

		// first check qWait
		c := g.qWait[g.chunkID]
		if c != nil {
			delete(g.qWait, g.chunkID)
			g.cond.L.Lock()
			g.qWaitLen--
			g.cond.L.Unlock()
			g.cond.Signal() // wake up waiting worker goroutine
			if g.c.Md5Check {
				if _, err := g.md5.Write(c.b[:c.size]); err != nil {
					return nil, err
				}
			}
			return c, nil
		}
		// if next chunk not in qWait, read from channel
		select {
		case c := <-g.readCh:
			g.qWait[c.id] = c
			g.cond.L.Lock()
			g.qWaitLen++
			g.cond.L.Unlock()
		case <-g.quit:
			return nil, g.err // fatal error, quit.
		}
	}
}

func (g *getter) Close() error {
	if g.closed {
		return syscall.EINVAL
	}
	g.closed = true
	close(g.sp.quit)
	if g.err != nil {
		return g.err
	}
	if g.bytesRead != g.contentLen {
		return fmt.Errorf("read error: %d bytes read. expected: %d", g.bytesRead, g.contentLen)
	}
	if g.c.Md5Check {
		if err := g.checkMd5(); err != nil {
			return err
		}
	}
	return nil
}

func (g *getter) checkMd5() (err error) {
	calcMd5 := fmt.Sprintf("%x", g.md5.Sum(nil))
	md5Path := fmt.Sprint(".md5", g.url.Path, ".md5")
	md5Url, err := g.b.url(md5Path, g.c)
	if err != nil {
		return err
	}

	logger.debugPrintln("md5: ", calcMd5)
	logger.debugPrintln("md5Path: ", md5Path)
	resp, err := g.retryRequest("GET", md5Url.String(), nil)
	if err != nil {
		return
	}
	defer checkClose(resp.Body, &err)
	if resp.StatusCode != 200 {
		return fmt.Errorf("MD5 check failed: %s not found: %s", md5Url.String(), newRespError(resp))
	}
	givenMd5, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	if calcMd5 != string(givenMd5) {
		return fmt.Errorf("MD5 mismatch. given:%s calculated:%s", givenMd5, calcMd5)
	}
	return
}
<|endoftext|>


<commit_before>package prscrape

// generic scraping functions for PR scrapers to use

import (
	"bytes"
	"code.google.com/p/cascadia"
	"code.google.com/p/go.net/html"
	"github.com/bcampbell/fuzzytime"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// GenericFetchList fetches a page, and extracts matching links.
func GenericFetchList(scraperName, pageUrl, linkSelector string) ([]*PressRelease, error) {
	page, err := url.Parse(pageUrl)
	if err != nil {
		return nil, err // TODO: wrap up as ScrapeError?
	}

	linkSel := cascadia.MustCompile(linkSelector)
	resp, err := http.Get(pageUrl)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	root, err := html.Parse(resp.Body)
	if err != nil {
		return nil, err // TODO: wrap up as ScrapeError?
	}
	docs := make([]*PressRelease, 0)
	for _, a := range linkSel.MatchAll(root) {
		link, err := page.Parse(GetAttr(a, "href")) // extend to absolute url if needed
		if err != nil {
			// TODO: log a warning?
			continue
		}
		pr := PressRelease{Source: scraperName, Permalink: link.String()}
		docs = append(docs, &pr)
	}
	return docs, nil
}

// GenericScrape scrapes a press release from raw_html based on a bunch of css selector strings
func GenericScrape(source string, pr *PressRelease, raw_html, title, content, cruft, pubDate string) error {
	titleSel := cascadia.MustCompile(title)
	contentSel := cascadia.MustCompile(content)

	r := strings.NewReader(string(raw_html))
	root, err := html.Parse(r)
	if err != nil {
		return err // TODO: wrap up as ScrapeError?
	}

	pr.Source = source

	// title
	pr.Title = CompressSpace(GetTextContent(titleSel.MatchAll(root)[0]))

	// pubdate - only needs to contain a valid date string, doesn't matter
	// if there's other crap in there too.
	if pubDate != "" {
		pubDateSel := cascadia.MustCompile(pubDate)
		dateTxt := GetTextContent(pubDateSel.MatchAll(root)[0])
		pr.PubDate, err = fuzzytime.Parse(dateTxt)
		if err != nil {
			return err
		}
	} else {
		// if time isn't already set, just fudge using current time
		if pr.PubDate.IsZero() {
			pr.PubDate = time.Now()
		}
	}

	// content
	contentEl := contentSel.MatchAll(root)[0]
	if cruft != "" {
		cruftSel := cascadia.MustCompile(cruft)
		for _, cruft := range cruftSel.MatchAll(contentEl) {
			cruft.Parent.RemoveChild(cruft)
		}
	}
	var out bytes.Buffer
	err = html.Render(&out, contentEl)
	if err != nil {
		return err
	}
	pr.Content = out.String()
	return nil
}
<commit_msg>GenericScrape - pick up all matching content elements<commit_after>package prscrape

// generic scraping functions for PR scrapers to use

import (
	"bytes"
	"code.google.com/p/cascadia"
	"code.google.com/p/go.net/html"
	"github.com/bcampbell/fuzzytime"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// GenericFetchList fetches a page, and extracts matching links.
func GenericFetchList(scraperName, pageUrl, linkSelector string) ([]*PressRelease, error) {
	page, err := url.Parse(pageUrl)
	if err != nil {
		return nil, err // TODO: wrap up as ScrapeError?
	}

	linkSel := cascadia.MustCompile(linkSelector)
	resp, err := http.Get(pageUrl)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	root, err := html.Parse(resp.Body)
	if err != nil {
		return nil, err // TODO: wrap up as ScrapeError?
	}
	docs := make([]*PressRelease, 0)
	for _, a := range linkSel.MatchAll(root) {
		link, err := page.Parse(GetAttr(a, "href")) // extend to absolute url if needed
		if err != nil {
			// TODO: log a warning?
			continue
		}
		pr := PressRelease{Source: scraperName, Permalink: link.String()}
		docs = append(docs, &pr)
	}
	return docs, nil
}

// GenericScrape scrapes a press release from raw_html based on a bunch of css selector strings
func GenericScrape(source string, pr *PressRelease, raw_html, title, content, cruft, pubDate string) error {
	titleSel := cascadia.MustCompile(title)
	contentSel := cascadia.MustCompile(content)

	r := strings.NewReader(string(raw_html))
	root, err := html.Parse(r)
	if err != nil {
		return err // TODO: wrap up as ScrapeError?
	}

	pr.Source = source

	// title
	pr.Title = CompressSpace(GetTextContent(titleSel.MatchAll(root)[0]))

	// pubdate - only needs to contain a valid date string, doesn't matter
	// if there's other crap in there too.
	if pubDate != "" {
		pubDateSel := cascadia.MustCompile(pubDate)
		dateTxt := GetTextContent(pubDateSel.MatchAll(root)[0])
		pr.PubDate, err = fuzzytime.Parse(dateTxt)
		if err != nil {
			return err
		}
	} else {
		// if time isn't already set, just fudge using current time
		if pr.PubDate.IsZero() {
			pr.PubDate = time.Now()
		}
	}

	// content
	contentElements := contentSel.MatchAll(root)
	if cruft != "" {
		cruftSel := cascadia.MustCompile(cruft)
		for _, el := range contentElements {
			for _, cruft := range cruftSel.MatchAll(el) {
				cruft.Parent.RemoveChild(cruft)
			}
		}
	}
	var out bytes.Buffer
	for _, el := range contentElements {
		err = html.Render(&out, el)
		if err != nil {
			return err
		}
	}

	pr.Content = out.String()
	return nil
}
<|endoftext|>


<commit_before>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package mdns

import "bytes"
import "fmt"
import "log"
import "math"
import "math/rand"
import "net"
import "time"
import "syscall"
import "unsafe"

import "code.google.com/p/go.net/ipv4"

import "netlink"

const maddr4 = "224.0.0.251:5353"
const maddr6 = "[FF02::FB]:5353"

func NewConn(addr string) (*net.UDPAddr, *ipv4.PacketConn, error) {
	saddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not resolve address '%s': %s", addr, err)
	}

	smaddr, err := net.ResolveUDPAddr("udp", maddr4)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not resolve address '%s': %s", maddr4, err)
	}

	udp, err := net.ListenUDP("udp", saddr)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not listen: %s", err)
	}

	p := ipv4.NewPacketConn(udp)

	err = p.SetTTL(1)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not set TTL: %s", err)
	}

	err = p.SetMulticastLoopback(false)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set loop: %s", err)
	}

	err = p.SetControlMessage(ipv4.FlagInterface|ipv4.FlagDst, true)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set ctrlmsg: %s", err)
	}

	return smaddr, p, nil
}

func NewServer(addr string) (*net.UDPAddr, *ipv4.PacketConn, error) {
	smaddr, p, err := NewConn(addr)
	if err != nil {
		return nil, nil, err
	}

	go MonitorNetwork(p, smaddr)

	return smaddr, p, nil
}

func NewClient(addr string) (*net.UDPAddr, *ipv4.PacketConn, error) {
	return NewConn(addr)
}

func Read(p *ipv4.PacketConn) (*Message, net.IP, *net.IPNet, *net.IPNet, *net.UDPAddr, error) {
	var local4 *net.IPNet
	var local6 *net.IPNet

	pkt := make([]byte, 9000)

	n, cm, from, err := p.ReadFrom(pkt)
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not read: %s", err)
	}

	ifi, err := net.InterfaceByIndex(cm.IfIndex)
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not find if: %s", err)
	}

	addrs, err := ifi.Addrs()
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not find addrs: %s", err)
	}

	for _, a := range addrs {
		if a.(*net.IPNet).IP.To4() != nil {
			local4 = a.(*net.IPNet)
		} else {
			local6 = a.(*net.IPNet)
		}
	}

	req, err := Unpack(pkt[:n])
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not unpack request: %s", err)
	}

	return req, cm.Dst, local4, local6, from.(*net.UDPAddr), err
}

func Write(p *ipv4.PacketConn, addr *net.UDPAddr, msg *Message) error {
	pkt, err := Pack(msg)
	if err != nil {
		return fmt.Errorf("Could not pack response: %s", err)
	}

	_, err = p.WriteTo(pkt, nil, addr)
	if err != nil {
		return fmt.Errorf("Could not write to network: %s", err)
	}

	return nil
}

func SendRequest(req *Message) (*Message, error) {
	maddr, client, err := NewClient("0.0.0.0:0")
	if err != nil {
		return nil, fmt.Errorf("Could not create client: %s", err)
	}
	defer client.Close()

	seconds := 3 * time.Second
	timeout := time.Now().Add(seconds)

	err = Write(client, maddr, req)
	if err != nil {
		return nil, fmt.Errorf("Could not send request: %s", err)
	}

	client.SetReadDeadline(timeout)

	rsp, _, _, _, _, err := Read(client)
	if err != nil {
		return nil, fmt.Errorf("Could not read response: %s", err)
	}

	if rsp.Header.Id != req.Header.Id {
		return nil, fmt.Errorf("Wrong id: %d", rsp.Header.Id)
	}

	return rsp, nil
}

func SendRecursiveRequest(msg *Message, q *Question) uint16 {
	if bytes.HasSuffix(q.Name, []byte("local.")) != true {
		msg.Header.Flags |= RCodeServFail
		return 0
	}

	rand.Seed(time.Now().UTC().UnixNano())
	id := uint16(rand.Intn(math.MaxUint16))

	req := new(Message)

	req.Header.Id = id
	req.AppendQD(q)

	rsp, err := SendRequest(req)
	if err != nil {
		return 0
	}

	for _, an := range rsp.Answer {
		msg.Answer = append(msg.Answer, an)
		msg.Header.ANCount++
	}

	return id
}

func Serve(p *ipv4.PacketConn, maddr *net.UDPAddr, localname string, silent, forward bool) {
	var sent_id uint16

	for {
		req, dest, local4, local6, client, err := Read(p)
		if err != nil {
			if silent != true {
				log.Println("Error reading request: ", err)
				continue
			}
		}

		if req.Header.Flags&FlagQR != 0 {
			continue
		}

		if sent_id > 0 && req.Header.Id == sent_id {
			continue
		}

		rsp := new(Message)

		rsp.Header.Flags |= FlagQR
		rsp.Header.Flags |= FlagAA

		if req.Header.Flags&FlagRD != 0 {
			rsp.Header.Flags |= FlagRD
			rsp.Header.Flags |= FlagRA
		}

		if client.Port != 5353 {
			rsp.Header.Id = req.Header.Id
		}

		for _, q := range req.Question {
			switch q.Class {
			case ClassInet:
			case ClassInet | ClassUnicast:
			case ClassAny:

			default:
				continue /* unsupport class */
			}

			if client.Port != 5353 {
				rsp.Question = append(rsp.Question, q)
				rsp.Header.QDCount++
			}

			if string(q.Name) != localname {
				if dest.IsLoopback() && forward != false {
					sent_id = SendRecursiveRequest(rsp, q)
				}

				continue
			}

			var rdata []RData

			switch q.Type {
			case TypeA:
				rdata = append(rdata, NewA(local4.IP))

			case TypeAAAA:
				rdata = append(rdata, NewAAAA(local6.IP))

			case TypeHINFO:
				rdata = append(rdata, NewHINFO())

			case TypeAny:
				rdata = append(rdata, NewA(local4.IP))
				rdata = append(rdata, NewAAAA(local6.IP))
				rdata = append(rdata, NewHINFO())

			default:
				continue
			}

			for _, rd := range rdata {
				an := NewAN(q.Name, q.Class, 120, rd)
				rsp.AppendAN(an)
			}
		}

		if rsp.Header.ANCount       == 0 &&
		   rsp.Header.Flags.RCode() == RCodeNoError {
			continue /* no answers and no error, skip */
		}

		if client.Port == 5353 {
			client = maddr
		}

		err = Write(p, client, rsp)
		if err != nil {
			if silent != true {
				log.Println("Error sending response: ", err)
				continue
			}
		}
	}
}

func MonitorNetwork(p *ipv4.PacketConn, group net.Addr) error {
	l, _ := netlink.ListenNetlink()

	l.SendRouteRequest(syscall.RTM_GETADDR, syscall.AF_UNSPEC)

	for {
		msgs, err := l.ReadMsgs()
		if err != nil {
			return fmt.Errorf("Could not read netlink: %s", err)
		}

		for _, m := range msgs {
			if netlink.IsNewAddr(&m) {
				err := JoinGroup(p, &m, group)
				if err != nil {
					return err
				}
			}

			if netlink.IsDelAddr(&m) {
				err := LeaveGroup(p, &m, group)
				if err != nil {
					return err
				}
			}
		}
	}
}

func JoinGroup(p *ipv4.PacketConn, msg *syscall.NetlinkMessage, group net.Addr) error {
	ifaddrmsg := (*syscall.IfAddrmsg)(unsafe.Pointer(&msg.Data[0]))

	if netlink.IsRelevant(ifaddrmsg) != true {
		return nil
	}

	ifi, err := net.InterfaceByIndex(int(ifaddrmsg.Index))
	if err != nil {
		return fmt.Errorf("Could not get interface: %s", err)
	}

	err = p.JoinGroup(ifi, group)
	if err != nil {
		return fmt.Errorf("Could not join group: %s", err)
	}

	return nil
}

func LeaveGroup(p *ipv4.PacketConn, msg *syscall.NetlinkMessage, group net.Addr) error {
	ifaddrmsg := (*syscall.IfAddrmsg)(unsafe.Pointer(&msg.Data[0]))

	ifi, err := net.InterfaceByIndex(int(ifaddrmsg.Index))
	if err != nil {
		return fmt.Errorf("Could not get interface: %s", err)
	}

	err = p.LeaveGroup(ifi, group)
	if err != nil {
		return fmt.Errorf("Could not leave group: %s", err)
	}

	return nil
}
<commit_msg>mdns: use golang.org import path for go.net<commit_after>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package mdns

import "bytes"
import "fmt"
import "log"
import "math"
import "math/rand"
import "net"
import "time"
import "syscall"
import "unsafe"

import "golang.org/x/net/ipv4"

import "netlink"

const maddr4 = "224.0.0.251:5353"
const maddr6 = "[FF02::FB]:5353"

func NewConn(addr string) (*net.UDPAddr, *ipv4.PacketConn, error) {
	saddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not resolve address '%s': %s", addr, err)
	}

	smaddr, err := net.ResolveUDPAddr("udp", maddr4)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not resolve address '%s': %s", maddr4, err)
	}

	udp, err := net.ListenUDP("udp", saddr)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not listen: %s", err)
	}

	p := ipv4.NewPacketConn(udp)

	err = p.SetTTL(1)
	if err != nil {
		return nil, nil,
		  fmt.Errorf("Could not set TTL: %s", err)
	}

	err = p.SetMulticastLoopback(false)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set loop: %s", err)
	}

	err = p.SetControlMessage(ipv4.FlagInterface|ipv4.FlagDst, true)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set ctrlmsg: %s", err)
	}

	return smaddr, p, nil
}

func NewServer(addr string) (*net.UDPAddr, *ipv4.PacketConn, error) {
	smaddr, p, err := NewConn(addr)
	if err != nil {
		return nil, nil, err
	}

	go MonitorNetwork(p, smaddr)

	return smaddr, p, nil
}

func NewClient(addr string) (*net.UDPAddr, *ipv4.PacketConn, error) {
	return NewConn(addr)
}

func Read(p *ipv4.PacketConn) (*Message, net.IP, *net.IPNet, *net.IPNet, *net.UDPAddr, error) {
	var local4 *net.IPNet
	var local6 *net.IPNet

	pkt := make([]byte, 9000)

	n, cm, from, err := p.ReadFrom(pkt)
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not read: %s", err)
	}

	ifi, err := net.InterfaceByIndex(cm.IfIndex)
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not find if: %s", err)
	}

	addrs, err := ifi.Addrs()
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not find addrs: %s", err)
	}

	for _, a := range addrs {
		if a.(*net.IPNet).IP.To4() != nil {
			local4 = a.(*net.IPNet)
		} else {
			local6 = a.(*net.IPNet)
		}
	}

	req, err := Unpack(pkt[:n])
	if err != nil {
		return nil, nil, nil, nil, nil,
		  fmt.Errorf("Could not unpack request: %s", err)
	}

	return req, cm.Dst, local4, local6, from.(*net.UDPAddr), err
}

func Write(p *ipv4.PacketConn, addr *net.UDPAddr, msg *Message) error {
	pkt, err := Pack(msg)
	if err != nil {
		return fmt.Errorf("Could not pack response: %s", err)
	}

	_, err = p.WriteTo(pkt, nil, addr)
	if err != nil {
		return fmt.Errorf("Could not write to network: %s", err)
	}

	return nil
}

func SendRequest(req *Message) (*Message, error) {
	maddr, client, err := NewClient("0.0.0.0:0")
	if err != nil {
		return nil, fmt.Errorf("Could not create client: %s", err)
	}
	defer client.Close()

	seconds := 3 * time.Second
	timeout := time.Now().Add(seconds)

	err = Write(client, maddr, req)
	if err != nil {
		return nil, fmt.Errorf("Could not send request: %s", err)
	}

	client.SetReadDeadline(timeout)

	rsp, _, _, _, _, err := Read(client)
	if err != nil {
		return nil, fmt.Errorf("Could not read response: %s", err)
	}

	if rsp.Header.Id != req.Header.Id {
		return nil, fmt.Errorf("Wrong id: %d", rsp.Header.Id)
	}

	return rsp, nil
}

func SendRecursiveRequest(msg *Message, q *Question) uint16 {
	if bytes.HasSuffix(q.Name, []byte("local.")) != true {
		msg.Header.Flags |= RCodeServFail
		return 0
	}

	rand.Seed(time.Now().UTC().UnixNano())
	id := uint16(rand.Intn(math.MaxUint16))

	req := new(Message)

	req.Header.Id = id
	req.AppendQD(q)

	rsp, err := SendRequest(req)
	if err != nil {
		return 0
	}

	for _, an := range rsp.Answer {
		msg.Answer = append(msg.Answer, an)
		msg.Header.ANCount++
	}

	return id
}

func Serve(p *ipv4.PacketConn, maddr *net.UDPAddr, localname string, silent, forward bool) {
	var sent_id uint16

	for {
		req, dest, local4, local6, client, err := Read(p)
		if err != nil {
			if silent != true {
				log.Println("Error reading request: ", err)
				continue
			}
		}

		if req.Header.Flags&FlagQR != 0 {
			continue
		}

		if sent_id > 0 && req.Header.Id == sent_id {
			continue
		}

		rsp := new(Message)

		rsp.Header.Flags |= FlagQR
		rsp.Header.Flags |= FlagAA

		if req.Header.Flags&FlagRD != 0 {
			rsp.Header.Flags |= FlagRD
			rsp.Header.Flags |= FlagRA
		}

		if client.Port != 5353 {
			rsp.Header.Id = req.Header.Id
		}

		for _, q := range req.Question {
			switch q.Class {
			case ClassInet:
			case ClassInet | ClassUnicast:
			case ClassAny:

			default:
				continue /* unsupport class */
			}

			if client.Port != 5353 {
				rsp.Question = append(rsp.Question, q)
				rsp.Header.QDCount++
			}

			if string(q.Name) != localname {
				if dest.IsLoopback() && forward != false {
					sent_id = SendRecursiveRequest(rsp, q)
				}

				continue
			}

			var rdata []RData

			switch q.Type {
			case TypeA:
				rdata = append(rdata, NewA(local4.IP))

			case TypeAAAA:
				rdata = append(rdata, NewAAAA(local6.IP))

			case TypeHINFO:
				rdata = append(rdata, NewHINFO())

			case TypeAny:
				rdata = append(rdata, NewA(local4.IP))
				rdata = append(rdata, NewAAAA(local6.IP))
				rdata = append(rdata, NewHINFO())

			default:
				continue
			}

			for _, rd := range rdata {
				an := NewAN(q.Name, q.Class, 120, rd)
				rsp.AppendAN(an)
			}
		}

		if rsp.Header.ANCount       == 0 &&
		   rsp.Header.Flags.RCode() == RCodeNoError {
			continue /* no answers and no error, skip */
		}

		if client.Port == 5353 {
			client = maddr
		}

		err = Write(p, client, rsp)
		if err != nil {
			if silent != true {
				log.Println("Error sending response: ", err)
				continue
			}
		}
	}
}

func MonitorNetwork(p *ipv4.PacketConn, group net.Addr) error {
	l, _ := netlink.ListenNetlink()

	l.SendRouteRequest(syscall.RTM_GETADDR, syscall.AF_UNSPEC)

	for {
		msgs, err := l.ReadMsgs()
		if err != nil {
			return fmt.Errorf("Could not read netlink: %s", err)
		}

		for _, m := range msgs {
			if netlink.IsNewAddr(&m) {
				err := JoinGroup(p, &m, group)
				if err != nil {
					return err
				}
			}

			if netlink.IsDelAddr(&m) {
				err := LeaveGroup(p, &m, group)
				if err != nil {
					return err
				}
			}
		}
	}
}

func JoinGroup(p *ipv4.PacketConn, msg *syscall.NetlinkMessage, group net.Addr) error {
	ifaddrmsg := (*syscall.IfAddrmsg)(unsafe.Pointer(&msg.Data[0]))

	if netlink.IsRelevant(ifaddrmsg) != true {
		return nil
	}

	ifi, err := net.InterfaceByIndex(int(ifaddrmsg.Index))
	if err != nil {
		return fmt.Errorf("Could not get interface: %s", err)
	}

	err = p.JoinGroup(ifi, group)
	if err != nil {
		return fmt.Errorf("Could not join group: %s", err)
	}

	return nil
}

func LeaveGroup(p *ipv4.PacketConn, msg *syscall.NetlinkMessage, group net.Addr) error {
	ifaddrmsg := (*syscall.IfAddrmsg)(unsafe.Pointer(&msg.Data[0]))

	ifi, err := net.InterfaceByIndex(int(ifaddrmsg.Index))
	if err != nil {
		return fmt.Errorf("Could not get interface: %s", err)
	}

	err = p.LeaveGroup(ifi, group)
	if err != nil {
		return fmt.Errorf("Could not leave group: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package system

import (
	"net/http"
	"github.com/golang/glog"
	"github.com/zenazn/goji/web"
	"github.com/elcct/taillachat/models"
	"github.com/gorilla/sessions"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

// Makes sure templates are stored in the context
func (application *Application) ApplyTemplates(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		c.Env["Template"] = application.Template
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

// Makes sure controllers can have access to session
func (application *Application) ApplySessions(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session, _ := application.Store.Get(r, "session")
		c.Env["Session"] = session
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

// Makes sure controllers can have access to the database
func (application *Application) ApplyDatabase(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := application.DBSession.Clone()
		defer session.Close()
		c.Env["DBSession"] = session
		c.Env["DBName"] = application.Configuration.Database.Database
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyAuth(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := c.Env["Session"].(*sessions.Session)
		if userId, ok := session.Values["User"].(bson.ObjectId); ok {
			dbSession := c.Env["DBSession"].(*mgo.Session)
			database := dbSession.DB(c.Env["DBName"].(string))

			user := new(models.User)
			err := database.C("users").Find(bson.M{"_id": userId}).One(&user)
			if err != nil {
				glog.Warningf("Auth error: %v", err)
				c.Env["User"] = nil
			} else {
				c.Env["User"] = user
			}
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

<commit_msg>Fixed memory leak in sessions<commit_after>package system

import (
	"net/http"
	"github.com/golang/glog"
	"github.com/zenazn/goji/web"
	"github.com/elcct/taillachat/models"
	"github.com/gorilla/context"
	"github.com/gorilla/sessions"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

// Makes sure templates are stored in the context
func (application *Application) ApplyTemplates(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		c.Env["Template"] = application.Template
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

// Makes sure controllers can have access to session
func (application *Application) ApplySessions(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session, _ := application.Store.Get(r, "session")
		c.Env["Session"] = session
		h.ServeHTTP(w, r)
		context.Clear(r)
	}
	return http.HandlerFunc(fn)
}

// Makes sure controllers can have access to the database
func (application *Application) ApplyDatabase(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := application.DBSession.Clone()
		defer session.Close()
		c.Env["DBSession"] = session
		c.Env["DBName"] = application.Configuration.Database.Database
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyAuth(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := c.Env["Session"].(*sessions.Session)
		if userId, ok := session.Values["User"].(bson.ObjectId); ok {
			dbSession := c.Env["DBSession"].(*mgo.Session)
			database := dbSession.DB(c.Env["DBName"].(string))

			user := new(models.User)
			err := database.C("users").Find(bson.M{"_id": userId}).One(&user)
			if err != nil {
				glog.Warningf("Auth error: %v", err)
				c.Env["User"] = nil
			} else {
				c.Env["User"] = user
			}
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

<|endoftext|>


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

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/syzkaller/pkg/cover"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/sys/targets"
)

var (
	initCoverOnce     sync.Once
	initCoverError    error
	initCoverVMOffset uint32
	reportGenerator   *cover.ReportGenerator
)

func initCover(target *targets.Target, kernelObj, kernelSrc, kernelBuildSrc string) error {
	initCoverOnce.Do(func() {
		if kernelObj == "" {
			initCoverError = fmt.Errorf("kernel_obj is not specified")
			return
		}
		vmlinux := filepath.Join(kernelObj, target.KernelObject)
		reportGenerator, initCoverError = cover.MakeReportGenerator(target, vmlinux, kernelSrc, kernelBuildSrc)
		if initCoverError != nil {
			return
		}
		initCoverVMOffset, initCoverError = getVMOffset(vmlinux, target.OS)
	})
	return initCoverError
}

func coverToPCs(target *targets.Target, cov []uint32) []uint64 {
	pcs := make([]uint64, 0, len(cov))
	for _, pc := range cov {
		fullPC := cover.RestorePC(pc, initCoverVMOffset)
		prevPC := cover.PreviousInstructionPC(target, fullPC)
		pcs = append(pcs, prevPC)
	}
	return pcs
}

func getVMOffset(vmlinux, OS string) (uint32, error) {
	if OS == "freebsd" {
		return 0xffffffff, nil
	}
	out, err := osutil.RunCmd(time.Hour, "", "readelf", "-SW", vmlinux)
	if err != nil {
		return 0, err
	}
	s := bufio.NewScanner(bytes.NewReader(out))
	var addr uint32
	for s.Scan() {
		ln := s.Text()
		pieces := strings.Fields(ln)
		for i := 0; i < len(pieces); i++ {
			if pieces[i] != "PROGBITS" {
				continue
			}
			v, err := strconv.ParseUint("0x"+pieces[i+1], 0, 64)
			if err != nil {
				return 0, fmt.Errorf("failed to parse addr in readelf output: %v", err)
			}
			if v == 0 {
				continue
			}
			v32 := (uint32)(v >> 32)
			if addr == 0 {
				addr = v32
			}
			if addr != v32 {
				return 0, fmt.Errorf("different section offsets in a single binary")
			}
		}
	}
	return addr, nil
}
<commit_msg>syz-manager/cover: support compiler triple for readelf<commit_after>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/syzkaller/pkg/cover"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/sys/targets"
)

var (
	initCoverOnce     sync.Once
	initCoverError    error
	initCoverVMOffset uint32
	reportGenerator   *cover.ReportGenerator
)

func initCover(target *targets.Target, kernelObj, kernelSrc, kernelBuildSrc string) error {
	initCoverOnce.Do(func() {
		if kernelObj == "" {
			initCoverError = fmt.Errorf("kernel_obj is not specified")
			return
		}
		vmlinux := filepath.Join(kernelObj, target.KernelObject)
		reportGenerator, initCoverError = cover.MakeReportGenerator(target, vmlinux, kernelSrc, kernelBuildSrc)
		if initCoverError != nil {
			return
		}
		initCoverVMOffset, initCoverError = getVMOffset(target, vmlinux)
	})
	return initCoverError
}

func coverToPCs(target *targets.Target, cov []uint32) []uint64 {
	pcs := make([]uint64, 0, len(cov))
	for _, pc := range cov {
		fullPC := cover.RestorePC(pc, initCoverVMOffset)
		prevPC := cover.PreviousInstructionPC(target, fullPC)
		pcs = append(pcs, prevPC)
	}
	return pcs
}

func getVMOffset(target *targets.Target, vmlinux string) (uint32, error) {
	if target.OS == "freebsd" {
		return 0xffffffff, nil
	}
	readelf := "readelf"
	if target.Triple != "" {
		readelf = target.Triple + "-" + readelf
	}
	out, err := osutil.RunCmd(time.Hour, "", readelf, "-SW", vmlinux)
	if err != nil {
		return 0, err
	}
	s := bufio.NewScanner(bytes.NewReader(out))
	var addr uint32
	for s.Scan() {
		ln := s.Text()
		pieces := strings.Fields(ln)
		for i := 0; i < len(pieces); i++ {
			if pieces[i] != "PROGBITS" {
				continue
			}
			v, err := strconv.ParseUint("0x"+pieces[i+1], 0, 64)
			if err != nil {
				return 0, fmt.Errorf("failed to parse addr in readelf output: %v", err)
			}
			if v == 0 {
				continue
			}
			v32 := (uint32)(v >> 32)
			if addr == 0 {
				addr = v32
			}
			if addr != v32 {
				return 0, fmt.Errorf("different section offsets in a single binary")
			}
		}
	}
	return addr, nil
}
<|endoftext|>